foreman-tasks 11.0.5 → 11.0.7

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman-tasks/locale/de/foreman_tasks.js +5 -2
  3. data/app/assets/javascripts/foreman-tasks/locale/en/foreman_tasks.js +4 -1
  4. data/app/assets/javascripts/foreman-tasks/locale/es/foreman_tasks.js +5 -2
  5. data/app/assets/javascripts/foreman-tasks/locale/fr/foreman_tasks.js +11 -8
  6. data/app/assets/javascripts/foreman-tasks/locale/ja/foreman_tasks.js +12 -9
  7. data/app/assets/javascripts/foreman-tasks/locale/ka/foreman_tasks.js +5 -2
  8. data/app/assets/javascripts/foreman-tasks/locale/ko/foreman_tasks.js +167 -165
  9. data/app/assets/javascripts/foreman-tasks/locale/pt_BR/foreman_tasks.js +5 -2
  10. data/app/assets/javascripts/foreman-tasks/locale/ru/foreman_tasks.js +5 -2
  11. data/app/assets/javascripts/foreman-tasks/locale/zh_CN/foreman_tasks.js +11 -8
  12. data/app/assets/javascripts/foreman-tasks/locale/zh_TW/foreman_tasks.js +5 -2
  13. data/lib/foreman_tasks/dynflow/console_authorizer.rb +1 -3
  14. data/lib/foreman_tasks/version.rb +1 -1
  15. data/locale/Makefile +18 -7
  16. data/locale/de/LC_MESSAGES/foreman_tasks.mo +0 -0
  17. data/locale/de/foreman_tasks.po +5 -2
  18. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  19. data/locale/en/foreman_tasks.po +4 -1
  20. data/locale/es/LC_MESSAGES/foreman_tasks.mo +0 -0
  21. data/locale/es/foreman_tasks.po +5 -2
  22. data/locale/foreman_tasks.pot +10 -6
  23. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  24. data/locale/fr/foreman_tasks.po +11 -8
  25. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  26. data/locale/ja/foreman_tasks.po +12 -9
  27. data/locale/ka/LC_MESSAGES/foreman_tasks.mo +0 -0
  28. data/locale/ka/foreman_tasks.po +5 -2
  29. data/locale/ko/LC_MESSAGES/foreman_tasks.mo +0 -0
  30. data/locale/ko/foreman_tasks.po +167 -165
  31. data/locale/pt_BR/LC_MESSAGES/foreman_tasks.mo +0 -0
  32. data/locale/pt_BR/foreman_tasks.po +5 -2
  33. data/locale/ru/LC_MESSAGES/foreman_tasks.mo +0 -0
  34. data/locale/ru/foreman_tasks.po +5 -2
  35. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  36. data/locale/zh_CN/foreman_tasks.po +11 -8
  37. data/locale/zh_TW/LC_MESSAGES/foreman_tasks.mo +0 -0
  38. data/locale/zh_TW/foreman_tasks.po +5 -2
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +37 -9
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +19 -16
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +197 -71
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -40
  43. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -16
  44. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +0 -16
  45. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/GenericConfirmModal.js +70 -0
  46. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +25 -14
  47. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +8 -7
  48. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/index.test.js +409 -0
  49. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createBulkTaskModal.js +67 -0
  50. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createTaskModal.js +51 -0
  51. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +73 -23
  52. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +5 -2
  53. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +1 -1
  54. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +67 -11
  55. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +86 -6
  56. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +225 -39
  57. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +136 -37
  58. metadata +6 -19
  59. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +0 -60
  60. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +0 -14
  61. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +0 -25
  62. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +0 -212
  63. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +0 -83
  64. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +0 -106
  65. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +0 -38
  66. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +0 -36
  67. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +0 -205
  68. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +0 -27
  69. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +0 -41
  70. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +0 -19
  71. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +0 -9
  72. data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +0 -52
  73. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
  74. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +0 -10
  75. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -18
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import URI from 'urijs';
4
4
  import { getURIsearch } from 'foremanReact/common/urlHelpers';
@@ -8,17 +8,25 @@ import { translate as __ } from 'foremanReact/common/I18n';
8
8
  import { getURIQuery } from 'foremanReact/common/helpers';
9
9
  import ExportButton from 'foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton';
10
10
  import { STATUS } from 'foremanReact/constants';
11
- import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
12
11
  import TasksDashboard from '../TasksDashboard';
13
12
  import TasksTable from './TasksTable';
14
13
  import { getCSVurl, updateURlQuery } from './TasksTableHelpers';
15
- import ConfirmModal from './Components/ConfirmModal/';
14
+ import {
15
+ CancelModal,
16
+ ResumeModal,
17
+ CancelSelectedModal,
18
+ ResumeSelectedModal,
19
+ ForceUnlockModal,
20
+ ForceUnlockSelectedModal,
21
+ } from './Components/ConfirmModal';
16
22
  import {
17
23
  TASKS_SEARCH_PROPS,
18
24
  CANCEL_SELECTED_MODAL,
19
25
  RESUME_SELECTED_MODAL,
20
26
  FORCE_UNLOCK_SELECTED_MODAL,
21
- CONFIRM_MODAL,
27
+ CANCEL_MODAL,
28
+ RESUME_MODAL,
29
+ FORCE_UNLOCK_MODAL,
22
30
  } from './TasksTableConstants';
23
31
  import { ActionSelectButton } from './Components/ActionSelectButton';
24
32
  import './TasksTablePage.scss';
@@ -48,21 +56,69 @@ const TasksTablePage = ({
48
56
  updateURlQuery(newUriQuery, history);
49
57
  }
50
58
  };
51
-
52
- const { setModalOpen, setModalClosed } = useForemanModal({
53
- id: CONFIRM_MODAL,
59
+ const [modalStates, setModalStates] = useState({
60
+ [CANCEL_MODAL]: false,
61
+ [RESUME_MODAL]: false,
62
+ [CANCEL_SELECTED_MODAL]: false,
63
+ [RESUME_SELECTED_MODAL]: false,
64
+ [FORCE_UNLOCK_MODAL]: false,
65
+ [FORCE_UNLOCK_SELECTED_MODAL]: false,
54
66
  });
55
67
 
56
- const openModal = id => openModalAction(id, setModalOpen);
68
+ const openModal = id => {
69
+ setModalStates(prev => ({
70
+ ...prev,
71
+ [id]: true,
72
+ }));
73
+ };
74
+
75
+ const closeModal = id => {
76
+ setModalStates(prev => ({
77
+ ...prev,
78
+ [id]: false,
79
+ }));
80
+ };
57
81
 
58
82
  return (
59
83
  <div className="tasks-table-wrapper">
60
- <ConfirmModal
61
- id={CONFIRM_MODAL}
84
+ <CancelModal
85
+ isModalOpen={modalStates[CANCEL_MODAL]}
86
+ setIsModalOpen={() => closeModal(CANCEL_MODAL)}
87
+ url={url}
88
+ parentTaskID={props.parentTaskID}
89
+ />
90
+ <ResumeModal
91
+ isModalOpen={modalStates[RESUME_MODAL]}
92
+ setIsModalOpen={() => closeModal(RESUME_MODAL)}
93
+ url={url}
94
+ parentTaskID={props.parentTaskID}
95
+ />
96
+ <CancelSelectedModal
97
+ isModalOpen={modalStates[CANCEL_SELECTED_MODAL]}
98
+ setIsModalOpen={() => closeModal(CANCEL_SELECTED_MODAL)}
62
99
  url={url}
100
+ uriQuery={uriQuery}
63
101
  parentTaskID={props.parentTaskID}
102
+ />
103
+ <ResumeSelectedModal
104
+ isModalOpen={modalStates[RESUME_SELECTED_MODAL]}
105
+ setIsModalOpen={() => closeModal(RESUME_SELECTED_MODAL)}
106
+ url={url}
64
107
  uriQuery={uriQuery}
65
- setModalClosed={setModalClosed}
108
+ parentTaskID={props.parentTaskID}
109
+ />
110
+ <ForceUnlockModal
111
+ isModalOpen={modalStates[FORCE_UNLOCK_MODAL]}
112
+ setIsModalOpen={() => closeModal(FORCE_UNLOCK_MODAL)}
113
+ url={url}
114
+ parentTaskID={props.parentTaskID}
115
+ />
116
+ <ForceUnlockSelectedModal
117
+ isModalOpen={modalStates[FORCE_UNLOCK_SELECTED_MODAL]}
118
+ setIsModalOpen={() => closeModal(FORCE_UNLOCK_SELECTED_MODAL)}
119
+ url={url}
120
+ uriQuery={uriQuery}
121
+ parentTaskID={props.parentTaskID}
66
122
  />
67
123
  <PageLayout
68
124
  searchable
@@ -4,10 +4,50 @@ exports[`TasksTablePage rendering render with Breadcrubs and edit permissions 1`
4
4
  <div
5
5
  className="tasks-table-wrapper"
6
6
  >
7
- <Connect(ConfirmModal)
8
- id="ConfirmModal"
7
+ <TaskModal
8
+ isModalOpen={false}
9
9
  parentTaskID={null}
10
- setModalClosed={[MockFunction]}
10
+ setIsModalOpen={[Function]}
11
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
12
+ />
13
+ <TaskModal
14
+ isModalOpen={false}
15
+ parentTaskID={null}
16
+ setIsModalOpen={[Function]}
17
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
18
+ />
19
+ <BulkTaskModal
20
+ isModalOpen={false}
21
+ parentTaskID={null}
22
+ setIsModalOpen={[Function]}
23
+ uriQuery={
24
+ Object {
25
+ "state": "stopped",
26
+ }
27
+ }
28
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
29
+ />
30
+ <BulkTaskModal
31
+ isModalOpen={false}
32
+ parentTaskID={null}
33
+ setIsModalOpen={[Function]}
34
+ uriQuery={
35
+ Object {
36
+ "state": "stopped",
37
+ }
38
+ }
39
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
40
+ />
41
+ <TaskModal
42
+ isModalOpen={false}
43
+ parentTaskID={null}
44
+ setIsModalOpen={[Function]}
45
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
46
+ />
47
+ <BulkTaskModal
48
+ isModalOpen={false}
49
+ parentTaskID={null}
50
+ setIsModalOpen={[Function]}
11
51
  uriQuery={
12
52
  Object {
13
53
  "state": "stopped",
@@ -156,10 +196,50 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
156
196
  <div
157
197
  className="tasks-table-wrapper"
158
198
  >
159
- <Connect(ConfirmModal)
160
- id="ConfirmModal"
199
+ <TaskModal
200
+ isModalOpen={false}
201
+ parentTaskID={null}
202
+ setIsModalOpen={[Function]}
203
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
204
+ />
205
+ <TaskModal
206
+ isModalOpen={false}
207
+ parentTaskID={null}
208
+ setIsModalOpen={[Function]}
209
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
210
+ />
211
+ <BulkTaskModal
212
+ isModalOpen={false}
213
+ parentTaskID={null}
214
+ setIsModalOpen={[Function]}
215
+ uriQuery={
216
+ Object {
217
+ "state": "stopped",
218
+ }
219
+ }
220
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
221
+ />
222
+ <BulkTaskModal
223
+ isModalOpen={false}
224
+ parentTaskID={null}
225
+ setIsModalOpen={[Function]}
226
+ uriQuery={
227
+ Object {
228
+ "state": "stopped",
229
+ }
230
+ }
231
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
232
+ />
233
+ <TaskModal
234
+ isModalOpen={false}
235
+ parentTaskID={null}
236
+ setIsModalOpen={[Function]}
237
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
238
+ />
239
+ <BulkTaskModal
240
+ isModalOpen={false}
161
241
  parentTaskID={null}
162
- setModalClosed={[MockFunction]}
242
+ setIsModalOpen={[Function]}
163
243
  uriQuery={
164
244
  Object {
165
245
  "state": "stopped",
@@ -1,44 +1,230 @@
1
1
  import React from 'react';
2
- import { testComponentSnapshotsWithFixtures, mount } from '@theforeman/test';
3
- import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
4
- import { ClickConfirmation } from './';
5
-
6
- const fixtures = {
7
- render: {
8
- title: 'some-title',
9
- confirmType: 'danger',
10
- body: 'some-body',
11
- confirmationMessage: 'some-message',
12
- id: 'some-id',
13
- confirmAction: 'some-confirm',
14
- onClick: jest.fn(),
15
- },
16
- };
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import {
5
+ ClickConfirmation,
6
+ UnlockConfirmationModal,
7
+ ForceUnlockConfirmationModal,
8
+ } from './';
17
9
 
18
10
  describe('ClickConfirmation', () => {
19
- testComponentSnapshotsWithFixtures(ClickConfirmation, fixtures);
20
- it('enable button on checkbox click', () => {
21
- const component = mount(<ClickConfirmation {...fixtures.render} />);
22
- const getButton = () => component.find('.confirm-button').at(0);
23
- expect(getButton().props().disabled).toBeTruthy();
24
- const checkbox = component.find('input').at(0);
25
- checkbox.simulate('change', { target: { checked: true } });
26
- expect(getButton().props().disabled).toBeFalsy();
27
- });
28
-
29
- it('click test', () => {
30
- const setModalClosed = jest.fn();
31
- useForemanModal.mockImplementation(id => ({
32
- setModalClosed: () => setModalClosed(id),
33
- }));
34
- const onClick = jest.fn();
35
- const props = { ...fixtures.render, onClick };
36
- const component = mount(<ClickConfirmation {...props} />);
37
- const getButton = () => component.find('.confirm-button').at(0);
38
- const checkbox = component.find('input').at(0);
39
- checkbox.simulate('change', { target: { checked: true } });
40
- getButton().simulate('click');
41
- expect(onClick).toBeCalled();
42
- expect(setModalClosed).toBeCalledWith({ id: fixtures.render.id });
11
+ const defaultProps = {
12
+ title: 'Test Modal',
13
+ body: 'This is a test modal body',
14
+ confirmationMessage: 'I understand the consequences',
15
+ confirmAction: 'Confirm',
16
+ onClick: jest.fn(),
17
+ id: 'test-modal',
18
+ isOpen: true,
19
+ setModalClosed: jest.fn(),
20
+ };
21
+
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ });
25
+
26
+ describe('Basic Rendering', () => {
27
+ it('renders modal with correct title and content when open', () => {
28
+ render(<ClickConfirmation {...defaultProps} />);
29
+
30
+ expect(screen.getByText('Test Modal')).toBeInTheDocument();
31
+ expect(screen.getByText('This is a test modal body')).toBeInTheDocument();
32
+ expect(
33
+ screen.getByText('I understand the consequences')
34
+ ).toBeInTheDocument();
35
+ expect(screen.getByText('Confirm')).toBeInTheDocument();
36
+ });
37
+
38
+ it('does not render modal when isOpen is false', () => {
39
+ render(<ClickConfirmation {...defaultProps} isOpen={false} />);
40
+
41
+ expect(screen.queryByText('Test Modal')).not.toBeInTheDocument();
42
+ });
43
+
44
+ it('renders with warning variant by default', () => {
45
+ render(<ClickConfirmation {...defaultProps} />);
46
+
47
+ const modal = screen.getByRole('dialog');
48
+ expect(modal).toBeInTheDocument();
49
+ });
50
+
51
+ it('renders with danger variant when specified', () => {
52
+ render(<ClickConfirmation {...defaultProps} confirmType="danger" />);
53
+
54
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
55
+ expect(confirmButton).toHaveClass('pf-m-danger');
56
+ });
57
+ });
58
+
59
+ describe('Checkbox Interaction', () => {
60
+ it('starts with checkbox unchecked and confirm button disabled', () => {
61
+ render(<ClickConfirmation {...defaultProps} />);
62
+
63
+ const checkbox = screen.getByRole('checkbox');
64
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
65
+
66
+ expect(checkbox).not.toBeChecked();
67
+ expect(confirmButton).toBeDisabled();
68
+ });
69
+
70
+ it('enables confirm button when checkbox is checked', () => {
71
+ render(<ClickConfirmation {...defaultProps} />);
72
+
73
+ const checkbox = screen.getByRole('checkbox');
74
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
75
+
76
+ fireEvent.click(checkbox);
77
+
78
+ expect(checkbox).toBeChecked();
79
+ expect(confirmButton).toBeEnabled();
80
+ });
81
+
82
+ it('disables confirm button when checkbox is unchecked', () => {
83
+ render(<ClickConfirmation {...defaultProps} />);
84
+
85
+ const checkbox = screen.getByRole('checkbox');
86
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
87
+
88
+ // Check the checkbox first
89
+ fireEvent.click(checkbox);
90
+ expect(confirmButton).toBeEnabled();
91
+
92
+ // Uncheck the checkbox
93
+ fireEvent.click(checkbox);
94
+ expect(checkbox).not.toBeChecked();
95
+ expect(confirmButton).toBeDisabled();
96
+ });
97
+ });
98
+
99
+ describe('Button Actions', () => {
100
+ it('calls onClick and setModalClosed when confirm button is clicked', () => {
101
+ const onClick = jest.fn();
102
+ const setModalClosed = jest.fn();
103
+
104
+ render(
105
+ <ClickConfirmation
106
+ {...defaultProps}
107
+ onClick={onClick}
108
+ setModalClosed={setModalClosed}
109
+ />
110
+ );
111
+
112
+ const checkbox = screen.getByRole('checkbox');
113
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
114
+
115
+ // Enable the button by checking the checkbox
116
+ fireEvent.click(checkbox);
117
+
118
+ // Click the confirm button
119
+ fireEvent.click(confirmButton);
120
+
121
+ expect(onClick).toHaveBeenCalledTimes(1);
122
+ expect(setModalClosed).toHaveBeenCalledTimes(1);
123
+ });
124
+
125
+ it('calls setModalClosed when cancel button is clicked', () => {
126
+ const setModalClosed = jest.fn();
127
+
128
+ render(
129
+ <ClickConfirmation {...defaultProps} setModalClosed={setModalClosed} />
130
+ );
131
+
132
+ const cancelButton = screen.getByRole('button', { name: 'Cancel' });
133
+ fireEvent.click(cancelButton);
134
+
135
+ expect(setModalClosed).toHaveBeenCalledTimes(1);
136
+ });
137
+
138
+ it('does not call onClick when confirm button is clicked while disabled', () => {
139
+ const onClick = jest.fn();
140
+
141
+ render(<ClickConfirmation {...defaultProps} onClick={onClick} />);
142
+
143
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
144
+
145
+ // Try to click the disabled button
146
+ fireEvent.click(confirmButton);
147
+
148
+ expect(onClick).not.toHaveBeenCalled();
149
+ });
150
+ });
151
+ });
152
+
153
+ describe('UnlockModal', () => {
154
+ const defaultProps = {
155
+ onClick: jest.fn(),
156
+ id: 'unlock-modal',
157
+ isOpen: true,
158
+ setModalClosed: jest.fn(),
159
+ };
160
+
161
+ beforeEach(() => {
162
+ jest.clearAllMocks();
163
+ });
164
+
165
+ it('renders with correct unlock-specific content and warning variant', () => {
166
+ render(<UnlockConfirmationModal {...defaultProps} />);
167
+
168
+ expect(
169
+ screen.getByRole('heading', { name: 'Warning alert: Unlock' })
170
+ ).toBeInTheDocument();
171
+ expect(
172
+ screen.getByText(
173
+ /This will unlock the resources that the task is running against/
174
+ )
175
+ ).toBeInTheDocument();
176
+ expect(
177
+ screen.getByText(
178
+ 'I understand that this may cause harm and have working database backups of all backend services.'
179
+ )
180
+ ).toBeInTheDocument();
181
+
182
+ const confirmButton = screen.getByRole('button', { name: 'Unlock' });
183
+ expect(confirmButton).toBeInTheDocument();
184
+ expect(confirmButton).toHaveClass('pf-m-primary');
185
+ });
186
+ });
187
+
188
+ describe('ForceUnlockModal', () => {
189
+ const defaultProps = {
190
+ onClick: jest.fn(),
191
+ id: 'force-unlock-modal',
192
+ selectedRowsLen: 3,
193
+ isOpen: true,
194
+ setModalClosed: jest.fn(),
195
+ };
196
+
197
+ beforeEach(() => {
198
+ jest.clearAllMocks();
199
+ });
200
+
201
+ it('renders with correct force unlock-specific content and danger variant', () => {
202
+ render(<ForceUnlockConfirmationModal {...defaultProps} />);
203
+
204
+ expect(
205
+ screen.getByRole('heading', { name: 'Danger alert: Force Unlock' })
206
+ ).toBeInTheDocument();
207
+ expect(
208
+ screen.getByText(/Resources for 3 task\(s\) will be unlocked/)
209
+ ).toBeInTheDocument();
210
+ expect(
211
+ screen.getByText(
212
+ 'I understand that this may cause harm and have working database backups of all backend services.'
213
+ )
214
+ ).toBeInTheDocument();
215
+
216
+ const confirmButton = screen.getByRole('button', { name: 'Force Unlock' });
217
+ expect(confirmButton).toBeInTheDocument();
218
+ expect(confirmButton).toHaveClass('pf-m-danger');
219
+ });
220
+
221
+ it('displays correct number of tasks in body', () => {
222
+ render(
223
+ <ForceUnlockConfirmationModal {...defaultProps} selectedRowsLen={5} />
224
+ );
225
+
226
+ expect(
227
+ screen.getByText(/Resources for 5 task\(s\) will be unlocked/)
228
+ ).toBeInTheDocument();
43
229
  });
44
230
  });
@@ -1,10 +1,17 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Button } from 'patternfly-react';
4
- import ForemanModal from 'foremanReact/components/ForemanModal';
5
- import { translate as __ } from 'foremanReact/common/I18n';
6
- import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
7
- import './ClickConfirmation.scss';
3
+ import {
4
+ Button,
5
+ Modal,
6
+ ModalVariant,
7
+ Checkbox,
8
+ TextContent,
9
+ } from '@patternfly/react-core';
10
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
11
+ import {
12
+ UNLOCK_MODAL,
13
+ FORCE_UNLOCK_MODAL,
14
+ } from '../../TaskActions/TaskActionsConstants';
8
15
 
9
16
  export const ClickConfirmation = ({
10
17
  title,
@@ -14,48 +21,57 @@ export const ClickConfirmation = ({
14
21
  id,
15
22
  confirmAction,
16
23
  onClick,
24
+ isOpen,
25
+ setModalClosed,
17
26
  }) => {
18
27
  const [isConfirmed, setConfirm] = useState(false);
19
- const { setModalClosed, modalOpen } = useForemanModal({
20
- id,
21
- });
22
- useEffect(() => {
28
+ const onClose = () => {
23
29
  setConfirm(false);
24
- }, [modalOpen]);
25
- const icon = confirmType === 'warning' ? confirmType : 'exclamation';
26
-
30
+ setModalClosed();
31
+ };
27
32
  return (
28
- <ForemanModal id={id}>
29
- <ForemanModal.Header>
30
- <span className={`glyphicon glyphicon-${icon}-sign`} />
31
- {` ${title}`}
32
- </ForemanModal.Header>
33
- <span>{body}</span>
34
- <div className="confirmation-check">
35
- <input
36
- onChange={e => {
37
- setConfirm(e.target.checked);
38
- }}
39
- checked={isConfirmed}
40
- type="checkbox"
41
- />
42
- <span>{` ${confirmationMessage}`}</span>
43
- </div>
44
- <ForemanModal.Footer>
33
+ <Modal
34
+ title={title}
35
+ titleIconVariant={confirmType}
36
+ variant={ModalVariant.small}
37
+ isOpen={isOpen}
38
+ onClose={onClose}
39
+ ouiaId={`${id}-modal`}
40
+ actions={[
45
41
  <Button
42
+ ouiaId={`${id}-cancel-button`}
43
+ key="cancel"
44
+ variant="secondary"
45
+ onClick={onClose}
46
+ >
47
+ {__('Cancel')}
48
+ </Button>,
49
+ <Button
50
+ ouiaId={`${id}-confirm-button`}
51
+ key="confirm"
46
52
  className="confirm-button"
53
+ variant={confirmType === 'danger' ? 'danger' : 'primary'}
47
54
  onClick={() => {
48
55
  onClick();
49
- setModalClosed();
56
+ onClose();
50
57
  }}
51
- bsStyle={confirmType}
52
- disabled={!isConfirmed}
58
+ isDisabled={!isConfirmed}
53
59
  >
54
60
  {confirmAction}
55
- </Button>
56
- <Button onClick={setModalClosed}>{__('Cancel')}</Button>
57
- </ForemanModal.Footer>
58
- </ForemanModal>
61
+ </Button>,
62
+ ]}
63
+ >
64
+ <TextContent>
65
+ {body}
66
+ <Checkbox
67
+ ouiaId={`${id}-confirmation-checkbox`}
68
+ id={`confirmation-checkbox-${id}`}
69
+ label={confirmationMessage}
70
+ isChecked={isConfirmed}
71
+ onChange={(_e, checked) => setConfirm(checked)}
72
+ />
73
+ </TextContent>
74
+ </Modal>
59
75
  );
60
76
  };
61
77
 
@@ -67,10 +83,93 @@ ClickConfirmation.propTypes = {
67
83
  onClick: PropTypes.func.isRequired,
68
84
  confirmType: PropTypes.oneOf(['warning', 'danger']),
69
85
  id: PropTypes.string.isRequired,
86
+ isOpen: PropTypes.bool,
87
+ setModalClosed: PropTypes.func,
70
88
  };
71
89
 
72
90
  ClickConfirmation.defaultProps = {
73
91
  confirmType: 'warning',
92
+ isOpen: false,
93
+ setModalClosed: () => {},
94
+ };
95
+
96
+ // Unlock Modal Components
97
+ const confirmationMessage = __(
98
+ 'I understand that this may cause harm and have working database backups of all backend services.'
99
+ );
100
+
101
+ export const UnlockConfirmationModal = ({
102
+ onClick,
103
+ id,
104
+ isOpen,
105
+ setModalClosed,
106
+ }) => (
107
+ <ClickConfirmation
108
+ id={id}
109
+ title={__('Unlock')}
110
+ body={__(
111
+ "This will unlock the resources that the task is running against. Please note that this might lead to inconsistent state and should be used with caution, after making sure that the task can't be resumed."
112
+ )}
113
+ confirmationMessage={confirmationMessage}
114
+ confirmAction={__('Unlock')}
115
+ onClick={onClick}
116
+ confirmType="warning"
117
+ isOpen={isOpen}
118
+ setModalClosed={setModalClosed}
119
+ />
120
+ );
121
+
122
+ export const ForceUnlockConfirmationModal = ({
123
+ onClick,
124
+ id,
125
+ selectedRowsLen,
126
+ isOpen,
127
+ setModalClosed,
128
+ }) => (
129
+ <ClickConfirmation
130
+ id={id}
131
+ title={__('Force Unlock')}
132
+ body={sprintf(
133
+ __(
134
+ `Resources for %s task(s) will be unlocked and will not prevent other tasks from being run. As the task(s) might be still running, it should be avoided to use this unless you are really sure the task(s) got stuck.`
135
+ ),
136
+ selectedRowsLen
137
+ )}
138
+ confirmationMessage={confirmationMessage}
139
+ confirmAction={__('Force Unlock')}
140
+ onClick={onClick}
141
+ confirmType="danger"
142
+ isOpen={isOpen}
143
+ setModalClosed={setModalClosed}
144
+ />
145
+ );
146
+
147
+ UnlockConfirmationModal.propTypes = {
148
+ onClick: PropTypes.func.isRequired,
149
+ id: PropTypes.string,
150
+ isOpen: PropTypes.bool,
151
+ setModalClosed: PropTypes.func,
152
+ };
153
+
154
+ ForceUnlockConfirmationModal.propTypes = {
155
+ onClick: PropTypes.func.isRequired,
156
+ id: PropTypes.string,
157
+ selectedRowsLen: PropTypes.number,
158
+ isOpen: PropTypes.bool,
159
+ setModalClosed: PropTypes.func,
160
+ };
161
+
162
+ UnlockConfirmationModal.defaultProps = {
163
+ id: UNLOCK_MODAL,
164
+ isOpen: false,
165
+ setModalClosed: () => {},
166
+ };
167
+
168
+ ForceUnlockConfirmationModal.defaultProps = {
169
+ id: FORCE_UNLOCK_MODAL,
170
+ selectedRowsLen: 1,
171
+ isOpen: false,
172
+ setModalClosed: () => {},
74
173
  };
75
174
 
76
175
  export default ClickConfirmation;