katello 3.18.5 → 4.0.0.rc1

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 (239) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/katello/katello.scss +72 -0
  3. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +6 -4
  4. data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +0 -19
  5. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -3
  6. data/app/controllers/katello/api/v2/content_credentials_controller.rb +24 -24
  7. data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +1 -1
  8. data/app/controllers/katello/api/v2/content_exports_controller.rb +4 -0
  9. data/app/controllers/katello/api/v2/content_views_controller.rb +2 -2
  10. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +2 -3
  11. data/app/controllers/katello/api/v2/repositories_controller.rb +3 -19
  12. data/app/controllers/katello/api/v2/simple_content_access_controller.rb +34 -0
  13. data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
  14. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +8 -4
  15. data/app/controllers/katello/concerns/api/v2/authorization.rb +1 -14
  16. data/app/controllers/katello/concerns/authorization/api/v2/content_views_controller.rb +1 -1
  17. data/app/helpers/katello/sync_management_helper.rb +0 -2
  18. data/app/lib/actions/candlepin/environment/create.rb +1 -1
  19. data/app/lib/actions/candlepin/environment/set_content.rb +1 -1
  20. data/app/lib/actions/katello/activation_key/create.rb +9 -11
  21. data/app/lib/actions/katello/capsule_content/sync.rb +8 -8
  22. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +9 -0
  23. data/app/lib/actions/katello/check_matching_content.rb +17 -0
  24. data/app/lib/actions/katello/content_view/environment_create.rb +6 -8
  25. data/app/lib/actions/katello/content_view/publish.rb +1 -1
  26. data/app/lib/actions/katello/content_view_version/incremental_update.rb +11 -7
  27. data/app/lib/actions/katello/host/hypervisors_update.rb +4 -4
  28. data/app/lib/actions/katello/organization/create.rb +3 -5
  29. data/app/lib/actions/katello/organization/destroy.rb +1 -1
  30. data/app/lib/actions/katello/organization/manifest_delete.rb +3 -5
  31. data/app/lib/actions/katello/organization/manifest_import.rb +1 -1
  32. data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
  33. data/app/lib/actions/katello/orphan_cleanup/remove_orphans.rb +1 -1
  34. data/app/lib/actions/katello/repository/check_matching_content.rb +3 -1
  35. data/app/lib/actions/katello/repository/clone_contents.rb +8 -11
  36. data/app/lib/actions/katello/repository/create.rb +0 -8
  37. data/app/lib/actions/katello/repository/filtered_index_content.rb +3 -0
  38. data/app/lib/actions/katello/repository/index_content.rb +1 -0
  39. data/app/lib/actions/katello/repository/multi_clone_contents.rb +9 -12
  40. data/app/lib/actions/katello/repository/sync.rb +1 -5
  41. data/app/lib/actions/katello/repository/update.rb +0 -8
  42. data/app/lib/actions/middleware/execute_if_contents_changed.rb +4 -1
  43. data/app/lib/actions/pulp/orchestration/repository/refresh_repos.rb +0 -6
  44. data/app/lib/actions/pulp3/capsule_content/refresh_distribution.rb +3 -3
  45. data/app/lib/actions/pulp3/content_guard/refresh_all_distributions.rb +1 -2
  46. data/app/lib/actions/pulp3/content_migration_presenter.rb +2 -5
  47. data/app/lib/actions/pulp3/orchestration/repository/refresh_repos.rb +1 -6
  48. data/app/lib/katello/concerns/base_template_scope_extensions.rb +8 -0
  49. data/app/lib/katello/errors.rb +1 -1
  50. data/app/lib/katello/event_daemon/monitor.rb +53 -0
  51. data/app/lib/katello/event_daemon/runner.rb +99 -0
  52. data/app/lib/katello/logging.rb +32 -0
  53. data/app/lib/katello/messaging/connection.rb +1 -7
  54. data/app/lib/katello/util/pulpcore_content_filters.rb +1 -1
  55. data/app/lib/katello/validators/content_view_puppet_module_validator.rb +1 -1
  56. data/app/models/katello/activation_key.rb +2 -2
  57. data/app/models/katello/candlepin/repository_mapper.rb +1 -1
  58. data/app/models/katello/concerns/hostgroup_extensions.rb +2 -4
  59. data/app/models/katello/concerns/organization_extensions.rb +2 -2
  60. data/app/models/katello/concerns/pulp_database_unit.rb +0 -12
  61. data/app/models/katello/concerns/redhat_extensions.rb +8 -9
  62. data/app/models/katello/concerns/smart_proxy_extensions.rb +24 -0
  63. data/app/models/katello/content_view.rb +5 -1
  64. data/app/models/katello/content_view_environment.rb +2 -2
  65. data/app/models/katello/content_view_puppet_environment.rb +2 -2
  66. data/app/models/katello/content_view_version.rb +2 -1
  67. data/app/models/katello/content_view_version_export_history.rb +20 -0
  68. data/app/models/katello/erratum.rb +3 -1
  69. data/app/models/katello/file_unit.rb +0 -4
  70. data/app/models/katello/glue/candlepin/pool.rb +2 -0
  71. data/app/models/katello/glue/pulp/repo.rb +0 -6
  72. data/app/models/katello/glue/pulp/repos.rb +1 -22
  73. data/app/models/katello/host/content_facet.rb +31 -9
  74. data/app/models/katello/ping.rb +19 -39
  75. data/app/models/katello/pool.rb +5 -0
  76. data/app/models/katello/product.rb +3 -3
  77. data/app/models/katello/repository.rb +3 -3
  78. data/app/presenters/katello/host_subscription_presenter.rb +3 -4
  79. data/app/presenters/katello/host_subscriptions_presenter.rb +24 -0
  80. data/app/services/katello/applicability/applicable_content_helper.rb +6 -8
  81. data/app/services/katello/candlepin_event_listener.rb +11 -19
  82. data/app/services/katello/event_monitor/poller_thread.rb +2 -11
  83. data/app/services/katello/pulp/repository.rb +2 -4
  84. data/app/services/katello/pulp/smart_proxy_repository.rb +0 -15
  85. data/app/services/katello/pulp3/api/core.rb +0 -14
  86. data/app/services/katello/pulp3/erratum.rb +1 -2
  87. data/app/services/katello/pulp3/migration.rb +9 -83
  88. data/app/services/katello/pulp3/migration_plan.rb +5 -54
  89. data/app/services/katello/pulp3/migration_switchover.rb +5 -36
  90. data/app/services/katello/pulp3/repository/apt.rb +2 -1
  91. data/app/services/katello/pulp3/repository/yum.rb +2 -11
  92. data/app/services/katello/pulp3/repository.rb +13 -34
  93. data/app/services/katello/pulp3/rpm.rb +1 -5
  94. data/app/services/katello/pulp3/task.rb +5 -8
  95. data/app/services/katello/pulp3/task_group.rb +5 -13
  96. data/app/services/katello/repository_type.rb +1 -1
  97. data/app/views/foreman/smart_proxies/_content_tab.html.erb +4 -47
  98. data/app/views/foreman/smart_proxies/show.html.erb +1 -1
  99. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +22 -25
  100. data/app/views/katello/api/v2/content_view_version_export_histories/show.json.rabl +1 -0
  101. data/app/views/katello/api/v2/organizations/show.json.rabl +7 -9
  102. data/app/views/katello/sync_management/_products.html.erb +1 -1
  103. data/app/views/overrides/organizations/_edit_override.html.erb +1 -4
  104. data/app/views/overrides/smart_proxies/_environment_tab.html.erb +1 -1
  105. data/app/views/overrides/smart_proxies/_environment_tab_pane.html.erb +1 -1
  106. data/config/katello.yaml.example +0 -3
  107. data/config/routes/api/v2.rb +8 -10
  108. data/db/migrate/20191204214919_add_content_view_version_counts.rb +0 -1
  109. data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +1 -1
  110. data/db/migrate/20210119162528_delete_puppet_and_ostree_repos.rb +56 -0
  111. data/db/migrate/20210128231228_add_type_and_from_cvv_to_cvv_export_history.rb +14 -0
  112. data/db/migrate/20210201163238_migrate_background_download_policy_to_migrate.rb +7 -0
  113. data/db/seeds.d/104-proxy.rb +1 -1
  114. data/db/seeds.d/111-upgrade_tasks.rb +2 -1
  115. data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
  116. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +1 -1
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-host-register-os-client.directive.js +17 -0
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +2 -2
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
  120. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +11 -4
  121. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-deb-client.html +38 -0
  122. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-oracle-client.html +5 -0
  123. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-sles-client.html +28 -0
  124. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register.html +14 -11
  125. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/views/package-filter-details.html +2 -2
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +2 -2
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/download-policy.service.js +0 -1
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +1 -1
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +2 -2
  131. data/lib/katello/engine.rb +4 -5
  132. data/lib/katello/middleware/event_daemon.rb +1 -1
  133. data/lib/katello/permission_creator.rb +3 -2
  134. data/lib/katello/plugin.rb +2 -2
  135. data/lib/katello/tasks/jenkins.rake +1 -1
  136. data/lib/katello/tasks/pulp3_content_switchover.rake +20 -31
  137. data/lib/katello/tasks/pulp3_migration.rake +25 -45
  138. data/lib/katello/tasks/pulp3_migration_abort.rake +0 -8
  139. data/lib/katello/tasks/pulp3_migration_stats.rake +3 -46
  140. data/lib/katello/tasks/upgrades/4.0/remove_ostree_puppet_content.rake +16 -0
  141. data/lib/katello/version.rb +1 -1
  142. data/lib/proxy_api/container_gateway.rb +21 -0
  143. data/locale/bn/katello.edit.po +0 -0
  144. data/locale/cs/katello.edit.po +0 -0
  145. data/locale/de/katello.edit.po +0 -0
  146. data/locale/en/katello.edit.po +0 -0
  147. data/locale/es/katello.edit.po +0 -0
  148. data/locale/fr/katello.edit.po +0 -0
  149. data/locale/gu/katello.edit.po +0 -0
  150. data/locale/hi/katello.edit.po +0 -0
  151. data/locale/it/katello.edit.po +0 -0
  152. data/locale/ja/katello.edit.po +0 -0
  153. data/locale/kn/katello.edit.po +0 -0
  154. data/locale/ko/katello.edit.po +0 -0
  155. data/locale/mr/katello.edit.po +0 -0
  156. data/locale/or/katello.edit.po +0 -0
  157. data/locale/pa/katello.edit.po +0 -0
  158. data/locale/pt/katello.edit.po +0 -0
  159. data/locale/pt_BR/katello.edit.po +0 -0
  160. data/locale/ru/katello.edit.po +0 -0
  161. data/locale/ta/katello.edit.po +0 -0
  162. data/locale/te/katello.edit.po +0 -0
  163. data/locale/zh_CN/katello.edit.po +0 -0
  164. data/locale/zh_TW/katello.edit.po +0 -0
  165. data/package.json +1 -1
  166. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +0 -1
  167. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationHooks.js +2 -0
  168. data/webpack/__mocks__/foremanReact/components/common/dates/LongDateTime.js +5 -0
  169. data/webpack/{scenes/ContentViews/Details/Repositories → components/SelectableDropdown}/SelectableDropdown.js +20 -3
  170. data/webpack/components/SelectableDropdown/__tests__/SelectableDropdown.test.js +45 -0
  171. data/webpack/components/SelectableDropdown/index.js +3 -0
  172. data/webpack/components/Table/TableWrapper.js +2 -1
  173. data/webpack/components/Table/helpers.js +14 -0
  174. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +0 -1
  175. data/webpack/containers/Application/overrides.scss +6 -0
  176. data/webpack/index.js +6 -0
  177. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
  178. data/webpack/scenes/ContentViews/ContentViewsActions.js +31 -2
  179. data/webpack/scenes/ContentViews/ContentViewsConstants.js +5 -1
  180. data/webpack/scenes/ContentViews/Copy/ContentViewCopySelectors.js +16 -0
  181. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +77 -0
  182. data/webpack/scenes/ContentViews/Copy/CopyContentViewModal.js +44 -0
  183. data/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json +42 -0
  184. data/webpack/scenes/ContentViews/Copy/__tests__/copyContentView.test.js +39 -0
  185. data/webpack/scenes/ContentViews/Copy/index.js +4 -0
  186. data/webpack/scenes/ContentViews/Create/ContentViewCreateSelectors.js +16 -0
  187. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +58 -0
  188. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +175 -0
  189. data/webpack/scenes/ContentViews/Create/CreateContentViewModal.js +27 -0
  190. data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +42 -0
  191. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +92 -0
  192. data/webpack/scenes/ContentViews/Create/index.js +4 -0
  193. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +16 -0
  194. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +20 -1
  195. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +17 -7
  196. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +19 -13
  197. data/webpack/scenes/ContentViews/Details/Filters/ContentType.js +40 -0
  198. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +124 -0
  199. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.fixtures.json +134 -0
  200. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.test.js +92 -0
  201. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +44 -25
  202. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewDetailRepos.test.js +17 -7
  203. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetail.test.js +24 -0
  204. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +53 -3
  205. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +4 -3
  206. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +41 -0
  207. data/webpack/scenes/ContentViews/helpers.js +13 -0
  208. data/webpack/scenes/SmartProxy/Content.js +17 -0
  209. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +11 -0
  210. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +3 -0
  211. data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +16 -0
  212. data/webpack/scenes/SmartProxy/SmartProxyContentTable.js +152 -0
  213. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json +140 -0
  214. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +38 -0
  215. data/webpack/scenes/SmartProxy/index.js +4 -0
  216. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +2 -7
  217. data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +3 -3
  218. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +2 -2
  219. data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +2 -2
  220. data/webpack/scenes/Subscriptions/Manifest/index.js +0 -1
  221. data/webpack/test-utils/react-testing-lib-wrapper.js +5 -2
  222. data/webpack/utils/helpers.js +3 -0
  223. metadata +103 -63
  224. data/app/controllers/katello/api/v2/gpg_keys_controller.rb +0 -114
  225. data/app/lib/actions/pulp3/content_migration_reset.rb +0 -22
  226. data/app/lib/katello/util/hostgroup_facets_helper.rb +0 -126
  227. data/app/overrides/disable_turbolinks_on_proxies_index.rb +0 -5
  228. data/app/services/katello/event_daemon.rb +0 -135
  229. data/app/services/katello/pulp/content_counts_calculator.rb +0 -60
  230. data/db/migrate/20210201165835_add_migration_missing_content.rb +0 -12
  231. data/db/migrate/20210420140050_add_pulp3_hrefs_to_content_types_deb.rb +0 -5
  232. data/lib/katello/tasks/check_config.rake +0 -11
  233. data/lib/katello/tasks/fix_hostgroup_facets.rake +0 -8
  234. data/lib/katello/tasks/pulp3_migration_approve_corrupted.rake +0 -21
  235. data/lib/katello/tasks/pulp3_migration_reset.rake +0 -26
  236. data/lib/katello/tasks/reports.rake +0 -7
  237. data/lib/katello/tasks/upgrades/3.10/update_gpg_key_urls.rake +0 -32
  238. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.scss +0 -5
  239. data/webpack/scenes/ContentViews/Table/actionResolver.js +0 -28
@@ -0,0 +1,175 @@
1
+ import { STATUS } from 'foremanReact/constants';
2
+ import React, { useState, useEffect } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { useDispatch, useSelector } from 'react-redux';
5
+ import { Redirect } from 'react-router-dom';
6
+ import { Form, FormGroup, TextInput, TextArea, Checkbox, ActionGroup, Button, Tile, Grid, GridItem } from '@patternfly/react-core';
7
+ import { createContentView } from '../ContentViewsActions';
8
+ import { selectCreateContentViews, selectCreateContentViewStatus, selectCreateContentViewError } from './ContentViewCreateSelectors';
9
+ import { LabelDependencies, LabelAutoPublish, LabelImportOnly } from './ContentViewFormComponents';
10
+ import ContentViewIcon from '../components/ContentViewIcon';
11
+
12
+ const CreateContentViewForm = ({ setModalOpen }) => {
13
+ const dispatch = useDispatch();
14
+ const [name, setName] = useState('');
15
+ const [label, setLabel] = useState('');
16
+ const [description, setDescription] = useState('');
17
+ const [composite, setComposite] = useState(false);
18
+ const [component, setComponent] = useState(true);
19
+ const [autoPublish, setAutoPublish] = useState(false);
20
+ const [importOnly, setImportOnly] = useState(false);
21
+ const [dependencies, setDependencies] = useState(false);
22
+ const [redirect, setRedirect] = useState(false);
23
+ const [saving, setSaving] = useState(false);
24
+
25
+ const response = useSelector(selectCreateContentViews);
26
+ const status = useSelector(selectCreateContentViewStatus);
27
+ const error = useSelector(selectCreateContentViewError);
28
+
29
+ useEffect(() => {
30
+ const { id } = response;
31
+ if (id && status === STATUS.RESOLVED) {
32
+ setSaving(false);
33
+ setRedirect(true);
34
+ } else if (status === STATUS.ERROR) {
35
+ setSaving(false);
36
+ }
37
+ }, [JSON.stringify(response), status, error]);
38
+
39
+ const onSave = () => {
40
+ setSaving(true);
41
+ dispatch(createContentView({
42
+ name,
43
+ label,
44
+ description,
45
+ composite,
46
+ solve_dependencies: dependencies,
47
+ auto_publish: (autoPublish && composite),
48
+ import_only: importOnly,
49
+ }));
50
+ };
51
+
52
+ useEffect(
53
+ () => {
54
+ setLabel(name.replace(/ /g, '_'));
55
+ },
56
+ [name],
57
+ );
58
+
59
+ if (redirect) {
60
+ const { id } = response;
61
+ return (<Redirect to={`/labs/content_views/${id}`} />);
62
+ }
63
+
64
+ return (
65
+ <Form>
66
+ <FormGroup label="Name" isRequired fieldId="name">
67
+ <TextInput
68
+ isRequired
69
+ type="text"
70
+ id="name"
71
+ aria-label="input_name"
72
+ name="name"
73
+ value={name}
74
+ onChange={value => setName(value)}
75
+ />
76
+ </FormGroup>
77
+ <FormGroup label="Label" isRequired fieldId="label">
78
+ <TextInput
79
+ isRequired
80
+ type="text"
81
+ id="label"
82
+ aria-label="input_label"
83
+ name="label"
84
+ value={label}
85
+ onChange={value => setLabel(value)}
86
+ />
87
+ </FormGroup>
88
+ <FormGroup label="Description" fieldId="description">
89
+ <TextArea
90
+ isRequired
91
+ type="text"
92
+ id="description"
93
+ name="description"
94
+ aria-label="input_description"
95
+ value={description}
96
+ onChange={value => setDescription(value)}
97
+ />
98
+ </FormGroup>
99
+ <FormGroup isInline fieldId="type" label="Type">
100
+ <Grid hasGutter>
101
+ <GridItem span={6}>
102
+ <Tile
103
+ isStacked
104
+ aria-label="component_tile"
105
+ icon={<ContentViewIcon composite={false} />}
106
+ id="component"
107
+ title="Component content view"
108
+ onClick={() => { setComponent(true); setComposite(false); }}
109
+ isSelected={component}
110
+ >
111
+ Single content view consisting of repositories
112
+ </Tile>
113
+ </GridItem>
114
+ <GridItem span={6}>
115
+ <Tile
116
+ isStacked
117
+ aria-label="composite_tile"
118
+ icon={<ContentViewIcon composite />}
119
+ id="composite"
120
+ title="Composite content view"
121
+ onClick={() => { setComposite(true); setComponent(false); }}
122
+ isSelected={composite}
123
+ >
124
+ Consists of component content views
125
+ </Tile>
126
+ </GridItem>
127
+ </Grid>
128
+ </FormGroup>
129
+ {!composite &&
130
+ <FormGroup isInline fieldId="dependencies">
131
+ <Checkbox
132
+ id="dependencies"
133
+ name="dependencies"
134
+ label={LabelDependencies()}
135
+ isChecked={dependencies}
136
+ onChange={checked => setDependencies(checked)}
137
+ />
138
+ </FormGroup>}
139
+ {!composite &&
140
+ <FormGroup isInline fieldId="importOnly">
141
+ <Checkbox
142
+ id="importOnly"
143
+ name="importOnly"
144
+ label={LabelImportOnly()}
145
+ isChecked={importOnly}
146
+ onChange={checked => setImportOnly(checked)}
147
+ />
148
+ </FormGroup>}
149
+ {composite &&
150
+ <FormGroup isInline fieldId="autoPublish">
151
+ <Checkbox
152
+ id="autoPublish"
153
+ name="autoPublish"
154
+ label={LabelAutoPublish()}
155
+ isChecked={autoPublish}
156
+ onChange={checked => setAutoPublish(checked)}
157
+ />
158
+ </FormGroup>}
159
+ <ActionGroup>
160
+ <Button aria-label="create_content_view" variant="primary" isDisabled={saving} onClick={() => onSave()}>Create content view</Button>
161
+ <Button variant="link" onClick={() => setModalOpen(false)}>Cancel</Button>
162
+ </ActionGroup>
163
+ </Form>
164
+ );
165
+ };
166
+
167
+ CreateContentViewForm.propTypes = {
168
+ setModalOpen: PropTypes.func,
169
+ };
170
+
171
+ CreateContentViewForm.defaultProps = {
172
+ setModalOpen: null,
173
+ };
174
+
175
+ export default CreateContentViewForm;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Modal, ModalVariant } from '@patternfly/react-core';
4
+ import CreateContentViewForm from './CreateContentViewForm';
5
+
6
+ const CreateContentViewModal = ({ show, setIsOpen }) => (
7
+ <Modal
8
+ title="Create content view"
9
+ variant={ModalVariant.small}
10
+ isOpen={show}
11
+ onClose={() => { setIsOpen(false); }}
12
+ appendTo={document.body}
13
+ ><CreateContentViewForm setModalOpen={setIsOpen} />
14
+ </Modal>
15
+ );
16
+
17
+ CreateContentViewModal.propTypes = {
18
+ show: PropTypes.bool,
19
+ setIsOpen: PropTypes.func,
20
+ };
21
+
22
+ CreateContentViewModal.defaultProps = {
23
+ show: false,
24
+ setIsOpen: null,
25
+ };
26
+
27
+ export default CreateContentViewModal;
@@ -0,0 +1,42 @@
1
+ {
2
+ "content_host_count": 0,
3
+ "composite": false,
4
+ "component_ids": [],
5
+ "default": false,
6
+ "force_puppet_environment": false,
7
+ "version_count": 0,
8
+ "latest_version": null,
9
+ "auto_publish": false,
10
+ "solve_dependencies": false,
11
+ "import_only": false,
12
+ "repository_ids": [],
13
+ "id": 34,
14
+ "name": "1232123",
15
+ "label": "1232123",
16
+ "description": "",
17
+ "organization_id": 1,
18
+ "organization": {
19
+ "name": "Default Organization",
20
+ "label": "Default_Organization",
21
+ "id": 1
22
+ },
23
+ "created_at": "2020-12-14 12:45:59 -0500",
24
+ "updated_at": "2020-12-14 12:45:59 -0500",
25
+ "environments": [],
26
+ "repositories": [],
27
+ "puppet_modules": [],
28
+ "versions": [],
29
+ "components": [],
30
+ "content_view_components": [],
31
+ "activation_keys": [],
32
+ "next_version": "1.0",
33
+ "last_published": null,
34
+ "permissions": {
35
+ "view_content_views": true,
36
+ "edit_content_views": true,
37
+ "destroy_content_views": true,
38
+ "publish_content_views": true,
39
+ "promote_or_remove_content_views": true
40
+ },
41
+ "duplicate_repositories_to_publish": []
42
+ }
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
+
4
+ import { nockInstance, assertNockRequest } from '../../../../test-utils/nockWrapper';
5
+ import api from '../../../../services/api';
6
+ import CreateContentViewForm from '../CreateContentViewForm';
7
+
8
+ const cvCreateData = require('./contentViewCreateResult.fixtures.json');
9
+
10
+ const cvCreatePath = api.getApiUrl('/content_views');
11
+
12
+ const setModalOpen = jest.fn();
13
+
14
+ const createDetails = {
15
+ name: '1232123',
16
+ label: '1232123',
17
+ description: '',
18
+ composite: false,
19
+ solve_dependencies: false,
20
+ auto_publish: false,
21
+ import_only: false,
22
+ };
23
+
24
+ const createdCVDetails = { ...cvCreateData };
25
+
26
+ const form = <CreateContentViewForm setModalOpen={setModalOpen} />;
27
+
28
+ test('Can save content view from form', async (done) => {
29
+ const createscope = nockInstance
30
+ .post(cvCreatePath, createDetails)
31
+ .reply(201, createdCVDetails);
32
+ const { queryByText, getByLabelText } = renderWithRedux(form);
33
+ expect(queryByText('Description')).toBeInTheDocument();
34
+
35
+ fireEvent.change(getByLabelText('input_name'), { target: { value: '1232123' } });
36
+
37
+ await patientlyWaitFor(() => { expect(getByLabelText('input_label')).toHaveAttribute('value', '1232123'); });
38
+
39
+ getByLabelText('create_content_view').click();
40
+
41
+ assertNockRequest(createscope, done);
42
+ });
43
+
44
+ test('Form closes itself upon save', async (done) => {
45
+ const createscope = nockInstance
46
+ .post(cvCreatePath, createDetails)
47
+ .reply(201, createdCVDetails);
48
+ const { getByText, queryByText, getByLabelText } = renderWithRedux(form);
49
+ expect(getByText('Description')).toBeInTheDocument();
50
+ expect(getByText('Name')).toBeInTheDocument();
51
+ expect(getByText('Label')).toBeInTheDocument();
52
+
53
+ fireEvent.change(getByLabelText('input_name'), { target: { value: '1232123' } });
54
+
55
+ await patientlyWaitFor(() => { expect(getByLabelText('input_label')).toHaveAttribute('value', '1232123'); });
56
+
57
+ getByLabelText('create_content_view').click();
58
+ // Form closes it self on success
59
+ await patientlyWaitFor(() => {
60
+ expect(queryByText('Description')).not.toBeInTheDocument();
61
+ });
62
+
63
+ assertNockRequest(createscope, done);
64
+ });
65
+
66
+ test('Displays dependent fields correctly', () => {
67
+ const { getByText, queryByText, getByLabelText } = renderWithRedux(form);
68
+ expect(getByText('Description')).toBeInTheDocument();
69
+ expect(getByText('Name')).toBeInTheDocument();
70
+ expect(getByText('Label')).toBeInTheDocument();
71
+ expect(getByText('Composite content view')).toBeInTheDocument();
72
+ expect(getByText('Component content view')).toBeInTheDocument();
73
+ expect(getByText('Solve Dependencies')).toBeInTheDocument();
74
+ expect(queryByText('Auto Publish')).not.toBeInTheDocument();
75
+ expect(getByText('Import Only')).toBeInTheDocument();
76
+
77
+ // label auto_set
78
+ fireEvent.change(getByLabelText('input_name'), { target: { value: '123 2123' } });
79
+ expect(getByLabelText('input_label')).toHaveAttribute('value', '123_2123');
80
+
81
+ // display Auto Publish when Composite CV
82
+ fireEvent.click(getByLabelText('composite_tile'));
83
+ expect(queryByText('Solve Dependencies')).not.toBeInTheDocument();
84
+ expect(getByText('Auto Publish')).toBeInTheDocument();
85
+ expect(queryByText('Import Only')).not.toBeInTheDocument();
86
+
87
+ // display Solve Dependencies when Component CV
88
+ fireEvent.click(getByLabelText('component_tile'));
89
+ expect(getByText('Solve Dependencies')).toBeInTheDocument();
90
+ expect(queryByText('Auto Publish')).not.toBeInTheDocument();
91
+ expect(getByText('Import Only')).toBeInTheDocument();
92
+ });
@@ -0,0 +1,4 @@
1
+ import { withRouter } from 'react-router-dom';
2
+ import CreateContentViewModal from './CreateContentViewModal';
3
+
4
+ export default withRouter(CreateContentViewModal);
@@ -8,8 +8,10 @@ import {
8
8
  UPDATE_CONTENT_VIEW_SUCCESS,
9
9
  NOT_ADDED,
10
10
  ALL_STATUSES,
11
+ REPOSITORY_TYPES,
11
12
  cvDetailsKey,
12
13
  cvDetailsRepoKey,
14
+ cvDetailsFilterKey,
13
15
  } from '../ContentViewsConstants';
14
16
  import api from '../../../services/api';
15
17
 
@@ -63,4 +65,18 @@ export const getContentViewRepositories = (cvId, params, status) => {
63
65
  });
64
66
  };
65
67
 
68
+ export const getRepositoryTypes = () => get({
69
+ type: API_OPERATIONS.GET,
70
+ key: REPOSITORY_TYPES,
71
+ errorToast: error => __(`Something went wrong while retrieving the repository types! ${error}`),
72
+ url: api.getApiUrl('/repositories/repository_types'),
73
+ });
74
+
75
+ export const getContentViewFilters = (cvId, params) => get({
76
+ key: cvDetailsFilterKey(cvId),
77
+ params: { content_view_id: cvId, ...params },
78
+ errorToast: error => __(`Something went wrong while retrieving the content view filters! ${error}`),
79
+ url: api.getApiUrl('/content_view_filters'),
80
+ });
81
+
66
82
  export default getContentViewDetails;
@@ -4,7 +4,12 @@ import {
4
4
  selectAPIResponse,
5
5
  } from 'foremanReact/redux/API/APISelectors';
6
6
  import { STATUS } from 'foremanReact/constants';
7
- import { cvDetailsKey, cvDetailsRepoKey } from '../ContentViewsConstants';
7
+ import {
8
+ cvDetailsKey,
9
+ cvDetailsRepoKey,
10
+ cvDetailsFilterKey,
11
+ REPOSITORY_TYPES,
12
+ } from '../ContentViewsConstants';
8
13
 
9
14
  export const selectCVDetails = (state, cvId) =>
10
15
  selectAPIResponse(state, cvDetailsKey(cvId)) || {};
@@ -24,5 +29,19 @@ export const selectCVReposStatus = (state, cvId) =>
24
29
  export const selectCVReposError = (state, cvId) =>
25
30
  selectAPIError(state, cvDetailsRepoKey(cvId));
26
31
 
32
+ export const selectRepoTypes = state =>
33
+ selectAPIResponse(state, REPOSITORY_TYPES) || {};
34
+
35
+ export const selectRepoTypesStatus = state =>
36
+ selectAPIStatus(state, REPOSITORY_TYPES) || STATUS.PENDING;
37
+
38
+ export const selectCVFilters = (state, cvId) =>
39
+ selectAPIResponse(state, cvDetailsFilterKey(cvId)) || {};
40
+
41
+ export const selectCVFiltersStatus = (state, cvId) =>
42
+ selectAPIStatus(state, cvDetailsFilterKey(cvId)) || STATUS.PENDING;
43
+
44
+ export const selectCVFiltersError = (state, cvId) =>
45
+ selectAPIError(state, cvDetailsFilterKey(cvId));
27
46
 
28
47
  export const selectIsCVUpdating = state => state.katello?.contentViewDetails?.updating;
@@ -1,12 +1,14 @@
1
1
  import React from 'react';
2
2
  import { useSelector, shallowEqual } from 'react-redux';
3
- import { Grid, GridItem, TextContent, Text, TextVariants } from '@patternfly/react-core';
3
+ import { Grid, GridItem, TextContent, Text, TextVariants, Button } from '@patternfly/react-core';
4
+ import { ExternalLinkAltIcon } from '@patternfly/react-icons';
4
5
  import { translate as __ } from 'foremanReact/common/I18n';
5
6
  import PropTypes from 'prop-types';
6
7
 
7
8
  import DetailsContainer from './DetailsContainer';
8
9
  import ContentViewInfo from './ContentViewInfo';
9
10
  import ContentViewRepositories from './Repositories/ContentViewRepositories';
11
+ import ContentViewFilters from './Filters/ContentViewFilters';
10
12
  import { selectCVDetails } from './ContentViewDetailSelectors';
11
13
  import TabbedView from '../../../components/TabbedView';
12
14
 
@@ -30,27 +32,35 @@ const ContentViewDetails = ({ match }) => {
30
32
  },
31
33
  {
32
34
  title: __('Filters'),
33
- content: <React.Fragment>Filters</React.Fragment>,
35
+ content: <ContentViewFilters cvId={cvId} />,
34
36
  },
35
37
  {
36
38
  title: __('History'),
37
39
  content: <React.Fragment>History</React.Fragment>,
38
40
  },
39
- {
40
- title: __('Tasks'),
41
- content: <React.Fragment>Tasks</React.Fragment>,
42
- },
43
41
  ];
44
42
 
45
43
  return (
46
44
  <Grid className="grid-with-margin">
47
45
  <DetailsContainer cvId={cvId}>
48
46
  <React.Fragment>
49
- <GridItem span={12}>
47
+ <GridItem span={8}>
50
48
  <TextContent>
51
49
  <Text component={TextVariants.h1}>{`${name} content view`}</Text>
52
50
  </TextContent>
53
51
  </GridItem>
52
+ <GridItem span={4} style={{ textAlign: 'right' }}>
53
+ <Button
54
+ component="a"
55
+ aria-label="view tasks button"
56
+ href={`/foreman_tasks/tasks?search=resource_type%3D+Katello%3A%3AContentView+resource_id%3D${cvId}`}
57
+ target="_blank"
58
+ variant="secondary"
59
+ >
60
+ {'View tasks '}
61
+ <ExternalLinkAltIcon />
62
+ </Button>
63
+ </GridItem>
54
64
  <GridItem span={12}>
55
65
  <TabbedView tabs={tabs} />
56
66
  </GridItem>
@@ -8,6 +8,7 @@ import {
8
8
  TextListVariants,
9
9
  TextListItem,
10
10
  TextListItemVariants,
11
+ Switch,
11
12
  } from '@patternfly/react-core';
12
13
  import PropTypes from 'prop-types';
13
14
  import { translate as __ } from 'foremanReact/common/I18n';
@@ -18,6 +19,8 @@ import Loading from '../../../components/Loading';
18
19
  import ContentViewIcon from '../components/ContentViewIcon';
19
20
  import ActionableDetail from '../../../components/ActionableDetail';
20
21
  import './contentViewInfo.scss';
22
+ import { dependenciesHelpText, autoPublishHelpText } from '../helpers';
23
+ import { LabelImportOnly } from '../Create/ContentViewFormComponents';
21
24
 
22
25
  const ContentViewInfo = ({ cvId, details }) => {
23
26
  const dispatch = useDispatch();
@@ -29,19 +32,9 @@ const ContentViewInfo = ({ cvId, details }) => {
29
32
  composite,
30
33
  solve_dependencies: solveDependencies,
31
34
  auto_publish: autoPublish,
35
+ import_only: importOnly,
32
36
  } = details;
33
37
 
34
- const autoPublishTooltip = __('Applicable only for composite views. Auto publish composite ' +
35
- 'view when a new version of a component content view is created. Also note auto publish will ' +
36
- 'only happen when the component is marked "latest".');
37
-
38
- const solveDependenciesTooltip = __('This option will solve RPM and Module Stream dependencies ' +
39
- 'on every publish of this Content View. Dependency solving significantly increases publish ' +
40
- 'time (publishes can take over three times as long) and filters will be ignored when adding ' +
41
- 'packages to solve dependencies. Also, certain scenarios involving errata may still cause ' +
42
- 'dependency errors.');
43
-
44
-
45
38
  if (updating) return <Loading size="sm" showText={false} />;
46
39
  const onEdit = (val, attribute) => dispatch(updateContentView(cvId, { [attribute]: val }));
47
40
  return (
@@ -85,7 +78,7 @@ const ContentViewInfo = ({ cvId, details }) => {
85
78
  attribute="auto_publish"
86
79
  value={autoPublish}
87
80
  onEdit={onEdit}
88
- tooltip={autoPublishTooltip}
81
+ tooltip={autoPublishHelpText}
89
82
  boolean
90
83
  />) :
91
84
  (<ActionableDetail
@@ -93,9 +86,21 @@ const ContentViewInfo = ({ cvId, details }) => {
93
86
  attribute="solve_dependencies"
94
87
  value={solveDependencies}
95
88
  onEdit={onEdit}
96
- tooltip={solveDependenciesTooltip}
89
+ tooltip={dependenciesHelpText}
97
90
  boolean
98
91
  />)}
92
+ <TextListItem component={TextListItemVariants.dt}>
93
+ {LabelImportOnly()}
94
+ </TextListItem>
95
+ <TextListItem component={TextListItemVariants.dd} className="foreman-spaced-list">
96
+ <Switch
97
+ id="import_only_switch"
98
+ aria-label="import_only_switch"
99
+ isChecked={importOnly}
100
+ className="foreman-spaced-list"
101
+ disabled
102
+ />
103
+ </TextListItem>
99
104
  </TextList>
100
105
  </TextContent>
101
106
  );
@@ -110,6 +115,7 @@ ContentViewInfo.propTypes = {
110
115
  composite: PropTypes.bool,
111
116
  solve_dependencies: PropTypes.bool,
112
117
  auto_publish: PropTypes.bool,
118
+ import_only: PropTypes.bool,
113
119
  }).isRequired,
114
120
  };
115
121
 
@@ -0,0 +1,40 @@
1
+ import React, { Fragment } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+
5
+ import RepoIcon from '../Repositories/RepoIcon';
6
+ import { capitalize } from '../../../../utils/helpers';
7
+
8
+ const typeName = (type, errataByDate) => {
9
+ if (errataByDate) return 'Errata - by date range';
10
+ const nameMap = {
11
+ rpm: __('RPM'),
12
+ docker: __('Container image tag'),
13
+ modulemd: __('Module stream'),
14
+ erratum: __('Errata'),
15
+ };
16
+
17
+ if (Object.prototype.hasOwnProperty.call(nameMap, type)) return nameMap[type];
18
+ return capitalize(type.replace('_', ' '));
19
+ };
20
+
21
+ const ContentType = ({ type, errataByDate }) => {
22
+ const repoType = ['rpm', 'modulemd', 'rpm', 'erratum', 'package_group'].includes(type) ? 'yum' : type;
23
+ return (
24
+ <Fragment>
25
+ <span style={{ marginRight: '5px' }}><RepoIcon type={repoType} /></span>
26
+ {typeName(type, errataByDate)}
27
+ </Fragment>
28
+ );
29
+ };
30
+
31
+ ContentType.propTypes = {
32
+ type: PropTypes.string.isRequired,
33
+ errataByDate: PropTypes.bool,
34
+ };
35
+
36
+ ContentType.defaultProps = {
37
+ errataByDate: false,
38
+ };
39
+
40
+ export default ContentType;