foreman_puppet 11.0.0 → 11.2.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_puppet/locale/ca/foreman_puppet.js +181 -1
  3. data/app/assets/javascripts/foreman_puppet/locale/cs_CZ/foreman_puppet.js +181 -1
  4. data/app/assets/javascripts/foreman_puppet/locale/de/foreman_puppet.js +181 -1
  5. data/app/assets/javascripts/foreman_puppet/locale/en/foreman_puppet.js +181 -1
  6. data/app/assets/javascripts/foreman_puppet/locale/en_GB/foreman_puppet.js +181 -1
  7. data/app/assets/javascripts/foreman_puppet/locale/es/foreman_puppet.js +181 -1
  8. data/app/assets/javascripts/foreman_puppet/locale/fr/foreman_puppet.js +181 -1
  9. data/app/assets/javascripts/foreman_puppet/locale/gl/foreman_puppet.js +181 -1
  10. data/app/assets/javascripts/foreman_puppet/locale/it/foreman_puppet.js +181 -1
  11. data/app/assets/javascripts/foreman_puppet/locale/ja/foreman_puppet.js +181 -1
  12. data/app/assets/javascripts/foreman_puppet/locale/ka/foreman_puppet.js +192 -12
  13. data/app/assets/javascripts/foreman_puppet/locale/ko/foreman_puppet.js +181 -1
  14. data/app/assets/javascripts/foreman_puppet/locale/nl_NL/foreman_puppet.js +181 -1
  15. data/app/assets/javascripts/foreman_puppet/locale/pl/foreman_puppet.js +181 -1
  16. data/app/assets/javascripts/foreman_puppet/locale/pt_BR/foreman_puppet.js +181 -1
  17. data/app/assets/javascripts/foreman_puppet/locale/ru/foreman_puppet.js +181 -1
  18. data/app/assets/javascripts/foreman_puppet/locale/sv_SE/foreman_puppet.js +181 -1
  19. data/app/assets/javascripts/foreman_puppet/locale/zh_CN/foreman_puppet.js +181 -1
  20. data/app/assets/javascripts/foreman_puppet/locale/zh_TW/foreman_puppet.js +181 -1
  21. data/app/controllers/concerns/foreman_puppet/extensions/hosts_controller_extensions.rb +1 -1
  22. data/app/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller.rb +75 -1
  23. data/app/models/foreman_puppet/config_group.rb +3 -1
  24. data/app/models/foreman_puppet/host_config_group.rb +12 -0
  25. data/app/models/foreman_puppet/puppetclass.rb +14 -3
  26. data/app/services/concerns/foreman_puppet/extensions/bulk_hosts_manager.rb +18 -0
  27. data/config/api_routes.rb +1 -0
  28. data/db/seeds.d/111_puppet_proxy_feature.rb +1 -1
  29. data/lib/foreman_puppet/register.rb +1 -0
  30. data/lib/foreman_puppet/version.rb +1 -1
  31. data/locale/ca/LC_MESSAGES/foreman_puppet.mo +0 -0
  32. data/locale/ca/foreman_puppet.po +187 -1
  33. data/locale/cs_CZ/LC_MESSAGES/foreman_puppet.mo +0 -0
  34. data/locale/cs_CZ/foreman_puppet.po +187 -1
  35. data/locale/de/LC_MESSAGES/foreman_puppet.mo +0 -0
  36. data/locale/de/foreman_puppet.po +188 -2
  37. data/locale/en/LC_MESSAGES/foreman_puppet.mo +0 -0
  38. data/locale/en/foreman_puppet.po +187 -1
  39. data/locale/en_GB/LC_MESSAGES/foreman_puppet.mo +0 -0
  40. data/locale/en_GB/foreman_puppet.po +187 -1
  41. data/locale/es/LC_MESSAGES/foreman_puppet.mo +0 -0
  42. data/locale/es/foreman_puppet.po +187 -1
  43. data/locale/foreman_puppet.pot +312 -13
  44. data/locale/fr/LC_MESSAGES/foreman_puppet.mo +0 -0
  45. data/locale/fr/foreman_puppet.po +187 -1
  46. data/locale/gl/LC_MESSAGES/foreman_puppet.mo +0 -0
  47. data/locale/gl/foreman_puppet.po +187 -1
  48. data/locale/it/LC_MESSAGES/foreman_puppet.mo +0 -0
  49. data/locale/it/foreman_puppet.po +187 -1
  50. data/locale/ja/LC_MESSAGES/foreman_puppet.mo +0 -0
  51. data/locale/ja/foreman_puppet.po +187 -1
  52. data/locale/ka/LC_MESSAGES/foreman_puppet.mo +0 -0
  53. data/locale/ka/foreman_puppet.po +199 -13
  54. data/locale/ko/LC_MESSAGES/foreman_puppet.mo +0 -0
  55. data/locale/ko/foreman_puppet.po +187 -1
  56. data/locale/nl_NL/LC_MESSAGES/foreman_puppet.mo +0 -0
  57. data/locale/nl_NL/foreman_puppet.po +187 -1
  58. data/locale/pl/LC_MESSAGES/foreman_puppet.mo +0 -0
  59. data/locale/pl/foreman_puppet.po +187 -1
  60. data/locale/pt_BR/LC_MESSAGES/foreman_puppet.mo +0 -0
  61. data/locale/pt_BR/foreman_puppet.po +187 -1
  62. data/locale/ru/LC_MESSAGES/foreman_puppet.mo +0 -0
  63. data/locale/ru/foreman_puppet.po +187 -1
  64. data/locale/sv_SE/LC_MESSAGES/foreman_puppet.mo +0 -0
  65. data/locale/sv_SE/foreman_puppet.po +187 -1
  66. data/locale/zh_CN/LC_MESSAGES/foreman_puppet.mo +0 -0
  67. data/locale/zh_CN/foreman_puppet.po +187 -1
  68. data/locale/zh_TW/LC_MESSAGES/foreman_puppet.mo +0 -0
  69. data/locale/zh_TW/foreman_puppet.po +187 -1
  70. data/test/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller_test.rb +93 -0
  71. data/test/models/foreman_puppet/host_test.rb +50 -0
  72. data/test/models/foreman_puppet/hostgroup_test.rb +50 -0
  73. data/test/services/foreman_puppet/bulk_hosts_manager_test.rb +45 -0
  74. data/webpack/__mocks__/foremanReact/redux/API/index.js +8 -0
  75. data/webpack/global_index.js +18 -1
  76. data/webpack/src/Extends/Hosts/ActionsBar/index.js +20 -0
  77. data/webpack/src/Extends/Hosts/BulkActions/BulkChangeProxyCommon/__tests__/actions.test.js +0 -7
  78. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/BulkChangePuppetEnvironmentModal.js +239 -0
  79. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/BulkChangePuppetEnvironmentModal.test.js +155 -0
  80. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/actions.test.js +49 -0
  81. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/index.test.js +66 -0
  82. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/actions.js +37 -0
  83. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/index.js +30 -0
  84. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetProxy/__tests__/index.test.js +160 -47
  85. data/webpack/src/Extends/Hosts/BulkActions/BulkRemoveProxyCommon/__tests__/actions.test.js +0 -6
  86. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy/__tests__/index.test.js +136 -39
  87. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/BulkRemovePuppetEnvironmentModal.js +148 -0
  88. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/BulkRemovePuppetEnvironmentModal.test.js +80 -0
  89. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/index.test.js +66 -0
  90. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/index.js +30 -0
  91. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy/__tests__/index.test.js +123 -34
  92. data/webpack/src/Router/routes.fixtures.js +13 -0
  93. data/webpack/src/Router/routes.test.js +68 -8
  94. data/webpack/src/foreman_puppet_host_form.test.js +3 -1
  95. data/webpack/test_setup.js +1 -0
  96. metadata +14 -3
  97. data/webpack/src/Router/__snapshots__/routes.test.js.snap +0 -3
@@ -0,0 +1,239 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { useDispatch, useSelector } from 'react-redux';
5
+ import {
6
+ Modal,
7
+ Button,
8
+ TextContent,
9
+ Text,
10
+ Select,
11
+ SelectOption,
12
+ SelectList,
13
+ MenuToggle,
14
+ } from '@patternfly/react-core';
15
+ import { translate as __ } from 'foremanReact/common/I18n';
16
+ import { addToast } from 'foremanReact/components/ToastsList/slice';
17
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
18
+ import {
19
+ selectAPIStatus,
20
+ selectAPIResponse,
21
+ } from 'foremanReact/redux/API/APISelectors';
22
+ import { STATUS } from 'foremanReact/constants';
23
+ import { bulkActionErrorToastParams } from '../toastHelpers';
24
+ import {
25
+ fetchEnvironments,
26
+ bulkChangePuppetEnvironment,
27
+ PUPPET_ENVIRONMENTS_KEY,
28
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY,
29
+ INHERIT_ENVIRONMENT,
30
+ } from './actions';
31
+
32
+ const BulkChangePuppetEnvironmentModal = ({
33
+ isOpen,
34
+ closeModal,
35
+ selectAllHostsMode,
36
+ selectedCount,
37
+ fetchBulkParams,
38
+ onSuccess: onSuccessCallback,
39
+ }) => {
40
+ const dispatch = useDispatch();
41
+ const [environmentId, setEnvironmentId] = useState(null);
42
+ const [environmentSelectOpen, setEnvironmentSelectOpen] = useState(false);
43
+ const currentOrganization = useForemanOrganization();
44
+
45
+ useEffect(() => {
46
+ dispatch(fetchEnvironments(currentOrganization?.id));
47
+ }, [dispatch, currentOrganization?.id]);
48
+
49
+ const environments = useSelector(state =>
50
+ selectAPIResponse(state, PUPPET_ENVIRONMENTS_KEY)
51
+ );
52
+ const environmentsStatus = useSelector(state =>
53
+ selectAPIStatus(state, PUPPET_ENVIRONMENTS_KEY)
54
+ );
55
+
56
+ const onToggleClick = () => {
57
+ setEnvironmentSelectOpen(!environmentSelectOpen);
58
+ };
59
+
60
+ const handleEnvironmentSelect = (event, selection) => {
61
+ setEnvironmentId(selection);
62
+ setEnvironmentSelectOpen(false);
63
+ };
64
+
65
+ const getEnvironmentLabel = value => {
66
+ if (value === INHERIT_ENVIRONMENT) return __('*Inherit from host group*');
67
+
68
+ const selectedEnvironment = environments?.results?.find(
69
+ environment => `${environment.id}` === value
70
+ );
71
+ return selectedEnvironment?.name || __('Select an Environment');
72
+ };
73
+
74
+ const toggle = toggleRef => (
75
+ <MenuToggle
76
+ ouiaId="bulk-change-env-common-select-toggle"
77
+ ref={toggleRef}
78
+ onClick={onToggleClick}
79
+ isExpanded={environmentSelectOpen}
80
+ style={{ width: '500px' }}
81
+ >
82
+ {environmentId
83
+ ? getEnvironmentLabel(environmentId)
84
+ : __('Select an Environment')}
85
+ </MenuToggle>
86
+ );
87
+
88
+ const handleModalClose = () => {
89
+ setEnvironmentId(null);
90
+ closeModal();
91
+ };
92
+
93
+ const handleError = response => {
94
+ handleModalClose();
95
+ dispatch(
96
+ addToast(
97
+ bulkActionErrorToastParams(
98
+ response,
99
+ __('Failed to change Puppet Environment'),
100
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY
101
+ )
102
+ )
103
+ );
104
+ };
105
+
106
+ const handleSuccess = response => {
107
+ dispatch(
108
+ addToast({
109
+ type: 'success',
110
+ message: response.data.message,
111
+ })
112
+ );
113
+ try {
114
+ if (onSuccessCallback) onSuccessCallback();
115
+ } finally {
116
+ handleModalClose();
117
+ }
118
+ };
119
+
120
+ const handleConfirm = () => {
121
+ const requestBody = {
122
+ included: {
123
+ search: fetchBulkParams(),
124
+ },
125
+ environment_id: environmentId,
126
+ organization_id: currentOrganization?.id,
127
+ };
128
+
129
+ dispatch(
130
+ bulkChangePuppetEnvironment(requestBody, handleSuccess, handleError)
131
+ );
132
+ };
133
+
134
+ const modalActions = [
135
+ <Button
136
+ key="add"
137
+ ouiaId="bulk-change-environment-modal-add-button"
138
+ variant="primary"
139
+ onClick={handleConfirm}
140
+ isDisabled={environmentId === null}
141
+ isLoading={environmentsStatus === STATUS.PENDING}
142
+ >
143
+ {__('Change Puppet Environment')}
144
+ </Button>,
145
+ <Button
146
+ key="cancel"
147
+ ouiaId="bulk-change-environment-modal-cancel-button"
148
+ variant="link"
149
+ onClick={handleModalClose}
150
+ >
151
+ {__('Cancel')}
152
+ </Button>,
153
+ ];
154
+
155
+ return (
156
+ <Modal
157
+ isOpen={isOpen}
158
+ onClose={handleModalClose}
159
+ onEscapePress={handleModalClose}
160
+ title={__('Change Puppet Environment')}
161
+ width="50%"
162
+ position="top"
163
+ actions={modalActions}
164
+ id="bulk-change-puppet-environment"
165
+ key="bulk-change-puppet-environment"
166
+ ouiaId="bulk-change-puppet-environment"
167
+ >
168
+ <TextContent>
169
+ <Text ouiaId="bulk-change-puppet-environment-options">
170
+ {selectAllHostsMode ? (
171
+ <FormattedMessage
172
+ id="bulk-change-puppet-environment-warning-message-all"
173
+ defaultMessage={__(
174
+ 'Changing the Puppet environment will affect {boldCount} selected hosts. Some hosts may already have been associated with the selected environment.'
175
+ )}
176
+ values={{
177
+ boldCount: <strong>{__('All')}</strong>,
178
+ }}
179
+ />
180
+ ) : (
181
+ <FormattedMessage
182
+ id="bulk-change-puppet-environment-warning-message"
183
+ defaultMessage={__(
184
+ 'Changing the Puppet environment will affect {boldCount} selected {count, plural, one {host} other {hosts}}. Some hosts may already have been associated with the selected environment.'
185
+ )}
186
+ values={{
187
+ count: selectedCount,
188
+ boldCount: <strong>{selectedCount}</strong>,
189
+ }}
190
+ />
191
+ )}
192
+ </Text>
193
+ </TextContent>
194
+ {environmentsStatus === STATUS.RESOLVED && (
195
+ <Select
196
+ id="bulk-change-puppet-environment-select"
197
+ isOpen={environmentSelectOpen}
198
+ selected={environmentId}
199
+ onSelect={handleEnvironmentSelect}
200
+ onOpenChange={isSelectOpen => setEnvironmentSelectOpen(isSelectOpen)}
201
+ toggle={toggle}
202
+ shouldFocusToggleOnSelect
203
+ ouiaId="bulk-change-puppet-environment-select"
204
+ >
205
+ <SelectList>
206
+ <SelectOption value={INHERIT_ENVIRONMENT}>
207
+ {__('*Inherit from host group*')}
208
+ </SelectOption>
209
+ {environments?.results?.map(environment => (
210
+ <SelectOption
211
+ key={`${environment.id}`}
212
+ value={`${environment.id}`}
213
+ >
214
+ {environment.name}
215
+ </SelectOption>
216
+ ))}
217
+ </SelectList>
218
+ </Select>
219
+ )}
220
+ </Modal>
221
+ );
222
+ };
223
+
224
+ BulkChangePuppetEnvironmentModal.propTypes = {
225
+ isOpen: PropTypes.bool,
226
+ closeModal: PropTypes.func,
227
+ fetchBulkParams: PropTypes.func.isRequired,
228
+ onSuccess: PropTypes.func,
229
+ selectedCount: PropTypes.number.isRequired,
230
+ selectAllHostsMode: PropTypes.bool.isRequired,
231
+ };
232
+
233
+ BulkChangePuppetEnvironmentModal.defaultProps = {
234
+ isOpen: false,
235
+ closeModal: () => {},
236
+ onSuccess: undefined,
237
+ };
238
+
239
+ export default BulkChangePuppetEnvironmentModal;
@@ -0,0 +1,155 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import { IntlProvider } from 'react-intl';
5
+ import { useDispatch, useSelector } from 'react-redux';
6
+
7
+ import BulkChangePuppetEnvironmentModal from '../BulkChangePuppetEnvironmentModal';
8
+ import { fetchEnvironments, bulkChangePuppetEnvironment } from '../actions';
9
+ import {
10
+ selectAPIResponse,
11
+ selectAPIStatus,
12
+ } from 'foremanReact/redux/API/APISelectors';
13
+
14
+ jest.mock('@patternfly/react-core', () => {
15
+ const React = require('react');
16
+ const actual = jest.requireActual('@patternfly/react-core');
17
+
18
+ const MenuToggle = React.forwardRef(({ children, onClick }, ref) => (
19
+ <button type="button" ref={ref} onClick={onClick}>
20
+ {children}
21
+ </button>
22
+ ));
23
+
24
+ const SelectOption = ({ children, value, onSelect }) => (
25
+ <button type="button" onClick={event => onSelect(event, value)}>
26
+ {children}
27
+ </button>
28
+ );
29
+
30
+ const SelectList = ({ children, onSelect }) => (
31
+ <div>
32
+ {React.Children.map(children, child =>
33
+ React.isValidElement(child)
34
+ ? React.cloneElement(child, { onSelect })
35
+ : child
36
+ )}
37
+ </div>
38
+ );
39
+
40
+ const Select = ({ children, isOpen, toggle, onSelect }) => (
41
+ <div>
42
+ {toggle()}
43
+ {isOpen &&
44
+ React.Children.map(children, child =>
45
+ React.isValidElement(child)
46
+ ? React.cloneElement(child, { onSelect })
47
+ : child
48
+ )}
49
+ </div>
50
+ );
51
+
52
+ return {
53
+ ...actual,
54
+ MenuToggle,
55
+ Select,
56
+ SelectList,
57
+ SelectOption,
58
+ };
59
+ });
60
+
61
+ jest.mock('react-redux', () => ({
62
+ ...jest.requireActual('react-redux'),
63
+ useDispatch: jest.fn(),
64
+ useSelector: jest.fn(),
65
+ }));
66
+
67
+ jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
68
+ useForemanOrganization: jest.fn(() => ({ id: 23 })),
69
+ }));
70
+
71
+ jest.mock('foremanReact/redux/API/APISelectors', () => ({
72
+ selectAPIResponse: jest.fn(),
73
+ selectAPIStatus: jest.fn(),
74
+ }));
75
+
76
+ jest.mock('../actions', () => ({
77
+ fetchEnvironments: jest.fn(() => ({ type: 'FETCH_ENVIRONMENTS' })),
78
+ bulkChangePuppetEnvironment: jest.fn(() => ({
79
+ type: 'BULK_CHANGE_PUPPET_ENVIRONMENT',
80
+ })),
81
+ PUPPET_ENVIRONMENTS_KEY: 'PUPPET_ENVIRONMENTS_KEY',
82
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY: 'BULK_CHANGE_PUPPET_ENVIRONMENT',
83
+ INHERIT_ENVIRONMENT: 'inherit',
84
+ }));
85
+
86
+ describe('BulkChangePuppetEnvironmentModal', () => {
87
+ const dispatch = jest.fn();
88
+ const fetchBulkParams = jest.fn(
89
+ () => 'organization = "Default Organization"'
90
+ );
91
+ const environmentsResponse = {
92
+ results: [{ id: 1, name: 'production' }],
93
+ };
94
+
95
+ const renderComponent = () =>
96
+ render(
97
+ <IntlProvider locale="en">
98
+ <BulkChangePuppetEnvironmentModal
99
+ isOpen
100
+ closeModal={jest.fn()}
101
+ fetchBulkParams={fetchBulkParams}
102
+ selectedCount={2}
103
+ selectAllHostsMode={false}
104
+ />
105
+ </IntlProvider>
106
+ );
107
+
108
+ beforeEach(() => {
109
+ jest.clearAllMocks();
110
+ useDispatch.mockReturnValue(dispatch);
111
+ selectAPIResponse.mockReturnValue(environmentsResponse);
112
+ selectAPIStatus.mockReturnValue('RESOLVED');
113
+ useSelector.mockImplementation(selector => selector({}));
114
+ });
115
+
116
+ it('renders the environment options', () => {
117
+ renderComponent();
118
+
119
+ expect(fetchEnvironments).toHaveBeenCalledWith(23);
120
+ expect(
121
+ screen.getAllByText('Change Puppet Environment')[0]
122
+ ).toBeInTheDocument();
123
+ expect(
124
+ screen.getByRole('button', { name: 'Select an Environment' })
125
+ ).toBeInTheDocument();
126
+ expect(
127
+ screen.getByText(/Changing the Puppet environment will affect/)
128
+ ).toBeInTheDocument();
129
+ });
130
+
131
+ it('submits organization scope with the bulk change request', () => {
132
+ renderComponent();
133
+
134
+ fireEvent.click(
135
+ screen.getByRole('button', { name: 'Select an Environment' })
136
+ );
137
+ expect(screen.getByText('*Inherit from host group*')).toBeInTheDocument();
138
+ fireEvent.click(screen.getByText('production'));
139
+ fireEvent.click(
140
+ screen.getByRole('button', { name: 'Change Puppet Environment' })
141
+ );
142
+
143
+ expect(bulkChangePuppetEnvironment).toHaveBeenCalledWith(
144
+ {
145
+ included: {
146
+ search: 'organization = "Default Organization"',
147
+ },
148
+ environment_id: '1',
149
+ organization_id: 23,
150
+ },
151
+ expect.any(Function),
152
+ expect.any(Function)
153
+ );
154
+ });
155
+ });
@@ -0,0 +1,49 @@
1
+ import { APIActions } from 'foremanReact/redux/API';
2
+ import {
3
+ fetchEnvironments,
4
+ PUPPET_ENVIRONMENTS_KEY,
5
+ bulkChangePuppetEnvironment,
6
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY,
7
+ } from '../actions';
8
+
9
+ jest.mock('foremanReact/redux/API', () => ({
10
+ APIActions: {
11
+ get: jest.fn(),
12
+ put: jest.fn(),
13
+ },
14
+ }));
15
+
16
+ describe('BulkChangePuppetEnvironment actions', () => {
17
+ const environmentsUrl = '/foreman_puppet/api/v2/environments';
18
+ const bulkChangeUrl = '/api/v2/hosts/bulk/change_puppet_environment';
19
+
20
+ beforeEach(() => {
21
+ jest.clearAllMocks();
22
+ });
23
+
24
+ it('fetches environments', () => {
25
+ fetchEnvironments(23);
26
+
27
+ expect(APIActions.get).toHaveBeenCalledWith({
28
+ key: PUPPET_ENVIRONMENTS_KEY,
29
+ url: environmentsUrl,
30
+ params: { per_page: 'all', organization_id: 23 },
31
+ });
32
+ });
33
+
34
+ it('calls bulk change puppet environment endpoint', () => {
35
+ const params = { included: { ids: [1] }, environment_id: '1' };
36
+ const handleSuccess = jest.fn();
37
+ const handleError = jest.fn();
38
+
39
+ bulkChangePuppetEnvironment(params, handleSuccess, handleError);
40
+
41
+ expect(APIActions.put).toHaveBeenCalledWith({
42
+ key: BULK_CHANGE_PUPPET_ENVIRONMENT_KEY,
43
+ url: bulkChangeUrl,
44
+ handleSuccess,
45
+ handleError,
46
+ params,
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+
4
+ import { useBulkModalOpen } from 'foremanReact/common/BulkModalStateHelper';
5
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
6
+
7
+ import BulkChangePuppetEnvironmentScene from '../index';
8
+ import BulkChangePuppetEnvironmentModal from '../BulkChangePuppetEnvironmentModal';
9
+
10
+ jest.mock('foremanReact/common/BulkModalStateHelper', () => ({
11
+ useBulkModalOpen: jest.fn(),
12
+ }));
13
+
14
+ jest.mock('../BulkChangePuppetEnvironmentModal', () => ({
15
+ __esModule: true,
16
+ default: jest.fn(() => null),
17
+ }));
18
+
19
+ describe('BulkChangePuppetEnvironmentScene', () => {
20
+ const fetchBulkParams = jest.fn();
21
+ const refreshTableData = jest.fn();
22
+ const contextValue = {
23
+ selectAllHostsMode: false,
24
+ selectedCount: 2,
25
+ selectedResults: [1, 2],
26
+ fetchBulkParams,
27
+ refreshTableData,
28
+ };
29
+
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ useBulkModalOpen.mockReturnValue({
33
+ isOpen: true,
34
+ close: jest.fn(),
35
+ });
36
+ });
37
+
38
+ it('opens with bulk modal state and passes expected props', () => {
39
+ let component;
40
+ act(() => {
41
+ component = renderer.create(
42
+ <ForemanActionsBarContext.Provider value={contextValue}>
43
+ <BulkChangePuppetEnvironmentScene />
44
+ </ForemanActionsBarContext.Provider>
45
+ );
46
+ });
47
+
48
+ const componentType =
49
+ BulkChangePuppetEnvironmentModal.default ||
50
+ BulkChangePuppetEnvironmentModal;
51
+ const { props } = component.root.findByType(componentType);
52
+
53
+ expect(props).toEqual(
54
+ expect.objectContaining({
55
+ fetchBulkParams,
56
+ selectedCount: 2,
57
+ selectAllHostsMode: false,
58
+ isOpen: true,
59
+ closeModal: expect.any(Function),
60
+ onSuccess: refreshTableData,
61
+ })
62
+ );
63
+
64
+ component.unmount();
65
+ });
66
+ });
@@ -0,0 +1,37 @@
1
+ import { APIActions } from 'foremanReact/redux/API';
2
+ import { foremanUrl } from 'foremanReact/common/helpers';
3
+
4
+ export const PUPPET_ENVIRONMENTS_KEY = 'PUPPET_ENVIRONMENTS_KEY';
5
+ export const BULK_CHANGE_PUPPET_ENVIRONMENT_KEY =
6
+ 'BULK_CHANGE_PUPPET_ENVIRONMENT';
7
+
8
+ export const INHERIT_ENVIRONMENT = 'inherit';
9
+
10
+ export const fetchEnvironments = organizationId => {
11
+ const url = foremanUrl('/foreman_puppet/api/v2/environments');
12
+ return APIActions.get({
13
+ key: PUPPET_ENVIRONMENTS_KEY,
14
+ url,
15
+ params: {
16
+ per_page: 'all',
17
+ ...(organizationId ? { organization_id: organizationId } : {}),
18
+ },
19
+ });
20
+ };
21
+
22
+ export const bulkChangePuppetEnvironment = (
23
+ params,
24
+ handleSuccess,
25
+ handleError
26
+ ) => {
27
+ const url = foremanUrl('/api/v2/hosts/bulk/change_puppet_environment');
28
+ return APIActions.put({
29
+ key: BULK_CHANGE_PUPPET_ENVIRONMENT_KEY,
30
+ url,
31
+ handleSuccess,
32
+ handleError,
33
+ params,
34
+ });
35
+ };
36
+
37
+ export default fetchEnvironments;
@@ -0,0 +1,30 @@
1
+ import React, { useContext } from 'react';
2
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
3
+ import { useBulkModalOpen } from 'foremanReact/common/BulkModalStateHelper';
4
+ import BulkChangePuppetEnvironmentModal from './BulkChangePuppetEnvironmentModal';
5
+
6
+ const BulkChangePuppetEnvironmentScene = () => {
7
+ const {
8
+ selectAllHostsMode,
9
+ selectedCount,
10
+ fetchBulkParams,
11
+ refreshTableData,
12
+ } = useContext(ForemanActionsBarContext);
13
+ const { isOpen, close: closeModal } = useBulkModalOpen(
14
+ 'bulk-change-puppet-environment'
15
+ );
16
+
17
+ return (
18
+ <BulkChangePuppetEnvironmentModal
19
+ fetchBulkParams={fetchBulkParams}
20
+ selectedCount={selectedCount}
21
+ selectAllHostsMode={selectAllHostsMode}
22
+ isOpen={isOpen}
23
+ closeModal={closeModal}
24
+ onSuccess={refreshTableData}
25
+ />
26
+ );
27
+ };
28
+
29
+ export { BulkChangePuppetEnvironmentModal };
30
+ export default BulkChangePuppetEnvironmentScene;