katello 4.7.0 → 4.7.1

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.

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/alternate_content_sources_controller.rb +4 -1
  3. data/app/controllers/katello/concerns/api/v2/registration_controller_extensions.rb +0 -1
  4. data/app/lib/katello/util/candlepin_repository_checker.rb +2 -0
  5. data/app/models/katello/concerns/host_managed_extensions.rb +4 -2
  6. data/app/models/katello/concerns/smart_proxy_extensions.rb +1 -1
  7. data/app/models/katello/content.rb +1 -1
  8. data/app/models/katello/glue/provider.rb +1 -1
  9. data/app/services/katello/product_content_importer.rb +61 -5
  10. data/lib/katello/engine.rb +1 -0
  11. data/lib/katello/version.rb +1 -1
  12. data/locale/action_names.rb +69 -69
  13. data/locale/bn/katello.po +23 -20
  14. data/locale/cs/katello.po +23 -20
  15. data/locale/de/katello.po +25 -22
  16. data/locale/en/katello.po +23 -20
  17. data/locale/es/katello.po +335 -332
  18. data/locale/fr/katello.po +704 -695
  19. data/locale/gu/katello.po +23 -20
  20. data/locale/hi/katello.po +23 -20
  21. data/locale/it/katello.po +23 -20
  22. data/locale/ja/katello.po +570 -561
  23. data/locale/ka/katello.po +2269 -2260
  24. data/locale/katello.pot +287 -279
  25. data/locale/kn/katello.po +23 -20
  26. data/locale/ko/katello.po +57 -53
  27. data/locale/mr/katello.po +23 -20
  28. data/locale/or/katello.po +23 -20
  29. data/locale/pa/katello.po +23 -20
  30. data/locale/pt/katello.po +23 -20
  31. data/locale/pt_BR/katello.po +441 -438
  32. data/locale/ru/katello.po +23 -20
  33. data/locale/ta/katello.po +23 -20
  34. data/locale/te/katello.po +23 -20
  35. data/locale/zh_CN/katello.po +694 -687
  36. data/locale/zh_TW/katello.po +23 -20
  37. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +5 -11
  38. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/changeHostCVModal.test.js +2 -2
  39. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +1 -1
  40. data/webpack/components/extensions/HostDetails/DetailsTabCards/SystemPropertiesCardExtensions.js +58 -1
  41. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +5 -1
  42. data/webpack/global_index.js +2 -0
  43. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReassignActivationKeysForm.js +10 -10
  44. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReassignHostsForm.js +10 -10
  45. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +5 -5
  46. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignActivationKeys.js +9 -10
  47. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignHosts.js +13 -10
  48. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignActivationKeysForm.js +18 -18
  49. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignHostsForm.js +10 -6
  50. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvVersionRemove.test.js +6 -6
  51. data/webpack/scenes/ContentViews/components/ContentViewSelect/ContentViewSelect.js +40 -0
  52. data/webpack/scenes/Hosts/ChangeContentSource/actions.js +0 -1
  53. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +16 -2
  54. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceTemplate.js +13 -17
  55. data/webpack/scenes/Hosts/ChangeContentSource/index.js +79 -39
  56. data/webpack/scenes/Hosts/ChangeContentSource/styles.scss +6 -2
  57. metadata +3 -2
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useContext } from 'react';
2
2
  import { useDispatch, useSelector } from 'react-redux';
3
3
  import useDeepCompareEffect from 'use-deep-compare-effect';
4
- import { ExpandableSection, Select, SelectOption } from '@patternfly/react-core';
4
+ import { ExpandableSection, SelectOption } from '@patternfly/react-core';
5
5
  import { STATUS } from 'foremanReact/constants';
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
7
  import EnvironmentPaths from '../../../../components/EnvironmentPaths/EnvironmentPaths';
@@ -9,6 +9,7 @@ import getContentViews from '../../../../ContentViewsActions';
9
9
  import { selectContentViewError, selectContentViews, selectContentViewStatus } from '../../../../ContentViewSelectors';
10
10
  import AffectedHosts from '../affectedHosts';
11
11
  import DeleteContext from '../DeleteContext';
12
+ import ContentViewSelect from '../../../../components/ContentViewSelect/ContentViewSelect';
12
13
 
13
14
  const CVReassignHostsForm = () => {
14
15
  const dispatch = useDispatch();
@@ -74,6 +75,11 @@ const CVReassignHostsForm = () => {
74
75
  return results.filter(cv => cv.id === id)[0]?.name;
75
76
  };
76
77
 
78
+ const onClear = () => {
79
+ setSelectedCVForHosts(null);
80
+ setSelectedCVNameForHosts(null);
81
+ };
82
+
77
83
  const onSelect = (event, selection) => {
78
84
  setSelectedCVForHosts(selection);
79
85
  setSelectedCVNameForHosts(fetchSelectedCVName(selection));
@@ -90,9 +96,8 @@ const CVReassignHostsForm = () => {
90
96
  multiSelect={false}
91
97
  />
92
98
  {selectedEnvForHost.length > 0 &&
93
- <div style={{ marginTop: '1em' }}>
94
- <h3>{__('Select content view')}</h3>
95
- <Select
99
+ <ContentViewSelect
100
+ onClear={onClear}
96
101
  selections={selectedCVForHosts}
97
102
  onSelect={onSelect}
98
103
  isOpen={cvSelectOpen}
@@ -105,8 +110,7 @@ const CVReassignHostsForm = () => {
105
110
  placeholderText={(cvSelectOptions.length === 0) ? __('No content views available') : __('Select a content view')}
106
111
  >
107
112
  {cvSelectOptions}
108
- </Select>
109
- </div>
113
+ </ContentViewSelect>
110
114
  }
111
115
  <ExpandableSection
112
116
  toggleText={showHosts ? 'Hide hosts' : 'Show hosts'}
@@ -160,7 +160,7 @@ test('Can open Remove wizard and remove version from environment with hosts', as
160
160
 
161
161
 
162
162
  const {
163
- getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText,
163
+ getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText, getByPlaceholderText,
164
164
  } = renderWithRedux(
165
165
  <ContentViewVersions cvId={2} details={cvDetailData} />,
166
166
  renderOptions,
@@ -190,9 +190,9 @@ test('Can open Remove wizard and remove version from environment with hosts', as
190
190
  fireEvent.click(getByLabelText('test1'));
191
191
  await patientlyWaitFor(() => {
192
192
  expect(getByText('Select content view')).toBeInTheDocument();
193
- expect(getByText('Select a content view')).toBeInTheDocument();
193
+ expect(getByPlaceholderText('Select a content view')).toBeInTheDocument();
194
194
  });
195
- fireEvent.click(getByText('Select a content view'));
195
+ fireEvent.click(getByPlaceholderText('Select a content view'));
196
196
  await patientlyWaitFor(() => {
197
197
  expect(getByText('cv2')).toBeInTheDocument();
198
198
  });
@@ -250,7 +250,7 @@ test('Can open Remove wizard and remove version from environment with activation
250
250
 
251
251
 
252
252
  const {
253
- getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText,
253
+ getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText, getByPlaceholderText,
254
254
  } = renderWithRedux(
255
255
  <ContentViewVersions cvId={2} details={cvDetailData} />,
256
256
  renderOptions,
@@ -280,9 +280,9 @@ test('Can open Remove wizard and remove version from environment with activation
280
280
  fireEvent.click(getByLabelText('test1'));
281
281
  await patientlyWaitFor(() => {
282
282
  expect(getByText('Select content view')).toBeInTheDocument();
283
- expect(getByText('Select a content view')).toBeInTheDocument();
283
+ expect(getByPlaceholderText('Select a content view')).toBeInTheDocument();
284
284
  });
285
- fireEvent.click(getByText('Select a content view'));
285
+ fireEvent.click(getByPlaceholderText('Select a content view'));
286
286
  await patientlyWaitFor(() => {
287
287
  expect(getByText('cv2')).toBeInTheDocument();
288
288
  });
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { translate as __ } from 'foremanReact/common/I18n';
3
+ import { Select, SelectVariant } from '@patternfly/react-core';
4
+ import PropTypes from 'prop-types';
5
+
6
+ const ContentViewSelect = ({
7
+ headerText,
8
+ children,
9
+ onClear,
10
+ ...pfSelectProps
11
+ }) => (
12
+ <div style={{ marginTop: '1em' }}>
13
+ <h3>{headerText}</h3>
14
+ <Select
15
+ variant={SelectVariant.typeahead}
16
+ onClear={onClear}
17
+ maxHeight="20rem"
18
+ menuAppendTo="parent"
19
+ ouiaId="select-content-view"
20
+ id="selectCV"
21
+ name="selectCV"
22
+ aria-label="selectCV"
23
+ {...pfSelectProps}
24
+ >
25
+ {children}
26
+ </Select>
27
+ </div>
28
+ );
29
+
30
+ ContentViewSelect.propTypes = {
31
+ headerText: PropTypes.string,
32
+ onClear: PropTypes.func.isRequired,
33
+ children: PropTypes.node.isRequired,
34
+ };
35
+
36
+ ContentViewSelect.defaultProps = {
37
+ headerText: __('Select content view'),
38
+ };
39
+
40
+ export default ContentViewSelect;
@@ -27,7 +27,6 @@ export const changeContentSource = (environmentId, contentViewId, contentSourceI
27
27
  content_source_id: contentSourceId,
28
28
  host_ids: hostIds,
29
29
  },
30
- successToast: () => __('Content source successfully updated.'),
31
30
  errorToast: () => __('Something went wrong while updating the content source. See the logs for more information'),
32
31
  });
33
32
 
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import {
3
3
  ActionGroup,
4
+ Alert,
4
5
  Button,
5
6
  Form,
6
7
  Grid,
@@ -24,6 +25,7 @@ const ContentSourceForm = ({
24
25
  contentSourceId,
25
26
  contentHosts,
26
27
  isLoading,
28
+ hostsUpdated,
27
29
  }) => {
28
30
  const formIsValid = () => (!!environmentId &&
29
31
  !!contentViewId &&
@@ -44,6 +46,16 @@ const ContentSourceForm = ({
44
46
  isHorizontal
45
47
  >
46
48
  <Grid hasGutter className="margin-top-16">
49
+ {(contentHosts.length === 0 && !isLoading) && (
50
+
51
+ <GridItem span={7}>
52
+ <Alert
53
+ variant="danger"
54
+ className="margin-top-20"
55
+ title={__('No hosts found')}
56
+ />
57
+ </GridItem>
58
+ )}
47
59
  <FormField label={__('Content source')} id="change_cs_content_source" value={contentSourceId} items={contentSources} onChange={handleContentSource} isDisabled={contentSourcesIsDisabled} />
48
60
  <FormField label={__('Environment')} id="change_cs_environment" value={environmentId} items={environments} onChange={handleEnvironment} isDisabled={environmentIsDisabled} />
49
61
  <FormField label={__('Content view')} id="change_cs_content_view" value={contentViewId} items={contentViews} onChange={handleContentView} isDisabled={viewIsDisabled} />
@@ -54,10 +66,10 @@ const ContentSourceForm = ({
54
66
  variant="primary"
55
67
  id="generate_btn"
56
68
  onClick={e => handleSubmit(e)}
57
- isDisabled={isLoading || !formIsValid()}
69
+ isDisabled={isLoading || !formIsValid() || hostsUpdated}
58
70
  isLoading={isLoading}
59
71
  >
60
- {__('Change content source')}
72
+ {__('Update')}
61
73
  </Button>
62
74
  </ActionGroup>
63
75
  </GridItem>
@@ -78,6 +90,7 @@ ContentSourceForm.propTypes = {
78
90
  contentSourceId: PropTypes.string,
79
91
  contentHosts: PropTypes.arrayOf(PropTypes.shape({})),
80
92
  isLoading: PropTypes.bool,
93
+ hostsUpdated: PropTypes.bool,
81
94
  };
82
95
 
83
96
  ContentSourceForm.defaultProps = {
@@ -89,6 +102,7 @@ ContentSourceForm.defaultProps = {
89
102
  contentSourceId: '',
90
103
  contentHosts: [],
91
104
  isLoading: false,
105
+ hostsUpdated: false,
92
106
  };
93
107
 
94
108
  export default ContentSourceForm;
@@ -1,5 +1,7 @@
1
1
  import React, { useState } from 'react';
2
+ import { FormattedMessage } from 'react-intl';
2
3
  import {
4
+ Alert,
3
5
  Grid,
4
6
  GridItem,
5
7
  CodeBlock,
@@ -39,25 +41,19 @@ const ContentSourceTemplate = ({ template, jobInvocationPath }) => {
39
41
  return (
40
42
  <Grid>
41
43
  <GridItem span={7}>
42
- <h1>
43
- {__("What's next?")}
44
- </h1>
45
- <p>
46
- {jobInvocationPath && (
47
- <>
48
- <a href={jobInvocationPath}>
49
- {__('Run job invocation')}
50
- </a>
51
- &nbsp;
52
- {__('to update configuration on all hosts, or')}
53
- </>
54
- )}
55
- &nbsp;
56
- {__('update configuration on the hosts manually:')}
57
- </p>
44
+ <Alert variant="warning" title={__('Host configurations are not updated yet')} className="margin-top-20" isInline>
45
+ <FormattedMessage
46
+ id="ccs_alert"
47
+ values={{
48
+ link: <a href={jobInvocationPath}>{__('run job invocation')}</a>,
49
+ }}
50
+ defaultMessage={jobInvocationPath ? __('To update the selected host configuration, {link}, or update hosts manually in the next section.') : __('To update the selected host configuration, update hosts manually in the next section.')}
51
+ />
52
+ </Alert>
53
+
58
54
  </GridItem>
59
55
  <GridItem span={7}>
60
- <CodeBlock actions={actions} className="cs_template_code">
56
+ <CodeBlock actions={actions} className="cs_template_code margin-top-20">
61
57
  <CodeBlockCode>
62
58
  {__('Change content source')}
63
59
  <ExpandableSection isExpanded={isExpanded} isDetached>
@@ -1,10 +1,13 @@
1
1
  import React, { useState, useEffect } from 'react';
2
2
  import { useSelector, useDispatch } from 'react-redux';
3
3
 
4
- import { Alert, Grid, GridItem } from '@patternfly/react-core';
4
+ import { Alert, Grid, GridItem, PageSection, Title } from '@patternfly/react-core';
5
5
 
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
+ import { foremanUrl } from 'foremanReact/common/helpers';
7
8
  import { STATUS } from 'foremanReact/constants';
9
+ import BreadcrumbBar from 'foremanReact/components/BreadcrumbBar';
10
+ import Head from 'foremanReact/components/Head';
8
11
 
9
12
  import { selectApiDataStatus,
10
13
  selectApiContentViewStatus,
@@ -53,6 +56,8 @@ const ChangeContentSourcePage = () => {
53
56
  const [environmentId, setEnvironmentId] = useState('');
54
57
  const [contentViewId, setContentViewId] = useState('');
55
58
 
59
+ const noHostSpecified = getHostIds(urlParams.host_id).length === 0 && urlParams.searchParam === '';
60
+
56
61
  const handleSubmit = (e) => {
57
62
  e.preventDefault();
58
63
 
@@ -61,6 +66,7 @@ const ChangeContentSourcePage = () => {
61
66
  contentViewId,
62
67
  contentSourceId,
63
68
  contentHosts.map(h => h.id),
69
+ jobInvocationPath,
64
70
  ));
65
71
  };
66
72
 
@@ -74,6 +80,19 @@ const ChangeContentSourcePage = () => {
74
80
  }
75
81
  };
76
82
 
83
+ const breadcrumbItems = () => {
84
+ const linkHosts = { caption: __('Hosts'), url: foremanUrl('/hosts') };
85
+ const linkContent = { caption: __('Change host content source') };
86
+
87
+ if (urlParams.host_id) {
88
+ const hostName = contentHosts.concat(hostsWithoutContent)
89
+ .find(h => `${h.id}` === urlParams.host_id)?.name;
90
+
91
+ return ([linkHosts, { caption: hostName, url: foremanUrl(`/new/hosts/${hostName}`) }, linkContent]);
92
+ }
93
+ return ([linkHosts, linkContent]);
94
+ };
95
+
77
96
  const handleEnvironment = (envId) => {
78
97
  setEnvironmentId(envId);
79
98
  setContentViewId('');
@@ -86,45 +105,66 @@ const ChangeContentSourcePage = () => {
86
105
  dispatch(getFormData(getHostIds(urlParams.host_id), urlParams.searchParam));
87
106
  }, [dispatch, urlParams.host_id, urlParams.searchParam]);
88
107
 
89
- if (getHostIds(urlParams.host_id).length === 0 && urlParams.searchParam === '') {
90
- return (
91
- <Grid className="margin-40">
92
- <GridItem span={7}>
93
- <Alert
94
- variant="danger"
95
- title={__('No hosts with content source found!')}
96
- />
97
- </GridItem>
98
- </Grid>);
99
- }
100
-
101
108
  return (
102
- <Grid className="margin-40">
103
- <GridItem span={7}>
104
- <h1>{__('Change host content source')}</h1>
105
- </GridItem>
106
- <Hosts
107
- contentHosts={contentHosts}
108
- hostsWithoutContent={hostsWithoutContent}
109
- />
110
-
111
- <ContentSourceForm
112
- handleSubmit={handleSubmit}
113
- environments={environments}
114
- handleEnvironment={handleEnvironment}
115
- environmentId={environmentId}
116
- contentViews={contentViews}
117
- handleContentView={setContentViewId}
118
- contentViewId={contentViewId}
119
- contentSources={contentSources}
120
- contentSourceId={contentSourceId}
121
- handleContentSource={handleContentSource}
122
- contentHosts={contentHosts}
123
- isLoading={isLoading}
124
- />
125
- { apiChangeStatus === STATUS.RESOLVED &&
126
- <ContentSourceTemplate template={template} jobInvocationPath={jobInvocationPath} /> }
127
- </Grid>
109
+ <>
110
+ <Head>
111
+ <title>{__('Change host content source')}</title>
112
+ </Head>
113
+ <PageSection
114
+ isFilled
115
+ variant="light"
116
+ >
117
+ <div className="margin-left-20">
118
+ <BreadcrumbBar
119
+ breadcrumbItems={breadcrumbItems()}
120
+ />
121
+ </div>
122
+ <Grid className="margin-left-20">
123
+ <GridItem span={7}>
124
+ <Title
125
+ headingLevel="h5"
126
+ size="2xl"
127
+ >
128
+ {__('Change host content source')}
129
+ </Title>
130
+ </GridItem>
131
+ {noHostSpecified &&
132
+ <GridItem span={7}>
133
+ <Alert
134
+ variant="danger"
135
+ className="margin-top-20"
136
+ title={__('No hosts were specified')}
137
+ />
138
+ </GridItem>
139
+ }
140
+ { !noHostSpecified &&
141
+ <>
142
+ <Hosts
143
+ contentHosts={contentHosts}
144
+ hostsWithoutContent={hostsWithoutContent}
145
+ />
146
+
147
+ <ContentSourceForm
148
+ handleSubmit={handleSubmit}
149
+ environments={environments}
150
+ handleEnvironment={handleEnvironment}
151
+ environmentId={environmentId}
152
+ contentViews={contentViews}
153
+ handleContentView={setContentViewId}
154
+ contentViewId={contentViewId}
155
+ contentSources={contentSources}
156
+ contentSourceId={contentSourceId}
157
+ handleContentSource={handleContentSource}
158
+ contentHosts={contentHosts}
159
+ isLoading={isLoading}
160
+ hostsUpdated={apiChangeStatus === STATUS.RESOLVED}
161
+ />
162
+ </> }
163
+ { apiChangeStatus === STATUS.RESOLVED &&
164
+ <ContentSourceTemplate template={template} jobInvocationPath={jobInvocationPath} /> }
165
+ </Grid>
166
+ </PageSection>
167
+ </>
128
168
  );
129
169
  };
130
170
 
@@ -6,6 +6,10 @@
6
6
  margin-bottom: 40px;
7
7
  }
8
8
 
9
- .margin-40 {
10
- margin: 40px;
9
+ .margin-left-20 {
10
+ margin-left: 20px;
11
+ }
12
+
13
+ .margin-top-20 {
14
+ margin-top: 20px;
11
15
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katello
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 4.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - N/A
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-08 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -5160,6 +5160,7 @@ files:
5160
5160
  - webpack/scenes/ContentViews/__tests__/mockDetails.fixtures.json
5161
5161
  - webpack/scenes/ContentViews/components/CVBreadCrumb.js
5162
5162
  - webpack/scenes/ContentViews/components/ContentViewIcon.js
5163
+ - webpack/scenes/ContentViews/components/ContentViewSelect/ContentViewSelect.js
5163
5164
  - webpack/scenes/ContentViews/components/ContentViewsCounter.js
5164
5165
  - webpack/scenes/ContentViews/components/EnvironmentLabels.js
5165
5166
  - webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPathActions.js