foreman_webhooks 4.0.2 → 5.0.0

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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/lib/foreman_webhooks/engine.rb +1 -1
  3. data/lib/foreman_webhooks/version.rb +1 -1
  4. data/test/integration/webhooks_test.rb +234 -0
  5. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/FieldConstructor.js +321 -0
  6. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/WebhookFormTabs.css +23 -4
  7. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/WebhookFormTabs.js +191 -157
  8. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/__tests__/FieldConstructor.test.js +216 -0
  9. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/WebhookForm.js +55 -26
  10. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/__tests__/WebhookForm.test.js +253 -37
  11. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/index.js +3 -4
  12. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookCreateModal.js +30 -19
  13. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookDeleteModal.js +52 -18
  14. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookEditModal.js +37 -26
  15. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookTestModal.js +57 -32
  16. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTable.js +24 -11
  17. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/__snapshots__/WebhooksTable.test.js.snap +64 -0
  18. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/index.js +21 -22
  19. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/WebhooksIndexPage.js +9 -15
  20. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/integration.test.js +0 -3
  21. metadata +7 -5
  22. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/Components/ForemanFormikField.js +0 -152
  23. data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookForm/__tests__/__snapshots__/WebhookForm.test.js.snap +0 -512
  24. data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/__snapshots__/integration.test.js.snap +0 -31
@@ -1,24 +1,14 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import * as Yup from 'yup';
4
-
5
3
  import { translate as __ } from 'foremanReact/common/I18n';
6
- import ForemanForm from 'foremanReact/components/common/forms/ForemanForm';
7
-
4
+ import { Form, ActionGroup, Button } from '@patternfly/react-core';
8
5
  import WebhookFormTabs from './Components/WebhookFormTabs';
9
6
 
10
- import { HTTP_METHODS, WEBHOOK_ITEM } from './constants';
11
-
12
- const webhookFormSchema = Yup.object().shape({
13
- name: Yup.string().required(__('is required')),
14
- target_url: Yup.string().required(__('is required')),
15
- http_method: Yup.string().required(__('is required')),
16
- event: Yup.string().required(__('is required')),
17
- webhook_template_id: Yup.string().required(__('is required')),
18
- });
7
+ import { HTTP_METHODS } from './constants';
19
8
 
20
9
  const WebhookForm = ({
21
10
  onCancel,
11
+ isLoading,
22
12
  handleSubmit,
23
13
  initialValues,
24
14
  templates,
@@ -26,7 +16,6 @@ const WebhookForm = ({
26
16
  isTemplatesLoading,
27
17
  isEventsLoading,
28
18
  isPasswordDisabled,
29
- setIsPasswordDisabled,
30
19
  }) => {
31
20
  const webhookTemplates = templates.map(t => ({ value: t.id, label: t.name }));
32
21
 
@@ -36,16 +25,44 @@ const WebhookForm = ({
36
25
  setActiveTab(tabIndex);
37
26
  };
38
27
 
28
+ const [inputValues, setInputValues] = useState(initialValues);
29
+
30
+ const requiredFields = [
31
+ 'event',
32
+ 'name',
33
+ 'target_url',
34
+ 'webhook_template_id',
35
+ 'http_method',
36
+ ];
37
+
38
+ const verifyFields = () =>
39
+ !requiredFields.every(field => {
40
+ if (field === 'target_url') return urlValidated() === 'success';
41
+ return (
42
+ inputValues[field] !== undefined &&
43
+ inputValues[field] !== null &&
44
+ String(inputValues[field]).trim() !== ''
45
+ );
46
+ });
47
+
48
+ const urlValidated = () => {
49
+ const value = inputValues.target_url;
50
+ if (!value || !value.trim()) return 'error';
51
+ try {
52
+ const u = new URL(value.trim());
53
+ return u.protocol === 'http:' || u.protocol === 'https:'
54
+ ? 'success'
55
+ : 'error';
56
+ } catch {
57
+ return 'error';
58
+ }
59
+ };
60
+
39
61
  return (
40
- <ForemanForm
41
- onSubmit={handleSubmit}
42
- initialValues={initialValues}
43
- validationSchema={webhookFormSchema}
44
- onCancel={onCancel}
45
- enableReinitialize
46
- item={WEBHOOK_ITEM}
47
- >
62
+ <Form isHorizontal>
48
63
  <WebhookFormTabs
64
+ inputValues={inputValues}
65
+ setInputValues={setInputValues}
49
66
  activeTab={activeTab}
50
67
  handleTabClick={handleTabClick}
51
68
  webhookTemplates={webhookTemplates}
@@ -54,13 +71,27 @@ const WebhookForm = ({
54
71
  isEventsLoading={isEventsLoading}
55
72
  isTemplatesLoading={isTemplatesLoading}
56
73
  isPasswordDisabled={isPasswordDisabled}
57
- setIsPasswordDisabled={setIsPasswordDisabled}
74
+ urlValidated={urlValidated}
58
75
  />
59
- </ForemanForm>
76
+ <ActionGroup>
77
+ <Button
78
+ ouiaId="submit-webhook-form"
79
+ isDisabled={verifyFields() || isLoading}
80
+ variant="primary"
81
+ onClick={() => handleSubmit(inputValues)}
82
+ >
83
+ {__('Submit')}
84
+ </Button>
85
+ <Button ouiaId="cancel-webhook-form" variant="link" onClick={onCancel}>
86
+ {__('Cancel')}
87
+ </Button>
88
+ </ActionGroup>
89
+ </Form>
60
90
  );
61
91
  };
62
92
 
63
93
  WebhookForm.propTypes = {
94
+ isLoading: PropTypes.bool.isRequired,
64
95
  onCancel: PropTypes.func.isRequired,
65
96
  handleSubmit: PropTypes.func.isRequired,
66
97
  initialValues: PropTypes.object.isRequired,
@@ -69,12 +100,10 @@ WebhookForm.propTypes = {
69
100
  isEventsLoading: PropTypes.bool.isRequired,
70
101
  isTemplatesLoading: PropTypes.bool.isRequired,
71
102
  isPasswordDisabled: PropTypes.bool,
72
- setIsPasswordDisabled: PropTypes.func,
73
103
  };
74
104
 
75
105
  WebhookForm.defaultProps = {
76
106
  isPasswordDisabled: false,
77
- setIsPasswordDisabled: undefined,
78
107
  };
79
108
 
80
109
  export default WebhookForm;
@@ -1,51 +1,267 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import '@testing-library/jest-dom';
3
5
  import WebhookForm from '../WebhookForm';
4
6
 
5
- const props = {
7
+ const defaultProps = {
6
8
  handleSubmit: jest.fn(),
7
9
  onCancel: jest.fn(),
8
- onSuccess: jest.fn(),
10
+ initialValues: {
11
+ http_method: 'POST',
12
+ enabled: true,
13
+ verify_ssl: true,
14
+ http_content_type: 'application/json',
15
+ event: 'host_created.event.foreman',
16
+ name: '',
17
+ target_url: '',
18
+ user: '',
19
+ password: '',
20
+ webhook_template_id: '',
21
+ ssl_ca_certs: '',
22
+ proxy_authorization: false,
23
+ http_headers: '',
24
+ },
9
25
  templates: [
10
26
  { id: 204, name: 'default template' },
11
27
  { id: 205, name: 'default template clone' },
12
28
  ],
13
- availableEvents: ['host_created'],
29
+ availableEvents: [
30
+ { value: 'host_created.event.foreman', label: 'Host Created' },
31
+ { value: 'host_updated.event.foreman', label: 'Host Updated' },
32
+ ],
14
33
  isEventsLoading: false,
15
34
  isTemplatesLoading: false,
35
+ isPasswordDisabled: false,
36
+ isLoading: false,
37
+ setIsPasswordDisabled: jest.fn(),
16
38
  };
17
39
 
18
- const fixtures = {
19
- 'should render for new page': {
20
- ...props,
21
- initialValues: {
22
- http_method: 'POST',
23
- enabled: true,
24
- verify_ssl: true,
25
- http_content_type: 'application/json',
26
- event: 'host_created.event.foreman',
27
- },
28
- },
29
- 'should render for edit page': {
30
- ...props,
31
- initialValues: {
32
- id: 54,
33
- http_method: 'PUT',
34
- enabled: true,
35
- verify_ssl: true,
36
- http_content_type: 'application/json',
37
- event: 'host_created.event.foreman',
38
- name: 'first webhook',
39
- target_url: 'https://foreman.example.com',
40
- user: undefined,
41
- password: undefined,
42
- webhook_template_id: 204,
43
- ssl_ca_certs: undefined,
44
- },
45
- },
46
- };
40
+ describe('WebhookForm RTL Tests', () => {
41
+ beforeEach(() => {
42
+ jest.clearAllMocks();
43
+ });
44
+
45
+ test('renders General tab fields by default', () => {
46
+ render(<WebhookForm {...defaultProps} />);
47
+
48
+ expect(screen.getByText('General')).toBeInTheDocument();
49
+ expect(screen.getByText('Credentials')).toBeInTheDocument();
50
+ expect(screen.getByText('Additional')).toBeInTheDocument();
51
+
52
+ expect(screen.getByText('Subscribe to')).toBeInTheDocument();
53
+ expect(screen.getByText('Name')).toBeInTheDocument();
54
+ expect(screen.getByText('Target URL')).toBeInTheDocument();
55
+ expect(screen.getByText('Template')).toBeInTheDocument();
56
+ expect(screen.getByText('HTTP Method')).toBeInTheDocument();
57
+ expect(screen.getByText('Enabled')).toBeInTheDocument();
58
+
59
+ expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
60
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
61
+ });
62
+
63
+ describe('Tab Navigation', () => {
64
+ test('switches to Credentials tab when clicked', () => {
65
+ render(<WebhookForm {...defaultProps} />);
66
+
67
+ fireEvent.click(screen.getByText('Credentials'));
68
+
69
+ expect(screen.getByText('User')).toBeInTheDocument();
70
+ expect(screen.getByText('Password')).toBeInTheDocument();
71
+ expect(screen.getByText('Verify SSL')).toBeInTheDocument();
72
+ expect(screen.getByText('Proxy Authorization')).toBeInTheDocument();
73
+ expect(
74
+ screen.getByText('X509 Certificate Authorities')
75
+ ).toBeInTheDocument();
76
+ });
77
+
78
+ test('switches to Additional tab when clicked', () => {
79
+ render(<WebhookForm {...defaultProps} />);
80
+
81
+ fireEvent.click(screen.getByText('Additional'));
82
+
83
+ expect(screen.getByText('HTTP Content Type')).toBeInTheDocument();
84
+ expect(screen.getByText('HTTP Headers')).toBeInTheDocument();
85
+ });
86
+ });
87
+
88
+ describe('Form Field Interactions', () => {
89
+ test('toggles enabled checkbox', () => {
90
+ render(<WebhookForm {...defaultProps} />);
91
+
92
+ const enabledCheckbox = document.querySelector('input#id-enabled');
93
+ expect(enabledCheckbox).toBeChecked();
94
+
95
+ fireEvent.click(enabledCheckbox);
96
+ expect(enabledCheckbox).not.toBeChecked();
97
+ });
98
+
99
+ test('updates user field in Credentials tab', () => {
100
+ render(<WebhookForm {...defaultProps} />);
101
+
102
+ fireEvent.click(screen.getByText('Credentials'));
103
+
104
+ const userInput = document.querySelector('input#id-user');
105
+ fireEvent.change(userInput, { target: { value: 'testuser' } });
106
+
107
+ expect(userInput.value).toBe('testuser');
108
+ });
109
+ });
110
+
111
+ describe('Form Submission', () => {
112
+ test('Submit button is disabled should not call handleSubmit', async () => {
113
+ const handleSubmit = jest.fn();
114
+ render(<WebhookForm {...defaultProps} handleSubmit={handleSubmit} />);
115
+
116
+ const submitBtn = screen.getByRole('button', { name: 'Submit' });
117
+
118
+ expect(submitBtn).toBeDisabled();
119
+ fireEvent.click(submitBtn);
120
+
121
+ expect(handleSubmit).toHaveBeenCalledTimes(0);
122
+ });
123
+
124
+ test('calls handleSubmit with form data when Submit button is clicked', async () => {
125
+ const handleSubmit = jest.fn();
126
+ const initialValues = {
127
+ ...defaultProps.initialValues,
128
+ webhook_template_id: 204,
129
+ };
130
+
131
+ render(
132
+ <WebhookForm
133
+ {...defaultProps}
134
+ initialValues={initialValues}
135
+ handleSubmit={handleSubmit}
136
+ />
137
+ );
138
+
139
+ const input = document.querySelector('input#id-name');
140
+ expect(input).toBeInTheDocument();
141
+ await userEvent.type(input, 'Test Webhook');
142
+ fireEvent.change(document.querySelector('input#id-target_url'), {
143
+ target: { value: 'https://example.com/webhook' },
144
+ });
145
+
146
+ const submitBtn = screen.getByRole('button', { name: 'Submit' });
147
+
148
+ expect(submitBtn).not.toBeDisabled();
149
+ fireEvent.click(submitBtn);
150
+
151
+ expect(handleSubmit).toHaveBeenCalledTimes(1);
152
+ expect(handleSubmit).toHaveBeenCalledWith(
153
+ expect.objectContaining({
154
+ name: 'Test Webhook',
155
+ target_url: 'https://example.com/webhook',
156
+ })
157
+ );
158
+ });
159
+
160
+ test('calls onCancel when Cancel button is clicked', () => {
161
+ const onCancel = jest.fn();
162
+ render(<WebhookForm {...defaultProps} onCancel={onCancel} />);
163
+
164
+ fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));
165
+
166
+ expect(onCancel).toHaveBeenCalledTimes(1);
167
+ });
168
+ });
169
+
170
+ describe('Loading States', () => {
171
+ test('disables password field when isPasswordDisabled is true', async () => {
172
+ render(<WebhookForm {...defaultProps} isPasswordDisabled />);
173
+
174
+ await fireEvent.click(screen.getByText('Credentials'));
175
+
176
+ const passwordInput = document.querySelector('input#id-password');
177
+ expect(passwordInput).toBeDisabled();
178
+ });
179
+
180
+ test('password field rendered correctly when isPasswordDisabled is false', async () => {
181
+ render(<WebhookForm {...defaultProps} />);
182
+
183
+ await fireEvent.click(screen.getByText('Credentials'));
184
+
185
+ const passwordInput = document.querySelector('input#id-password');
186
+ expect(passwordInput).toBeInTheDocument();
187
+ expect(passwordInput).not.toBeDisabled();
188
+ });
189
+ });
190
+
191
+ describe('Initial Values', () => {
192
+ test('renders with provided initial values', () => {
193
+ const initialValues = {
194
+ ...defaultProps.initialValues,
195
+ name: 'Initial Webhook',
196
+ target_url: 'https://initial.example.com',
197
+ enabled: false,
198
+ verify_ssl: false,
199
+ };
200
+
201
+ render(<WebhookForm {...defaultProps} initialValues={initialValues} />);
202
+
203
+ expect(document.querySelector('input#id-name')).toHaveValue(
204
+ 'Initial Webhook'
205
+ );
206
+ expect(document.querySelector('input#id-target_url')).toHaveValue(
207
+ 'https://initial.example.com'
208
+ );
209
+ expect(document.querySelector('input#id-enabled')).not.toBeChecked();
210
+
211
+ fireEvent.click(screen.getByText('Credentials'));
212
+ expect(document.querySelector('input#id-verify_ssl')).not.toBeChecked();
213
+ });
214
+ });
215
+
216
+ describe('Test submitted data', () => {
217
+ test('submits correct data structure', async () => {
218
+ const handleSubmit = jest.fn();
219
+ render(<WebhookForm {...defaultProps} handleSubmit={handleSubmit} />);
220
+
221
+ const nameInput = document.querySelector('input#id-name');
222
+ await userEvent.type(nameInput, 'Webhook Test');
223
+ await fireEvent.change(document.querySelector('input#id-target_url'), {
224
+ target: { value: 'https://example.com/webhook' },
225
+ });
226
+
227
+ const webhookTemplateInput = document.querySelector(
228
+ 'input#id-webhook_template_id'
229
+ );
230
+ fireEvent.click(webhookTemplateInput);
231
+
232
+ await waitFor(() => {
233
+ const option = screen.getByRole('option', { name: 'default template' });
234
+ fireEvent.click(option);
235
+ });
236
+
237
+ await fireEvent.click(screen.getByText('Credentials'));
238
+
239
+ const userInput = document.querySelector('input#id-user');
240
+ await fireEvent.change(userInput, { target: { value: 'testuser' } });
241
+
242
+ const passwordInput = document.querySelector('input#id-password');
243
+ await fireEvent.change(passwordInput, { target: { value: 'testpass' } });
244
+
245
+ const submitBtn = screen.getByRole('button', { name: 'Submit' });
246
+
247
+ expect(submitBtn).not.toBeDisabled();
248
+ fireEvent.click(submitBtn);
47
249
 
48
- describe('WebhookForm', () => {
49
- describe('rendering', () =>
50
- testComponentSnapshotsWithFixtures(WebhookForm, fixtures));
250
+ expect(handleSubmit).toHaveBeenCalledWith({
251
+ name: 'Webhook Test',
252
+ target_url: 'https://example.com/webhook',
253
+ webhook_template_id: 204,
254
+ http_method: 'POST',
255
+ enabled: true,
256
+ verify_ssl: true,
257
+ http_content_type: 'application/json',
258
+ event: 'host_created.event.foreman',
259
+ user: 'testuser',
260
+ password: 'testpass',
261
+ proxy_authorization: false,
262
+ ssl_ca_certs: '',
263
+ http_headers: '',
264
+ });
265
+ });
266
+ });
51
267
  });
@@ -25,11 +25,11 @@ import {
25
25
  const params = { page: 1, search: 'snippet = false', per_page: 'all' };
26
26
 
27
27
  const ConnectedWebhookForm = ({
28
+ isLoading,
28
29
  onCancel,
29
30
  handleSubmit,
30
31
  initialValues,
31
32
  isPasswordDisabled,
32
- setIsPasswordDisabled,
33
33
  }) => {
34
34
  const dispatch = useDispatch();
35
35
 
@@ -59,6 +59,7 @@ const ConnectedWebhookForm = ({
59
59
 
60
60
  return (
61
61
  <WebhookForm
62
+ isLoading={isLoading}
62
63
  templates={templates}
63
64
  availableEvents={availableEvents}
64
65
  onCancel={onCancel}
@@ -67,22 +68,20 @@ const ConnectedWebhookForm = ({
67
68
  isTemplatesLoading={isTemplatesLoading}
68
69
  isEventsLoading={isEventsLoading}
69
70
  isPasswordDisabled={isPasswordDisabled}
70
- setIsPasswordDisabled={setIsPasswordDisabled}
71
71
  />
72
72
  );
73
73
  };
74
74
 
75
75
  ConnectedWebhookForm.propTypes = {
76
+ isLoading: PropTypes.bool.isRequired,
76
77
  onCancel: PropTypes.func.isRequired,
77
78
  handleSubmit: PropTypes.func.isRequired,
78
79
  initialValues: PropTypes.object.isRequired,
79
80
  isPasswordDisabled: PropTypes.bool,
80
- setIsPasswordDisabled: PropTypes.func,
81
81
  };
82
82
 
83
83
  ConnectedWebhookForm.defaultProps = {
84
84
  isPasswordDisabled: false,
85
- setIsPasswordDisabled: undefined,
86
85
  };
87
86
 
88
87
  export default ConnectedWebhookForm;
@@ -1,12 +1,11 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Modal } from 'patternfly-react';
3
+ import { Modal, ModalVariant } from '@patternfly/react-core';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
- import { submitForm } from 'foremanReact/redux/actions/common/forms';
8
7
  import { foremanUrl } from 'foremanReact/common/helpers';
9
- import ForemanModal from 'foremanReact/components/ForemanModal';
8
+ import { APIActions } from 'foremanReact/redux/API';
10
9
 
11
10
  import ConnectedWebhookForm from '../../Components/WebhookForm';
12
11
 
@@ -14,9 +13,10 @@ import { WEBHOOK_CREATE_MODAL_ID, WEBHOOKS_PATH } from '../../constants';
14
13
 
15
14
  import './WebhookModal.scss';
16
15
 
17
- const WebhookCreateModal = ({ onSuccess, onCancel }) => {
16
+ const WebhookCreateModal = ({ onSuccess, onCancel, isOpen }) => {
18
17
  const dispatch = useDispatch();
19
18
 
19
+ const [isLoading, setIsLoading] = useState(false);
20
20
  const initialWebhookValues = {
21
21
  name: '',
22
22
  target_url: '',
@@ -33,39 +33,50 @@ const WebhookCreateModal = ({ onSuccess, onCancel }) => {
33
33
  proxy_authorization: false,
34
34
  };
35
35
 
36
- const handleSubmit = (values, actions) =>
36
+ const handleSubmit = values => {
37
+ setIsLoading(true);
37
38
  dispatch(
38
- submitForm({
39
+ APIActions.post({
39
40
  url: foremanUrl(`/api${WEBHOOKS_PATH}`),
40
- values: { ...values, controller: 'webhooks' },
41
- item: 'Webhook',
42
- message: __('Webhook was successfully created.'),
43
- successCallback: onSuccess,
44
- actions,
41
+ key: WEBHOOK_CREATE_MODAL_ID,
42
+ params: { ...values, controller: 'webhooks' },
43
+ successToast: () => __('Webhook was successfully created.'),
44
+ handleSuccess: () => {
45
+ onSuccess();
46
+ setIsLoading(false);
47
+ },
48
+ handleError: () => setIsLoading(false),
49
+ errorToast: ({ response }) =>
50
+ // eslint-disable-next-line camelcase
51
+ response?.data?.error?.full_messages?.[0] || response,
45
52
  })
46
53
  );
54
+ };
47
55
 
48
56
  return (
49
- <ForemanModal
57
+ <Modal
58
+ position="top"
59
+ variant={ModalVariant.medium}
60
+ isOpen={isOpen}
61
+ onClose={onCancel}
50
62
  id={WEBHOOK_CREATE_MODAL_ID}
51
- backdrop="static"
52
- className="webhooks-modal"
63
+ ouiaId={WEBHOOK_CREATE_MODAL_ID}
64
+ title={__('Create Webhook')}
53
65
  >
54
- <Modal.Header>
55
- <Modal.Title>{__('Create Webhook')}</Modal.Title>
56
- </Modal.Header>
57
66
  <ConnectedWebhookForm
67
+ isLoading={isLoading}
58
68
  handleSubmit={handleSubmit}
59
69
  initialValues={initialWebhookValues}
60
70
  onCancel={onCancel}
61
71
  />
62
- </ForemanModal>
72
+ </Modal>
63
73
  );
64
74
  };
65
75
 
66
76
  WebhookCreateModal.propTypes = {
67
77
  onSuccess: PropTypes.func.isRequired,
68
78
  onCancel: PropTypes.func.isRequired,
79
+ isOpen: PropTypes.bool.isRequired,
69
80
  };
70
81
 
71
82
  export default WebhookCreateModal;
@@ -1,40 +1,74 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
+ import { APIActions } from 'foremanReact/redux/API';
5
+ import { useDispatch } from 'react-redux';
4
6
  import { sprintf, translate as __ } from 'foremanReact/common/I18n';
5
- import ForemanModal from 'foremanReact/components/ForemanModal';
6
7
  import { foremanUrl } from 'foremanReact/common/helpers';
8
+ import { Modal, Button, ModalVariant } from '@patternfly/react-core';
7
9
 
8
10
  import { WEBHOOK_DELETE_MODAL_ID } from '../../constants';
9
11
 
10
- const WebhookDeleteModal = ({ toDelete, onSuccess }) => {
12
+ const WebhookDeleteModal = ({ toDelete, onSuccess, modalState }) => {
11
13
  const { id, name } = toDelete;
12
14
 
15
+ const dispatch = useDispatch();
16
+ const handleSubmit = () =>
17
+ dispatch(
18
+ APIActions.delete({
19
+ url: foremanUrl(`/api/v2/webhooks/${id}`),
20
+ key: WEBHOOK_DELETE_MODAL_ID,
21
+ successToast: () =>
22
+ sprintf(__('Webhook %s was successfully deleted'), name),
23
+ errorToast: response =>
24
+ // eslint-disable-next-line camelcase
25
+ response?.response?.data?.error?.full_messages?.[0] || response,
26
+ handleSuccess: onSuccess,
27
+ })
28
+ );
29
+
13
30
  return (
14
- <ForemanModal
31
+ <Modal
32
+ position="top"
33
+ variant={ModalVariant.small}
15
34
  id={WEBHOOK_DELETE_MODAL_ID}
35
+ ouiaId={WEBHOOK_DELETE_MODAL_ID}
16
36
  title={__('Confirm Webhook Deletion')}
17
- backdrop="static"
18
- enforceFocus
19
- submitProps={{
20
- url: foremanUrl(`/api/v2/webhooks/${id}`),
21
- message: sprintf(__('Webhook %s was successfully deleted'), name),
22
- onSuccess,
23
- submitBtnProps: {
24
- bsStyle: 'danger',
25
- btnText: __('Delete'),
26
- },
27
- }}
28
- >
29
- {sprintf(__('You are about to delete %s. Are you sure?'), name)}
30
- <ForemanModal.Footer />
31
- </ForemanModal>
37
+ isOpen={modalState.isOpen}
38
+ onClose={modalState.closeModal}
39
+ description={sprintf(
40
+ __('You are about to delete %s. Are you sure?'),
41
+ name
42
+ )}
43
+ actions={[
44
+ <Button
45
+ ouiaId="submitBtn"
46
+ key="confirm"
47
+ variant="danger"
48
+ onClick={handleSubmit}
49
+ >
50
+ {__('Delete')}
51
+ </Button>,
52
+ <Button
53
+ ouiaId="cancelBtn"
54
+ key="cancel"
55
+ variant="link"
56
+ onClick={modalState.closeModal}
57
+ >
58
+ {__('Cancel')}
59
+ </Button>,
60
+ ]}
61
+ />
32
62
  );
33
63
  };
34
64
 
35
65
  WebhookDeleteModal.propTypes = {
36
66
  toDelete: PropTypes.object,
37
67
  onSuccess: PropTypes.func.isRequired,
68
+ modalState: PropTypes.shape({
69
+ isOpen: PropTypes.bool.isRequired,
70
+ closeModal: PropTypes.func.isRequired,
71
+ }).isRequired,
38
72
  };
39
73
 
40
74
  WebhookDeleteModal.defaultProps = {