katello 4.8.0.rc1 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/controllers/katello/api/registry/registry_proxies_controller.rb +2 -18
- data/app/controllers/katello/api/v2/alternate_content_sources_controller.rb +7 -5
- data/app/controllers/katello/api/v2/repositories_controller.rb +3 -18
- data/app/helpers/katello/hosts_and_hostgroups_helper.rb +13 -8
- data/app/lib/actions/katello/alternate_content_source/create.rb +3 -1
- data/app/lib/actions/katello/alternate_content_source/update.rb +3 -1
- data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +1 -1
- data/app/lib/actions/pulp3/orchestration/content_view_version/export.rb +11 -11
- data/app/lib/actions/pulp3/orchestration/content_view_version/syncable_export.rb +0 -2
- data/app/lib/actions/pulp3/repository/reclaim_space.rb +1 -1
- data/app/lib/katello/api/v2/error_handling.rb +12 -2
- data/app/lib/katello/concerns/base_template_scope_extensions.rb +7 -3
- data/app/models/katello/alternate_content_source.rb +54 -4
- data/app/models/katello/concerns/host_managed_extensions.rb +14 -0
- data/app/models/katello/glue/provider.rb +1 -1
- data/app/models/katello/host/content_facet.rb +2 -0
- data/app/services/katello/pulp3/content_view_version/export_validation_error.rb +1 -1
- data/app/services/katello/pulp3/content_view_version/export_validator.rb +16 -0
- data/app/views/foreman/smart_proxies/_content_sync.html.erb +1 -1
- data/db/migrate/20230203141353_set_new_acs_verify_ssl_default.rb +5 -0
- data/db/seeds.d/111-upgrade_tasks.rb +2 -1
- data/lib/katello/plugin.rb +0 -12
- data/lib/katello/tasks/upgrades/4.8/regenerate_imported_repository_metadata.rake +33 -0
- data/lib/katello/version.rb +1 -1
- data/webpack/components/Content/{ContentPage.js → GenericContentPage.js} +7 -4
- data/webpack/components/Content/__tests__/ContentTable.test.js +1 -1
- data/webpack/components/Content/__tests__/GenericContentPage.test.js +35 -0
- data/webpack/components/Search/SearchText.js +70 -0
- data/webpack/components/Table/EmptyStateMessage.js +2 -2
- data/webpack/components/Table/TableWrapper.js +4 -0
- data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +10 -72
- data/webpack/components/extensions/HostDetails/HostDetailsConstants.js +0 -1
- data/webpack/components/extensions/HostDetails/HostDetailsSelectors.js +0 -6
- data/webpack/components/extensions/HostDetails/Tabs/__tests__/moduleStreamsTab.test.js +76 -0
- data/webpack/components/extensions/SearchBar/SearchBarConstants.js +3 -0
- data/webpack/components/extensions/SearchBar/SearchBarHooks.js +50 -0
- data/webpack/components/extensions/SearchBar/SearchBarReducer.js +14 -0
- data/webpack/components/extensions/SearchBar/SearchBarSelectors.js +5 -0
- data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -3
- data/webpack/redux/reducers/index.js +2 -2
- data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +1 -13
- data/webpack/scenes/AlternateContentSources/Details/ACSExpandableDetails.js +6 -5
- data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditCredentials.js +1 -0
- data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditDetails.js +3 -2
- data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditProducts.js +1 -0
- data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditSmartProxies.js +2 -0
- data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditURLPaths.js +1 -0
- data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +1 -0
- data/webpack/scenes/Content/{ContentPage.js → GenericContentPage.js} +2 -2
- data/webpack/scenes/Content/__tests__/contentTable.test.js +2 -2
- data/webpack/scenes/Content/index.js +2 -2
- data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +1 -0
- data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js +14 -17
- data/webpack/scenes/ContentViews/Details/Filters/Rules/Package/AddEditPackageRuleModal.js +24 -28
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +11 -18
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +10 -23
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/ContentViewPackageGroupFilter.test.js +0 -2
- data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +1 -7
- data/webpack/scenes/ContentViews/components/ContentViewSelect/ContentViewSelectOption.js +87 -0
- data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +1 -1
- data/webpack/scenes/ContentViews/expansions/__tests__/contentViewComponentsModal.test.js +0 -2
- data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +153 -28
- data/webpack/scenes/Hosts/ChangeContentSource/index.js +14 -15
- data/webpack/scenes/Hosts/ChangeContentSource/selectors.js +4 -0
- data/webpack/scenes/Hosts/ChangeContentSource/styles.scss +4 -0
- data/webpack/scenes/ModuleStreams/ModuleStreamsPage.js +2 -2
- data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamPage.test.js +2 -2
- data/webpack/scenes/ModuleStreams/__tests__/__snapshots__/ModuleStreamPage.test.js.snap +1 -1
- data/webpack/scenes/Settings/SettingsConstants.js +2 -3
- data/webpack/scenes/Settings/SettingsReducer.js +2 -16
- data/webpack/scenes/Settings/SettingsSelectors.js +2 -2
- data/webpack/test-utils/react-testing-lib-wrapper.js +0 -6
- metadata +16 -25
- data/webpack/components/Content/__tests__/ContentPage.test.js +0 -32
- data/webpack/components/Content/__tests__/__snapshots__/ContentPage.test.js.snap +0 -89
- data/webpack/components/Search/Search.js +0 -156
- data/webpack/components/Search/__tests__/search.test.js +0 -104
- data/webpack/components/Search/helpers.js +0 -6
- data/webpack/components/Search/index.js +0 -15
- data/webpack/components/TypeAhead/TypeAhead.js +0 -157
- data/webpack/components/TypeAhead/TypeAhead.scss +0 -7
- data/webpack/components/TypeAhead/helpers/commonPropTypes.js +0 -35
- data/webpack/components/TypeAhead/helpers/helpers.js +0 -32
- data/webpack/components/TypeAhead/index.js +0 -3
- data/webpack/components/TypeAhead/pf3Search/TypeAheadInput.js +0 -44
- data/webpack/components/TypeAhead/pf3Search/TypeAheadItems.js +0 -56
- data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +0 -53
- data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +0 -66
- data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.scss +0 -12
- data/webpack/components/TypeAhead/pf4Search/TypeAheadItems.js +0 -59
- data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +0 -81
@@ -34,6 +34,7 @@ const ACSEditDetails = ({ onClose, acsId, acsDetails }) => {
|
|
34
34
|
isOpen
|
35
35
|
onClose={onClose}
|
36
36
|
appendTo={document.body}
|
37
|
+
ouiaId="acs-edit-details-modal"
|
37
38
|
>
|
38
39
|
<Form onSubmit={(e) => {
|
39
40
|
e.preventDefault();
|
@@ -43,9 +44,9 @@ const ACSEditDetails = ({ onClose, acsId, acsDetails }) => {
|
|
43
44
|
<FormGroup label={__('Name')} isRequired fieldId="acs_name">
|
44
45
|
<TextInput
|
45
46
|
isRequired
|
47
|
+
ouiaId="acs-edit-name-field"
|
46
48
|
type="text"
|
47
|
-
id=
|
48
|
-
ouiaId="acs_name_field"
|
49
|
+
id={`acs-edit-name-field-${acsId}`}
|
49
50
|
name="acs_name_field"
|
50
51
|
aria-label="acs_name_field"
|
51
52
|
value={acsName}
|
@@ -80,6 +80,7 @@ const ACSEditSmartProxies = ({ onClose, acsId, acsDetails }) => {
|
|
80
80
|
isOpen
|
81
81
|
onClose={onClose}
|
82
82
|
appendTo={document.body}
|
83
|
+
ouiaId="acs-edit-smart-proxies-modal"
|
83
84
|
>
|
84
85
|
<Form onSubmit={(e) => {
|
85
86
|
e.preventDefault();
|
@@ -110,6 +111,7 @@ const ACSEditSmartProxies = ({ onClose, acsId, acsDetails }) => {
|
|
110
111
|
<Switch
|
111
112
|
id="use-http-proxies-switch"
|
112
113
|
aria-label="use-http-proxies-switch"
|
114
|
+
ouiaId="use-http-proxies-switch"
|
113
115
|
isChecked={acsUseHttpProxies}
|
114
116
|
onChange={checked => setAcsUseHttpProxies(checked)}
|
115
117
|
/>
|
@@ -12,7 +12,7 @@ import { getContentTypes } from './ContentActions';
|
|
12
12
|
import Loading from '../../components/Loading';
|
13
13
|
import EmptyStateMessage from '../../components/Table/EmptyStateMessage';
|
14
14
|
|
15
|
-
const
|
15
|
+
const GenericContentPage = () => {
|
16
16
|
const dispatch = useDispatch();
|
17
17
|
const contentTypesResponse = useSelector(selectContentTypes);
|
18
18
|
const contentTypesStatus = useSelector(selectContentTypesStatus);
|
@@ -86,4 +86,4 @@ const ContentPage = () => {
|
|
86
86
|
);
|
87
87
|
};
|
88
88
|
|
89
|
-
export default
|
89
|
+
export default GenericContentPage;
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
|
3
3
|
import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../test-utils/nockWrapper';
|
4
4
|
import api from '../../../services/api';
|
5
|
-
import
|
5
|
+
import GenericContentPage from '../GenericContentPage';
|
6
6
|
import ansibleCollectionsResponse from './ansibleCollections.fixtures';
|
7
7
|
import contentTypesResponse from './contentTypes.fixtures.json';
|
8
8
|
import pythonPackagesResponse from './pythonPackages.fixtures.json';
|
@@ -29,7 +29,7 @@ test('Can call API for Python Packages and show table on page load', async (done
|
|
29
29
|
.reply(200, contentTypesResponse);
|
30
30
|
|
31
31
|
const { queryByText, getAllByText } =
|
32
|
-
renderWithRedux(<
|
32
|
+
renderWithRedux(<GenericContentPage />);
|
33
33
|
|
34
34
|
expect(queryByText(firstPackage.name)).toBeNull();
|
35
35
|
await patientlyWaitFor(() => {
|
@@ -199,6 +199,7 @@ export default () => {
|
|
199
199
|
<FlexItem>
|
200
200
|
<Dropdown
|
201
201
|
position={DropdownPosition.right}
|
202
|
+
ouiaId="cv-details-actions"
|
202
203
|
style={{ marginLeft: 'auto' }}
|
203
204
|
toggle={<KebabToggle onToggle={setDropdownOpen} id="toggle-dropdown" />}
|
204
205
|
isOpen={dropDownOpen}
|
data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js
CHANGED
@@ -5,7 +5,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
import { Modal, ModalVariant, Form, FormGroup, ActionGroup, Button } from '@patternfly/react-core';
|
6
6
|
import { addCVFilterRule, editCVFilterRule, getCVFilterRules } from '../../../ContentViewDetailActions';
|
7
7
|
import { orgId } from '../../../../../../services/api';
|
8
|
-
import
|
8
|
+
import SearchText from '../../../../../../components/Search/SearchText';
|
9
9
|
|
10
10
|
const AddEditContainerTagRuleModal = ({
|
11
11
|
onClose, filterId, selectedFilterRuleData, repositoryIds,
|
@@ -16,7 +16,7 @@ const AddEditContainerTagRuleModal = ({
|
|
16
16
|
const [saving, setSaving] = useState(false);
|
17
17
|
const isEditing = name && id;
|
18
18
|
|
19
|
-
const autoCompleteEndpoint = '/docker_tags/auto_complete_name';
|
19
|
+
const autoCompleteEndpoint = '/katello/api/v2/docker_tags/auto_complete_name';
|
20
20
|
|
21
21
|
const onSubmit = () => {
|
22
22
|
setSaving(true);
|
@@ -36,13 +36,10 @@ const AddEditContainerTagRuleModal = ({
|
|
36
36
|
onClose();
|
37
37
|
};
|
38
38
|
|
39
|
-
const
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
term,
|
44
|
-
repoids: repositoryIds,
|
45
|
-
},
|
39
|
+
const searchDataProp = term => ({
|
40
|
+
organization_id: orgId(),
|
41
|
+
term,
|
42
|
+
repoids: repositoryIds,
|
46
43
|
});
|
47
44
|
|
48
45
|
return (
|
@@ -59,14 +56,14 @@ const AddEditContainerTagRuleModal = ({
|
|
59
56
|
}}
|
60
57
|
>
|
61
58
|
<FormGroup label={__('Tag name')} isRequired fieldId="tag_name">
|
62
|
-
<
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
<SearchText
|
60
|
+
data={{
|
61
|
+
autocomplete: {
|
62
|
+
url: autoCompleteEndpoint,
|
63
|
+
apiParams: tag => searchDataProp(tag),
|
64
|
+
},
|
65
|
+
}}
|
66
|
+
onSearchChange={setTagName}
|
70
67
|
/>
|
71
68
|
</FormGroup>
|
72
69
|
<ActionGroup>
|
@@ -13,7 +13,7 @@ import {
|
|
13
13
|
selectCreateFilterRuleStatus,
|
14
14
|
} from '../../../ContentViewDetailSelectors';
|
15
15
|
import { orgId } from '../../../../../../services/api';
|
16
|
-
import
|
16
|
+
import SearchText from '../../../../../../components/Search/SearchText';
|
17
17
|
|
18
18
|
const AddEditPackageRuleModal = ({
|
19
19
|
filterId, onClose, selectedFilterRuleData, repositoryIds,
|
@@ -27,8 +27,8 @@ const AddEditPackageRuleModal = ({
|
|
27
27
|
max_version: editingMaxVersion,
|
28
28
|
} = selectedFilterRuleData || {};
|
29
29
|
|
30
|
-
const architectureAutoCompleteEndpoint = '/packages/auto_complete_arch';
|
31
|
-
const nameAutoCompleteEndpoint = '/packages/auto_complete_name';
|
30
|
+
const architectureAutoCompleteEndpoint = '/katello/api/v2/packages/auto_complete_arch';
|
31
|
+
const nameAutoCompleteEndpoint = '/katello/api/v2/packages/auto_complete_name';
|
32
32
|
|
33
33
|
const isEditing = !!selectedFilterRuleData;
|
34
34
|
|
@@ -118,14 +118,11 @@ const AddEditPackageRuleModal = ({
|
|
118
118
|
}
|
119
119
|
}, [status, setSaving]);
|
120
120
|
|
121
|
-
const
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
repoids: repositoryIds,
|
127
|
-
non_modular: true,
|
128
|
-
},
|
121
|
+
const searchDataProp = term => ({
|
122
|
+
organization_id: orgId(),
|
123
|
+
term,
|
124
|
+
repoids: repositoryIds,
|
125
|
+
non_modular: true,
|
129
126
|
});
|
130
127
|
|
131
128
|
return (
|
@@ -142,26 +139,25 @@ const AddEditPackageRuleModal = ({
|
|
142
139
|
}}
|
143
140
|
>
|
144
141
|
<FormGroup label={__('RPM name')} isRequired fieldId="name">
|
145
|
-
<
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
142
|
+
<SearchText
|
143
|
+
data={{
|
144
|
+
autocomplete: {
|
145
|
+
url: nameAutoCompleteEndpoint,
|
146
|
+
apiParams: input => searchDataProp(input),
|
147
|
+
},
|
148
|
+
}}
|
149
|
+
onSearchChange={setName}
|
153
150
|
/>
|
154
151
|
</FormGroup>
|
155
152
|
<FormGroup label={__('Architecture')} fieldId="architecture">
|
156
|
-
<
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
setTextInputValue={setArchitecture}
|
153
|
+
<SearchText
|
154
|
+
data={{
|
155
|
+
autocomplete: {
|
156
|
+
url: architectureAutoCompleteEndpoint,
|
157
|
+
apiParams: arch => searchDataProp(arch),
|
158
|
+
},
|
159
|
+
}}
|
160
|
+
onSearchChange={setArchitecture}
|
165
161
|
/>
|
166
162
|
</FormGroup>
|
167
163
|
<FormGroup label={__('Version')} fieldId="version_comparator">
|
data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js
CHANGED
@@ -7,7 +7,6 @@ import {
|
|
7
7
|
nockInstance,
|
8
8
|
assertNockRequest,
|
9
9
|
mockAutocomplete,
|
10
|
-
mockSetting,
|
11
10
|
} from '../../../../../test-utils/nockWrapper';
|
12
11
|
import api from '../../../../../services/api';
|
13
12
|
import CVContainerImageFilterContent from '../CVContainerImageFilterContent';
|
@@ -140,8 +139,6 @@ test('Can add filter rules', async (done) => {
|
|
140
139
|
2,
|
141
140
|
);
|
142
141
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
143
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
144
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
145
142
|
|
146
143
|
const cvFiltersScope = nockInstance
|
147
144
|
.get(cvFilterRulesPath)
|
@@ -158,7 +155,7 @@ test('Can add filter rules', async (done) => {
|
|
158
155
|
.query(true)
|
159
156
|
.reply(200, { ...cvFilterFixtures, results: [...cvFilterFixtures.results, addedRule] });
|
160
157
|
|
161
|
-
const { queryByText, getByLabelText } =
|
158
|
+
const { queryByText, getByLabelText, getAllByLabelText } =
|
162
159
|
renderWithRedux(
|
163
160
|
withCVRoute(<CVContainerImageFilterContent filterId={195} details={details} />),
|
164
161
|
renderOptions,
|
@@ -177,7 +174,9 @@ test('Can add filter rules', async (done) => {
|
|
177
174
|
expect(getByLabelText('add_edit_filter_rule')).toHaveAttribute('aria-disabled', 'true');
|
178
175
|
});
|
179
176
|
|
180
|
-
|
177
|
+
const searchInput = getAllByLabelText('Search input')[1];
|
178
|
+
searchInput.focus();
|
179
|
+
fireEvent.change(searchInput, { target: { value: 'new-rule' } });
|
181
180
|
fireEvent.submit(getByLabelText('add_edit_filter_rule'));
|
182
181
|
|
183
182
|
await patientlyWaitFor(() => {
|
@@ -185,8 +184,6 @@ test('Can add filter rules', async (done) => {
|
|
185
184
|
});
|
186
185
|
|
187
186
|
assertNockRequest(autocompleteScope);
|
188
|
-
assertNockRequest(searchDelayScope);
|
189
|
-
assertNockRequest(autoSearchScope);
|
190
187
|
assertNockRequest(cvFiltersScope);
|
191
188
|
assertNockRequest(cvFilterAddScope);
|
192
189
|
assertNockRequest(autocompleteNameScope);
|
@@ -205,8 +202,6 @@ test('Can edit filter rules', async (done) => {
|
|
205
202
|
2,
|
206
203
|
);
|
207
204
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
208
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
209
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
210
205
|
|
211
206
|
const cvFiltersScope = nockInstance
|
212
207
|
.get(cvFilterRulesPath)
|
@@ -231,7 +226,9 @@ test('Can edit filter rules', async (done) => {
|
|
231
226
|
}),
|
232
227
|
});
|
233
228
|
|
234
|
-
const {
|
229
|
+
const {
|
230
|
+
queryByText, getAllByLabelText, getByLabelText,
|
231
|
+
} =
|
235
232
|
renderWithRedux(
|
236
233
|
withCVRoute(<CVContainerImageFilterContent filterId={195} details={details} />),
|
237
234
|
renderOptions,
|
@@ -258,7 +255,9 @@ test('Can edit filter rules', async (done) => {
|
|
258
255
|
expect(getByLabelText('add_edit_filter_rule')).toHaveAttribute('aria-disabled', 'false');
|
259
256
|
});
|
260
257
|
|
261
|
-
|
258
|
+
const searchInput = getAllByLabelText('Search input')[1];
|
259
|
+
searchInput.focus();
|
260
|
+
fireEvent.change(searchInput, { target: { value: 'changed-name' } });
|
262
261
|
fireEvent.submit(getByLabelText('add_edit_filter_rule'));
|
263
262
|
|
264
263
|
await patientlyWaitFor(() => {
|
@@ -266,8 +265,6 @@ test('Can edit filter rules', async (done) => {
|
|
266
265
|
});
|
267
266
|
|
268
267
|
assertNockRequest(autocompleteScope);
|
269
|
-
assertNockRequest(searchDelayScope);
|
270
|
-
assertNockRequest(autoSearchScope);
|
271
268
|
assertNockRequest(cvFiltersScope);
|
272
269
|
assertNockRequest(cvFilterAddScope);
|
273
270
|
assertNockRequest(autocompleteNameScope);
|
@@ -284,8 +281,6 @@ test('Shows call-to-action when there are no filter rules', async (done) => {
|
|
284
281
|
2,
|
285
282
|
);
|
286
283
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
287
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
288
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
289
284
|
const cvFiltersScope = nockInstance
|
290
285
|
.get(cvFilterRulesPath)
|
291
286
|
.times(2)
|
@@ -302,13 +297,11 @@ test('Shows call-to-action when there are no filter rules', async (done) => {
|
|
302
297
|
await patientlyWaitFor(() => expect(queryByLabelText('add_filter_rule_empty_state')).toBeInTheDocument());
|
303
298
|
fireEvent.click(queryByLabelText('add_filter_rule_empty_state'));
|
304
299
|
await patientlyWaitFor(() => {
|
305
|
-
expect(getAllByLabelText('
|
300
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
306
301
|
});
|
307
302
|
|
308
303
|
assertNockRequest(autocompleteScope);
|
309
304
|
assertNockRequest(autocompleteNameScope);
|
310
|
-
assertNockRequest(searchDelayScope);
|
311
|
-
assertNockRequest(autoSearchScope);
|
312
305
|
assertNockRequest(cvFiltersScope, done);
|
313
306
|
act(done);
|
314
307
|
});
|
@@ -8,7 +8,6 @@ import {
|
|
8
8
|
nockInstance,
|
9
9
|
assertNockRequest,
|
10
10
|
mockAutocomplete,
|
11
|
-
mockSetting,
|
12
11
|
} from '../../../../../test-utils/nockWrapper';
|
13
12
|
import api from '../../../../../services/api';
|
14
13
|
import cvFilterDetails from './cvPackageFilterDetail.fixtures.json';
|
@@ -163,8 +162,6 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
163
162
|
nockInstance, autocompleteArchUrl, true,
|
164
163
|
undefined, 2,
|
165
164
|
);
|
166
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
167
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
168
165
|
|
169
166
|
const cvFiltersScope = nockInstance
|
170
167
|
.get(cvFiltersPath)
|
@@ -214,20 +211,22 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
214
211
|
});
|
215
212
|
getByLabelText('add_rpm_rule').click();
|
216
213
|
await patientlyWaitFor(() => {
|
217
|
-
expect(getAllByLabelText('
|
218
|
-
expect(getAllByLabelText('
|
214
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
215
|
+
expect(getAllByLabelText('Search input')[1]).toBeInTheDocument();
|
219
216
|
expect(getByLabelText('add_package_filter_rule')).toBeInTheDocument();
|
220
217
|
});
|
221
|
-
|
222
|
-
|
218
|
+
const nameSearchInput = getAllByLabelText('Search input')[1];
|
219
|
+
const archSearchInput = getAllByLabelText('Search input')[2];
|
220
|
+
nameSearchInput.focus();
|
221
|
+
fireEvent.change(nameSearchInput, { target: { value: 'elephant' } });
|
222
|
+
archSearchInput.focus();
|
223
|
+
fireEvent.change(archSearchInput, { target: { value: 'noarch' } });
|
223
224
|
fireEvent.submit(getByLabelText('add_package_filter_rule'));
|
224
225
|
|
225
226
|
await patientlyWaitFor(() => {
|
226
227
|
expect(queryByText('Add rule')).not.toBeInTheDocument();
|
227
228
|
});
|
228
229
|
assertNockRequest(autocompleteScope);
|
229
|
-
assertNockRequest(searchDelayScope);
|
230
|
-
assertNockRequest(autoSearchScope);
|
231
230
|
assertNockRequest(autocompleteNameScope);
|
232
231
|
assertNockRequest(autocompleteArchScope);
|
233
232
|
assertNockRequest(cvFiltersScope);
|
@@ -241,8 +240,6 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
241
240
|
test('Remove rpm filter rule in a self-closing modal', async (done) => {
|
242
241
|
const { name: cvFilterName } = cvFilterDetails;
|
243
242
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
|
244
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
245
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
246
243
|
|
247
244
|
const cvFiltersScope = nockInstance
|
248
245
|
.get(cvFiltersPath)
|
@@ -289,8 +286,6 @@ test('Remove rpm filter rule in a self-closing modal', async (done) => {
|
|
289
286
|
});
|
290
287
|
|
291
288
|
assertNockRequest(autocompleteScope);
|
292
|
-
assertNockRequest(searchDelayScope);
|
293
|
-
assertNockRequest(autoSearchScope);
|
294
289
|
assertNockRequest(cvFiltersScope);
|
295
290
|
assertNockRequest(cvFilterDetailsScope);
|
296
291
|
assertNockRequest(cvPackageFilterRulesScope);
|
@@ -310,8 +305,6 @@ test('Edit rpm filter rule in a self-closing modal', async (done) => {
|
|
310
305
|
nockInstance, autocompleteArchUrl, true,
|
311
306
|
undefined, 2,
|
312
307
|
);
|
313
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
314
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
315
308
|
const cvFiltersScope = nockInstance
|
316
309
|
.get(cvFiltersPath)
|
317
310
|
.times(2)
|
@@ -366,8 +359,6 @@ test('Edit rpm filter rule in a self-closing modal', async (done) => {
|
|
366
359
|
});
|
367
360
|
|
368
361
|
assertNockRequest(autocompleteScope);
|
369
|
-
assertNockRequest(searchDelayScope);
|
370
|
-
assertNockRequest(autoSearchScope);
|
371
362
|
assertNockRequest(autocompleteNameScope);
|
372
363
|
assertNockRequest(autocompleteArchScope);
|
373
364
|
assertNockRequest(cvFiltersScope);
|
@@ -381,8 +372,6 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
381
372
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
|
382
373
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl);
|
383
374
|
const autocompleteArchScope = mockAutocomplete(nockInstance, autocompleteArchUrl);
|
384
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
385
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
386
375
|
const cvFilterDetailScope = nockInstance
|
387
376
|
.get(cvFilterDetailsPath)
|
388
377
|
.query(true)
|
@@ -397,7 +386,7 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
397
386
|
.query(true)
|
398
387
|
.reply(200, emptyCVPackageFilterRules);
|
399
388
|
const {
|
400
|
-
queryByLabelText,
|
389
|
+
queryByLabelText, queryByText, getAllByLabelText,
|
401
390
|
} =
|
402
391
|
renderWithRedux(withCVRoute(<ContentViewFilterDetails
|
403
392
|
cvId={1}
|
@@ -408,7 +397,7 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
408
397
|
fireEvent.click(queryByLabelText('add_rpm_rule_empty_state'));
|
409
398
|
|
410
399
|
await patientlyWaitFor(() => {
|
411
|
-
expect(getAllByLabelText('
|
400
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
412
401
|
expect(queryByText('Cancel')).toBeInTheDocument();
|
413
402
|
});
|
414
403
|
fireEvent.click(queryByText('Cancel'));
|
@@ -418,8 +407,6 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
418
407
|
assertNockRequest(autocompleteNameScope);
|
419
408
|
assertNockRequest(autocompleteArchScope);
|
420
409
|
assertNockRequest(autocompleteScope);
|
421
|
-
assertNockRequest(searchDelayScope);
|
422
|
-
assertNockRequest(autoSearchScope);
|
423
410
|
assertNockRequest(cvFiltersScope);
|
424
411
|
assertNockRequest(cvFilterDetailScope);
|
425
412
|
assertNockRequest(cvPackageFilterRulesScope);
|
data/webpack/scenes/ContentViews/Details/Filters/__tests__/ContentViewPackageGroupFilter.test.js
CHANGED
@@ -46,8 +46,6 @@ const renderOptions = {
|
|
46
46
|
|
47
47
|
const withCVRoute = component => <Route path="/content_views/:id([0-9]+)#/filters/:filterId([0-9]+)">{component}</Route>;
|
48
48
|
|
49
|
-
jest.mock('../../../../../components/Search', () => () => 'mocked!');
|
50
|
-
|
51
49
|
test('Can enable and disable add filter button', async (done) => {
|
52
50
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
|
53
51
|
const { name: cvFilterName } = cvFilterDetails;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { act, renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
|
3
3
|
import { Route } from 'react-router-dom';
|
4
|
-
import { nockInstance, assertNockRequest, mockAutocomplete
|
4
|
+
import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../../../test-utils/nockWrapper';
|
5
5
|
import api from '../../../../../services/api';
|
6
6
|
import CONTENT_VIEWS_KEY from '../../../ContentViewsConstants';
|
7
7
|
import ContentViewVersions from '../ContentViewVersions';
|
@@ -36,15 +36,11 @@ const autocompleteUrl = '/content_view_versions/auto_complete_search';
|
|
36
36
|
const taskPollingUrl = '/foreman_tasks/api/tasks/6b900ff8-62bb-42ac-8c45-da86b7258520';
|
37
37
|
|
38
38
|
let firstVersion;
|
39
|
-
let searchDelayScope;
|
40
|
-
let autoSearchScope;
|
41
39
|
let envScope;
|
42
40
|
|
43
41
|
beforeEach(() => {
|
44
42
|
const { results } = cvVersionsData;
|
45
43
|
[firstVersion] = results;
|
46
|
-
searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
47
|
-
autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
48
44
|
envScope = nockInstance
|
49
45
|
.get(environmentPathsPath)
|
50
46
|
.query(true)
|
@@ -53,8 +49,6 @@ beforeEach(() => {
|
|
53
49
|
|
54
50
|
afterEach(() => {
|
55
51
|
assertNockRequest(envScope);
|
56
|
-
assertNockRequest(searchDelayScope);
|
57
|
-
assertNockRequest(autoSearchScope);
|
58
52
|
});
|
59
53
|
|
60
54
|
test('Can call API and show versions on page load', async (done) => {
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { Flex, SelectOption } from '@patternfly/react-core';
|
4
|
+
import { FormattedMessage } from 'react-intl';
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
import {
|
7
|
+
global_palette_black_600 as pfDescriptionColor,
|
8
|
+
} from '@patternfly/react-tokens';
|
9
|
+
import ContentViewIcon from '../../../../scenes/ContentViews/components/ContentViewIcon';
|
10
|
+
import { uniq } from '../../../../utils/helpers';
|
11
|
+
|
12
|
+
export const ContentViewDescription = ({ cv, versionNumber }) => {
|
13
|
+
const descriptionStyle = {
|
14
|
+
fontSize: '12px',
|
15
|
+
fontWeight: 400,
|
16
|
+
color: pfDescriptionColor.value,
|
17
|
+
};
|
18
|
+
if (cv.default) return <span style={descriptionStyle}>{__('Library')}</span>;
|
19
|
+
return (
|
20
|
+
<span style={descriptionStyle}>
|
21
|
+
<FormattedMessage
|
22
|
+
id={`content-view-${cv.id}-version-${cv.latest_version}`}
|
23
|
+
defaultMessage="Version {versionNumber}"
|
24
|
+
values={{ versionNumber }}
|
25
|
+
/>
|
26
|
+
</span>
|
27
|
+
);
|
28
|
+
};
|
29
|
+
|
30
|
+
ContentViewDescription.propTypes = {
|
31
|
+
cv: PropTypes.shape({
|
32
|
+
default: PropTypes.bool.isRequired,
|
33
|
+
id: PropTypes.number.isRequired,
|
34
|
+
latest_version: PropTypes.string.isRequired,
|
35
|
+
}).isRequired,
|
36
|
+
versionNumber: PropTypes.string.isRequired,
|
37
|
+
};
|
38
|
+
|
39
|
+
export const relevantVersionObjFromCv = (cv, env) => { // returns the entire version object
|
40
|
+
const versions = cv.versions.filter(version => new Set(version.environment_ids).has(env.id));
|
41
|
+
return uniq(versions)?.[0];
|
42
|
+
};
|
43
|
+
|
44
|
+
export const relevantVersionFromCv = (cv, env) =>
|
45
|
+
relevantVersionObjFromCv(cv, env)?.version; // returns the version text e.g. "1.0"
|
46
|
+
|
47
|
+
const ContentViewSelectOption = ({ cv, env }) => (
|
48
|
+
<SelectOption
|
49
|
+
key={cv.id}
|
50
|
+
value={`${cv.name}`}
|
51
|
+
>
|
52
|
+
<Flex
|
53
|
+
direction={{ default: 'row', sm: 'row' }}
|
54
|
+
flexWrap={{ default: 'nowrap' }}
|
55
|
+
alignItems={{ default: 'alignItemsCenter', sm: 'alignItemsCenter' }}
|
56
|
+
>
|
57
|
+
<ContentViewIcon
|
58
|
+
composite={cv.composite}
|
59
|
+
size="sm"
|
60
|
+
/>
|
61
|
+
<Flex
|
62
|
+
direction={{ default: 'column', sm: 'column' }}
|
63
|
+
flexWrap={{ default: 'nowrap' }}
|
64
|
+
alignItems={{ default: 'alignItemsFlexStart', sm: 'alignItemsFlexStart' }}
|
65
|
+
>
|
66
|
+
{cv.name}
|
67
|
+
<ContentViewDescription
|
68
|
+
cv={cv}
|
69
|
+
versionNumber={relevantVersionFromCv(cv, env)}
|
70
|
+
/>
|
71
|
+
</Flex>
|
72
|
+
</Flex>
|
73
|
+
</SelectOption>
|
74
|
+
);
|
75
|
+
|
76
|
+
ContentViewSelectOption.propTypes = {
|
77
|
+
cv: PropTypes.shape({
|
78
|
+
id: PropTypes.number.isRequired,
|
79
|
+
name: PropTypes.string.isRequired,
|
80
|
+
composite: PropTypes.bool.isRequired,
|
81
|
+
}).isRequired,
|
82
|
+
env: PropTypes.shape({
|
83
|
+
id: PropTypes.number.isRequired,
|
84
|
+
}).isRequired,
|
85
|
+
};
|
86
|
+
|
87
|
+
export default ContentViewSelectOption;
|
@@ -47,7 +47,7 @@ const EnvironmentPaths = ({
|
|
47
47
|
return (
|
48
48
|
<div className="env-path" key={index}>
|
49
49
|
{index === 0 && <hr />}
|
50
|
-
<FormGroup key={`fg-${index}`} isInline fieldId="environment-checkbox-group">
|
50
|
+
<FormGroup key={`fg-${index}`} isInline fieldId="environment-checkbox-group" style={{ display: 'block' }}>
|
51
51
|
{environments.map(env =>
|
52
52
|
(<CheckboxOrRadio
|
53
53
|
isChecked={(publishing && env.library) ||
|
@@ -9,8 +9,6 @@ import RelatedCompositeContentViewsModal from '../RelatedCompositeContentViewsMo
|
|
9
9
|
|
10
10
|
import contentViewComponentsResponse from './contentViewComponentsResponse.fixtures.json';
|
11
11
|
|
12
|
-
jest.mock('../../../../components/Search', () => () => 'Mocked!');
|
13
|
-
|
14
12
|
test('Can call API and show Related Content Views Components Modal', async (done) => {
|
15
13
|
const cvId = 5;
|
16
14
|
const relatedCvCount = 2;
|