foreman_webhooks 5.0.3 → 5.1.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.
- checksums.yaml +4 -4
- data/Rakefile +0 -15
- data/app/models/webhook.rb +1 -1
- data/lib/foreman_webhooks/version.rb +1 -1
- data/webpack/ForemanWebhooks/Routes/ForemanWebhooksRoutes.js +1 -1
- data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookTable/Components/Formatters/__tests__/actionCellFormatter.test.js +109 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookTable/Components/Formatters/__tests__/enabledCellFormatter.test.js +38 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookTable/Components/Formatters/__tests__/nameToEditFormatter.test.js +82 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookTable/Components/Formatters/actionCellFormatter.js +23 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/{WebhooksIndexPage/Components/WebhooksTable/Components/EnabledCell.js → Components/WebhookTable/Components/Formatters/enabledCellFormatter.js} +6 -1
- data/webpack/ForemanWebhooks/Routes/Webhooks/Components/WebhookTable/Components/Formatters/nameToEditFormatter.js +33 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookCreateModal.js +1 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookDeleteModal.js +5 -1
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookEditModal.js +1 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/WebhooksIndexPage.js +120 -16
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/WebhooksIndexPage.test.js +130 -22
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/integration.test.js +10 -3
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/mocks/MockForemanTableIndexPage.js +37 -0
- data/webpack/ForemanWebhooks/Routes/Webhooks/constants.js +3 -3
- data/webpack/test_setup.js +3 -0
- metadata +18 -93
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/EmptyWebhooksTable/index.js +0 -29
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/__tests__/__snapshots__/enabledCellFormatter.test.js.snap +0 -7
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/__tests__/enabledCellFormatter.test.js +0 -7
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/actionCellFormatter.js +0 -20
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/enabledCellFormatter.js +0 -6
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/index.js +0 -3
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/Formatters/nameToEditFormatter.js +0 -19
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/NameToEditCell.js +0 -42
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/__tests__/EnabledCell.test.js +0 -14
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/Components/__tests__/__snapshots__/EnabledCell.test.js.snap +0 -5
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTable.js +0 -121
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/WebhooksTableSchema.js +0 -48
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/WebhooksTable.test.js +0 -64
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/__tests__/__snapshots__/WebhooksTable.test.js.snap +0 -250
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhooksTable/index.js +0 -76
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/__tests__/__snapshots__/WebhooksIndexPage.test.js.snap +0 -17
- data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/index.js +0 -3
- data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +0 -1
- data/webpack/__mocks__/foremanReact/common/HOC.js +0 -30
- data/webpack/__mocks__/foremanReact/common/I18n.js +0 -7
- data/webpack/__mocks__/foremanReact/common/helpers.js +0 -7
- data/webpack/__mocks__/foremanReact/common/urlHelpers.js +0 -8
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +0 -10
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -23
- data/webpack/__mocks__/foremanReact/components/Layout/LayoutActions.js +0 -2
- data/webpack/__mocks__/foremanReact/components/Loading/Loading.js +0 -2
- data/webpack/__mocks__/foremanReact/components/Loading/index.js +0 -3
- data/webpack/__mocks__/foremanReact/components/PF4/TableIndexPage/TableIndexPage.js +0 -10
- data/webpack/__mocks__/foremanReact/components/Pagination/index.js +0 -4
- data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +0 -3
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +0 -5
- data/webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js +0 -9
- data/webpack/__mocks__/foremanReact/components/common/forms/FormField.js +0 -3
- data/webpack/__mocks__/foremanReact/components/common/table.js +0 -26
- data/webpack/__mocks__/foremanReact/constants.js +0 -24
- data/webpack/__mocks__/foremanReact/history.js +0 -3
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +0 -6
- data/webpack/__mocks__/foremanReact/redux/API/index.js +0 -10
- data/webpack/__mocks__/foremanReact/redux/actions/common/forms.js +0 -1
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +0 -8
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +0 -10
- /data/webpack/ForemanWebhooks/Routes/Webhooks/{WebhooksIndexPage/Components/WebhooksTable → Components/WebhookTable}/Components/ActionButtons/ActionButton.js +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c90b385f92db59657a6f026239c2ccfda1b574c852563755fd4dab6522cbf84c
|
|
4
|
+
data.tar.gz: 05324c9d1589fed4e35b0bf477d0edc7380b5e1abe391872d27a18457355f6f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8956d6c344db760a44ee50c9699d701078a5cae604dc561a40d55ecb25717d03129dceed5bb770c337cd9b1bc28455b0fff5aa80431e2b6834a368476f358ad
|
|
7
|
+
data.tar.gz: 5d47beee070a29ac44960ea8c8bbe81e19179be5d806f062809a804457fc2929ea63dab6c6569b89d8ebf0d22a0af7c8a14dee2e1c53b15f1a3e6889eb485755
|
data/Rakefile
CHANGED
|
@@ -6,21 +6,6 @@ begin
|
|
|
6
6
|
rescue LoadError
|
|
7
7
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
8
8
|
end
|
|
9
|
-
begin
|
|
10
|
-
require 'rdoc/task'
|
|
11
|
-
rescue LoadError
|
|
12
|
-
require 'rdoc/rdoc'
|
|
13
|
-
require 'rake/rdoctask'
|
|
14
|
-
RDoc::Task = Rake::RDocTask
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
|
18
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
19
|
-
rdoc.title = 'ForemanWebhooks'
|
|
20
|
-
rdoc.options << '--line-numbers'
|
|
21
|
-
rdoc.rdoc_files.include('README.rdoc')
|
|
22
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
23
|
-
end
|
|
24
9
|
|
|
25
10
|
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
|
26
11
|
|
data/app/models/webhook.rb
CHANGED
|
@@ -11,7 +11,7 @@ class Webhook < ApplicationRecord
|
|
|
11
11
|
|
|
12
12
|
graphql_type 'ForemanWebhooks::Types::Webhook'
|
|
13
13
|
|
|
14
|
-
EVENT_POSTFIX = ".#{Foreman::Observable::DEFAULT_NAMESPACE}"
|
|
14
|
+
EVENT_POSTFIX = ".#{Foreman::Observable::DEFAULT_NAMESPACE}".freeze
|
|
15
15
|
|
|
16
16
|
DEFAULT_PAYLOAD_TEMPLATE = 'Webhook Template - Payload Default'
|
|
17
17
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import actionCellFormatter from '../actionCellFormatter';
|
|
6
|
+
|
|
7
|
+
jest.mock(
|
|
8
|
+
'foremanReact/components/common/table',
|
|
9
|
+
() => ({
|
|
10
|
+
cellFormatter: content => (
|
|
11
|
+
<div data-testid="cell-formatter-mock">
|
|
12
|
+
{content === false ? null : content}
|
|
13
|
+
</div>
|
|
14
|
+
),
|
|
15
|
+
}),
|
|
16
|
+
{ virtual: true }
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
jest.mock('../../ActionButtons/ActionButton', () => {
|
|
20
|
+
// eslint-disable-next-line global-require
|
|
21
|
+
const PropTypes = require('prop-types');
|
|
22
|
+
|
|
23
|
+
const ActionButton = ({ id, name, canDelete }) => (
|
|
24
|
+
<span
|
|
25
|
+
data-testid="action-button"
|
|
26
|
+
data-id={id}
|
|
27
|
+
data-name={name}
|
|
28
|
+
data-can-delete={String(canDelete)}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
ActionButton.propTypes = {
|
|
32
|
+
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
33
|
+
name: PropTypes.string.isRequired,
|
|
34
|
+
canDelete: PropTypes.bool,
|
|
35
|
+
};
|
|
36
|
+
ActionButton.defaultProps = {
|
|
37
|
+
canDelete: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return { ActionButton };
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('actionCellFormatter', () => {
|
|
44
|
+
const webhookActions = {
|
|
45
|
+
deleteWebhook: jest.fn(),
|
|
46
|
+
testWebhook: jest.fn(),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
jest.clearAllMocks();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('wraps the action control in cellFormatter when rowData is present and the row is editable', () => {
|
|
54
|
+
const formatter = actionCellFormatter(webhookActions);
|
|
55
|
+
const row = { id: 10, name: 'Wh', can_edit: true, can_delete: true };
|
|
56
|
+
|
|
57
|
+
render(formatter(null, { rowData: row }));
|
|
58
|
+
|
|
59
|
+
expect(screen.getByTestId('cell-formatter-mock')).toBeInTheDocument();
|
|
60
|
+
const action = screen.getByTestId('action-button');
|
|
61
|
+
expect(action).toHaveAttribute('data-id', '10');
|
|
62
|
+
expect(action).toHaveAttribute('data-name', 'Wh');
|
|
63
|
+
expect(action).toHaveAttribute('data-can-delete', 'true');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('passes canDelete from can_delete when rowData is present', () => {
|
|
67
|
+
const formatter = actionCellFormatter(webhookActions);
|
|
68
|
+
const row = { id: 2, name: 'A', can_edit: true, can_delete: false };
|
|
69
|
+
|
|
70
|
+
render(formatter(null, { rowData: row }));
|
|
71
|
+
|
|
72
|
+
expect(screen.getByTestId('action-button')).toHaveAttribute(
|
|
73
|
+
'data-can-delete',
|
|
74
|
+
'false'
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('renders falsy content through cellFormatter when rowData is present but the row is not editable', () => {
|
|
79
|
+
const formatter = actionCellFormatter(webhookActions);
|
|
80
|
+
const row = { id: 5, name: 'B', can_edit: false };
|
|
81
|
+
|
|
82
|
+
render(formatter(null, { rowData: row }));
|
|
83
|
+
|
|
84
|
+
expect(screen.getByTestId('cell-formatter-mock')).toBeInTheDocument();
|
|
85
|
+
expect(screen.queryByTestId('action-button')).not.toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns the action control without cellFormatter when rowData is omitted', () => {
|
|
89
|
+
const formatter = actionCellFormatter(webhookActions);
|
|
90
|
+
const row = { id: 20, name: 'Direct', can_edit: true, canDelete: true };
|
|
91
|
+
|
|
92
|
+
render(formatter(row));
|
|
93
|
+
|
|
94
|
+
expect(screen.queryByTestId('cell-formatter-mock')).not.toBeInTheDocument();
|
|
95
|
+
expect(screen.getByTestId('action-button')).toHaveAttribute(
|
|
96
|
+
'data-id',
|
|
97
|
+
'20'
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('returns nothing when rowData is omitted and the row is not editable', () => {
|
|
102
|
+
const formatter = actionCellFormatter(webhookActions);
|
|
103
|
+
const row = { id: 1, name: 'X', can_edit: false };
|
|
104
|
+
|
|
105
|
+
const { container } = render(formatter(row));
|
|
106
|
+
|
|
107
|
+
expect(container).toBeEmptyDOMElement();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import enabledCellFormatter from '../enabledCellFormatter';
|
|
6
|
+
|
|
7
|
+
jest.mock('@patternfly/react-icons', () => ({
|
|
8
|
+
CheckIcon: () => <span data-testid="check-icon" />,
|
|
9
|
+
BanIcon: () => <span data-testid="ban-icon" />,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
const renderCell = (value, extra) => {
|
|
13
|
+
const formatter = enabledCellFormatter();
|
|
14
|
+
const element = formatter(value, extra);
|
|
15
|
+
return render(element);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe('enabledCellFormatter', () => {
|
|
19
|
+
it('uses the cell value when row context includes rowData and value is true', () => {
|
|
20
|
+
renderCell(true, { rowData: { id: 1, enabled: false } });
|
|
21
|
+
expect(screen.getByTestId('check-icon')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('uses the cell value when row context includes rowData and value is false', () => {
|
|
25
|
+
renderCell(false, { rowData: { id: 1, enabled: true } });
|
|
26
|
+
expect(screen.getByTestId('ban-icon')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('uses value.enabled when rowData is not present and enabled is true', () => {
|
|
30
|
+
renderCell({ enabled: true });
|
|
31
|
+
expect(screen.getByTestId('check-icon')).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('uses value.enabled when rowData is not present and enabled is false', () => {
|
|
35
|
+
renderCell({ enabled: false });
|
|
36
|
+
expect(screen.getByTestId('ban-icon')).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import nameToEditFormatter from '../nameToEditFormatter';
|
|
6
|
+
|
|
7
|
+
jest.mock('@patternfly/react-core', () => {
|
|
8
|
+
// eslint-disable-next-line global-require
|
|
9
|
+
const PropTypes = require('prop-types');
|
|
10
|
+
|
|
11
|
+
const Button = ({ children, onClick, isDisabled }) => (
|
|
12
|
+
<button type="button" onClick={onClick} disabled={isDisabled}>
|
|
13
|
+
{children}
|
|
14
|
+
</button>
|
|
15
|
+
);
|
|
16
|
+
Button.propTypes = {
|
|
17
|
+
children: PropTypes.node,
|
|
18
|
+
onClick: PropTypes.func,
|
|
19
|
+
isDisabled: PropTypes.bool,
|
|
20
|
+
};
|
|
21
|
+
Button.defaultProps = {
|
|
22
|
+
children: null,
|
|
23
|
+
onClick: () => {},
|
|
24
|
+
isDisabled: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return { Button };
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('nameToEditFormatter', () => {
|
|
31
|
+
it('renders the cell value as the label and calls the handler with the row id when can_edit is true', () => {
|
|
32
|
+
const onEdit = jest.fn();
|
|
33
|
+
const formatter = nameToEditFormatter(onEdit);
|
|
34
|
+
const row = { id: 42, name: 'Other', can_edit: true };
|
|
35
|
+
|
|
36
|
+
render(formatter('Shown name', { rowData: row }));
|
|
37
|
+
|
|
38
|
+
expect(screen.getByText('Shown name')).toBeInTheDocument();
|
|
39
|
+
fireEvent.click(screen.getByText('Shown name'));
|
|
40
|
+
expect(onEdit).toHaveBeenCalledTimes(1);
|
|
41
|
+
expect(onEdit).toHaveBeenCalledWith(42);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('prefers canEdit over can_edit when both are set', () => {
|
|
45
|
+
const onEdit = jest.fn();
|
|
46
|
+
const formatter = nameToEditFormatter(onEdit);
|
|
47
|
+
|
|
48
|
+
render(
|
|
49
|
+
formatter('Label', {
|
|
50
|
+
rowData: { id: 1, name: 'N', canEdit: true, can_edit: false },
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
fireEvent.click(screen.getByText('Label'));
|
|
55
|
+
expect(onEdit).toHaveBeenCalledWith(1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('does not call the handler when the row cannot be edited', () => {
|
|
59
|
+
const onEdit = jest.fn();
|
|
60
|
+
const formatter = nameToEditFormatter(onEdit);
|
|
61
|
+
|
|
62
|
+
render(
|
|
63
|
+
formatter('Read only', {
|
|
64
|
+
rowData: { id: 7, name: 'X', can_edit: false },
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const control = screen.getByText('Read only');
|
|
69
|
+
expect(control.closest('button')).toBeDisabled();
|
|
70
|
+
fireEvent.click(control);
|
|
71
|
+
expect(onEdit).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('uses row.name as the label when rowData is not passed and value is the row object', () => {
|
|
75
|
+
const formatter = nameToEditFormatter(jest.fn());
|
|
76
|
+
const row = { id: 3, name: 'From row', can_edit: false };
|
|
77
|
+
|
|
78
|
+
render(formatter(row));
|
|
79
|
+
|
|
80
|
+
expect(screen.getByText('From row')).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cellFormatter } from 'foremanReact/components/common/table';
|
|
3
|
+
import { ActionButton } from '../ActionButtons/ActionButton';
|
|
4
|
+
|
|
5
|
+
const actionCellFormatter = webhookActions => (value, extra) => {
|
|
6
|
+
const row = extra?.rowData ?? value;
|
|
7
|
+
const canEdit = row.canEdit ?? row.can_edit;
|
|
8
|
+
const canDelete = row.canDelete ?? row.can_delete;
|
|
9
|
+
const { id, name } = row;
|
|
10
|
+
|
|
11
|
+
const content = canEdit && (
|
|
12
|
+
<ActionButton
|
|
13
|
+
canDelete={canDelete}
|
|
14
|
+
id={id}
|
|
15
|
+
name={name}
|
|
16
|
+
webhookActions={webhookActions}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return extra?.rowData != null ? cellFormatter(content) : content;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default actionCellFormatter;
|
|
@@ -13,4 +13,9 @@ EnabledCell.defaultProps = {
|
|
|
13
13
|
condition: false,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const enabledCellFormatter = () => (value, extra) => {
|
|
17
|
+
const condition = extra?.rowData != null ? value : value?.enabled;
|
|
18
|
+
return <EnabledCell condition={Boolean(condition)} />;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default enabledCellFormatter;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from '@patternfly/react-core';
|
|
3
|
+
|
|
4
|
+
const nameToEditFormatter = onClick => (value, extra) => {
|
|
5
|
+
const row = extra?.rowData ?? value;
|
|
6
|
+
const canEdit = row.canEdit ?? row.can_edit;
|
|
7
|
+
const { id } = row;
|
|
8
|
+
const label = extra?.rowData != null ? value : row.name;
|
|
9
|
+
|
|
10
|
+
return canEdit ? (
|
|
11
|
+
<Button
|
|
12
|
+
ouiaId="name-edit-active-button"
|
|
13
|
+
variant="link"
|
|
14
|
+
isInline
|
|
15
|
+
component="span"
|
|
16
|
+
onClick={() => onClick(id)}
|
|
17
|
+
>
|
|
18
|
+
{label}
|
|
19
|
+
</Button>
|
|
20
|
+
) : (
|
|
21
|
+
<Button
|
|
22
|
+
ouiaId="name-edit-disabled-button"
|
|
23
|
+
variant="link"
|
|
24
|
+
isInline
|
|
25
|
+
isDisabled
|
|
26
|
+
component="span"
|
|
27
|
+
>
|
|
28
|
+
{label}
|
|
29
|
+
</Button>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default nameToEditFormatter;
|
data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookCreateModal.js
CHANGED
|
@@ -42,6 +42,7 @@ const WebhookCreateModal = ({ onSuccess, onCancel, isOpen }) => {
|
|
|
42
42
|
params: { ...values, controller: 'webhooks' },
|
|
43
43
|
successToast: () => __('Webhook was successfully created.'),
|
|
44
44
|
handleSuccess: () => {
|
|
45
|
+
setIsSubmitting(false);
|
|
45
46
|
onSuccess();
|
|
46
47
|
},
|
|
47
48
|
handleError: () => setIsSubmitting(false),
|
data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookDeleteModal.js
CHANGED
|
@@ -14,6 +14,7 @@ const WebhookDeleteModal = ({ toDelete, onSuccess, modalState }) => {
|
|
|
14
14
|
|
|
15
15
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
16
16
|
const dispatch = useDispatch();
|
|
17
|
+
|
|
17
18
|
const handleSubmit = () => {
|
|
18
19
|
setIsSubmitting(true);
|
|
19
20
|
dispatch(
|
|
@@ -25,7 +26,10 @@ const WebhookDeleteModal = ({ toDelete, onSuccess, modalState }) => {
|
|
|
25
26
|
errorToast: response =>
|
|
26
27
|
// eslint-disable-next-line camelcase
|
|
27
28
|
response?.response?.data?.error?.full_messages?.[0] || response,
|
|
28
|
-
handleSuccess:
|
|
29
|
+
handleSuccess: () => {
|
|
30
|
+
setIsSubmitting(false);
|
|
31
|
+
onSuccess();
|
|
32
|
+
},
|
|
29
33
|
handleError: () => setIsSubmitting(false),
|
|
30
34
|
})
|
|
31
35
|
);
|
data/webpack/ForemanWebhooks/Routes/Webhooks/WebhooksIndexPage/Components/WebhookEditModal.js
CHANGED
|
@@ -69,6 +69,7 @@ const WebhookEditModal = ({ toEdit, onSuccess, modalState }) => {
|
|
|
69
69
|
params: { ...values, controller: 'webhooks' },
|
|
70
70
|
successToast: () => __('Webhook was successfully updated.'),
|
|
71
71
|
handleSuccess: () => {
|
|
72
|
+
setIsSubmitting(false);
|
|
72
73
|
onSuccess();
|
|
73
74
|
},
|
|
74
75
|
handleError: () => setIsSubmitting(false),
|
|
@@ -4,12 +4,25 @@ import { useSelector, useDispatch } from 'react-redux';
|
|
|
4
4
|
import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
|
|
5
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
WEBHOOKS_API_REQUEST_KEY,
|
|
9
|
+
WEBHOOKS_API_PLAIN_PATH,
|
|
10
|
+
} from '../constants';
|
|
8
11
|
|
|
9
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
selectPage,
|
|
14
|
+
selectPerPage,
|
|
15
|
+
selectSearch,
|
|
16
|
+
selectSubtotal,
|
|
17
|
+
} from '../WebhooksPageSelectors';
|
|
10
18
|
|
|
11
|
-
import WebhooksTable from './Components/WebhooksTable';
|
|
12
19
|
import WebhookCreateModal from './Components/WebhookCreateModal';
|
|
20
|
+
import WebhookDeleteModal from './Components/WebhookDeleteModal';
|
|
21
|
+
import WebhookEditModal from './Components/WebhookEditModal';
|
|
22
|
+
import WebhookTestModal from './Components/WebhookTestModal';
|
|
23
|
+
import nameToEditFormatter from '../Components/WebhookTable/Components/Formatters/nameToEditFormatter';
|
|
24
|
+
import enabledCellFormatter from '../Components/WebhookTable/Components/Formatters/enabledCellFormatter';
|
|
25
|
+
import actionCellFormatter from '../Components/WebhookTable/Components/Formatters/actionCellFormatter';
|
|
13
26
|
|
|
14
27
|
import { reloadWithSearch, fetchAndPush } from '../WebhooksPageActions';
|
|
15
28
|
|
|
@@ -17,16 +30,100 @@ const WebhooksIndexPage = () => {
|
|
|
17
30
|
const dispatch = useDispatch();
|
|
18
31
|
|
|
19
32
|
const search = useSelector(selectSearch);
|
|
33
|
+
const page = useSelector(selectPage);
|
|
34
|
+
const perPage = useSelector(selectPerPage);
|
|
35
|
+
const itemCount = useSelector(selectSubtotal);
|
|
20
36
|
|
|
21
37
|
const [toDelete, setToDelete] = useState({});
|
|
22
38
|
const [toTest, setToTest] = useState({});
|
|
23
39
|
const [toEdit, setToEdit] = useState(0);
|
|
24
40
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
41
|
+
const [isTestModalOpen, setIsTestModalOpen] = useState(false);
|
|
42
|
+
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
|
43
|
+
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
|
25
44
|
|
|
26
45
|
const openModal = () => {
|
|
27
46
|
setIsCreateModalOpen(true);
|
|
28
47
|
};
|
|
29
48
|
|
|
49
|
+
const onEditClick = rowData => {
|
|
50
|
+
setToEdit(rowData);
|
|
51
|
+
setIsEditModalOpen(true);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const onTestClick = rowData => {
|
|
55
|
+
setToTest(rowData);
|
|
56
|
+
setIsTestModalOpen(true);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const onDeleteClick = rowData => {
|
|
60
|
+
setToDelete(rowData);
|
|
61
|
+
setIsDeleteModalOpen(true);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const webhookActions = {
|
|
65
|
+
deleteWebhook: (id, name) => {
|
|
66
|
+
onDeleteClick({ id, name });
|
|
67
|
+
},
|
|
68
|
+
testWebhook: (id, name) => {
|
|
69
|
+
onTestClick({ id, name });
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const modalsStates = {
|
|
74
|
+
testModal: {
|
|
75
|
+
isOpen: isTestModalOpen,
|
|
76
|
+
closeModal: () => {
|
|
77
|
+
setToTest({});
|
|
78
|
+
setIsTestModalOpen(false);
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
deleteModal: {
|
|
82
|
+
isOpen: isDeleteModalOpen,
|
|
83
|
+
closeModal: () => {
|
|
84
|
+
setToDelete({});
|
|
85
|
+
setIsDeleteModalOpen(false);
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
editModal: {
|
|
89
|
+
isOpen: isEditModalOpen,
|
|
90
|
+
closeModal: () => {
|
|
91
|
+
setToEdit(0);
|
|
92
|
+
setIsEditModalOpen(false);
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const columns = {
|
|
98
|
+
name: {
|
|
99
|
+
title: __('Name'),
|
|
100
|
+
wrapper: nameToEditFormatter(onEditClick),
|
|
101
|
+
isSorted: true,
|
|
102
|
+
},
|
|
103
|
+
target_url: {
|
|
104
|
+
title: __('Target URL'),
|
|
105
|
+
isSorted: true,
|
|
106
|
+
},
|
|
107
|
+
enabled: {
|
|
108
|
+
title: __('Enabled'),
|
|
109
|
+
wrapper: enabledCellFormatter(),
|
|
110
|
+
isSorted: true,
|
|
111
|
+
},
|
|
112
|
+
actions: {
|
|
113
|
+
title: __('Actions'),
|
|
114
|
+
wrapper: actionCellFormatter(webhookActions),
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const onDeleteSuccess = () => {
|
|
119
|
+
modalsStates.deleteModal.closeModal();
|
|
120
|
+
const currentPage = page;
|
|
121
|
+
const maxPage = Math.ceil((itemCount - 1) / perPage);
|
|
122
|
+
dispatch(
|
|
123
|
+
fetchAndPush({ page: maxPage < currentPage ? maxPage : currentPage })
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
30
127
|
return (
|
|
31
128
|
<>
|
|
32
129
|
<WebhookCreateModal
|
|
@@ -37,24 +134,31 @@ const WebhooksIndexPage = () => {
|
|
|
37
134
|
}}
|
|
38
135
|
onCancel={() => setIsCreateModalOpen(false)}
|
|
39
136
|
/>
|
|
137
|
+
<WebhookDeleteModal
|
|
138
|
+
toDelete={toDelete}
|
|
139
|
+
onSuccess={onDeleteSuccess}
|
|
140
|
+
modalState={modalsStates.deleteModal}
|
|
141
|
+
/>
|
|
142
|
+
<WebhookEditModal
|
|
143
|
+
toEdit={toEdit}
|
|
144
|
+
onSuccess={() => {
|
|
145
|
+
modalsStates.editModal.closeModal();
|
|
146
|
+
dispatch(reloadWithSearch(search));
|
|
147
|
+
}}
|
|
148
|
+
modalState={modalsStates.editModal}
|
|
149
|
+
/>
|
|
150
|
+
<WebhookTestModal toTest={toTest} modalState={modalsStates.testModal} />
|
|
151
|
+
|
|
40
152
|
<TableIndexPage
|
|
41
153
|
header={__('Webhooks')}
|
|
42
154
|
controller="webhooks"
|
|
43
|
-
apiUrl={
|
|
155
|
+
apiUrl={WEBHOOKS_API_PLAIN_PATH}
|
|
44
156
|
apiOptions={{ key: WEBHOOKS_API_REQUEST_KEY }}
|
|
45
157
|
customCreateAction={() => openModal}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
setToDelete={setToDelete}
|
|
51
|
-
toEdit={toEdit}
|
|
52
|
-
setToEdit={setToEdit}
|
|
53
|
-
toTest={toTest}
|
|
54
|
-
setToTest={setToTest}
|
|
55
|
-
reloadWithSearch={query => dispatch(reloadWithSearch(query))}
|
|
56
|
-
/>
|
|
57
|
-
</TableIndexPage>
|
|
158
|
+
columns={columns}
|
|
159
|
+
id="webhooks-table"
|
|
160
|
+
key="webhooks-table"
|
|
161
|
+
/>
|
|
58
162
|
</>
|
|
59
163
|
);
|
|
60
164
|
};
|