katello 4.3.0.rc1 → 4.3.0.rc2

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/api_controller.rb +4 -0
  3. data/app/controllers/katello/api/v2/host_errata_controller.rb +5 -0
  4. data/app/controllers/katello/api/v2/host_packages_controller.rb +2 -0
  5. data/app/controllers/katello/api/v2/host_tracer_controller.rb +4 -0
  6. data/app/controllers/katello/api/v2/repository_sets_controller.rb +2 -2
  7. data/app/controllers/katello/api/v2/root_controller.rb +10 -19
  8. data/app/controllers/katello/concerns/api/v2/bulk_extensions.rb +3 -13
  9. data/app/controllers/katello/remote_execution_controller.rb +1 -1
  10. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +7 -5
  11. data/app/lib/actions/katello/repository/destroy.rb +3 -3
  12. data/app/lib/actions/pulp/repository/sync.rb +0 -2
  13. data/app/lib/actions/pulp3/abstract_async_task.rb +16 -4
  14. data/app/lib/katello/resources/cdn.rb +10 -1
  15. data/app/models/katello/concerns/host_managed_extensions.rb +7 -4
  16. data/app/models/katello/concerns/smart_proxy_extensions.rb +6 -2
  17. data/app/models/katello/content_view_version.rb +1 -6
  18. data/app/models/katello/glue/pulp/repo.rb +1 -2
  19. data/app/models/katello/host_tracer.rb +2 -0
  20. data/app/models/katello/repository.rb +2 -30
  21. data/app/models/katello/root_repository.rb +3 -43
  22. data/app/presenters/katello/host_package_presenter.rb +21 -0
  23. data/app/services/katello/bulk_items_helper.rb +35 -0
  24. data/app/services/katello/smart_proxy_helper.rb +10 -1
  25. data/app/views/foreman/job_templates/install_errata.erb +8 -6
  26. data/app/views/foreman/job_templates/resolve_traces.erb +4 -5
  27. data/app/views/foreman/job_templates/resolve_traces_-_katello_ansible_default.erb +3 -5
  28. data/app/views/foreman/smart_proxies/_content_sync.html.erb +7 -0
  29. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +4 -0
  30. data/app/views/katello/api/v2/{organizations/cdn_configuration.rabl → cdn_configurations/show.json.rabl} +4 -0
  31. data/app/views/katello/api/v2/content_facet/show.json.rabl +8 -0
  32. data/app/views/katello/api/v2/content_view_filters/show.json.rabl +0 -1
  33. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -1
  34. data/app/views/katello/api/v2/host_packages/base.json.rabl +2 -0
  35. data/app/views/katello/api/v2/organizations/show.json.rabl +1 -1
  36. data/app/views/katello/api/v2/repositories/show.json.rabl +0 -3
  37. data/config/routes/api/v2.rb +0 -10
  38. data/db/migrate/20211115215210_drop_ostree_branches.rb +13 -0
  39. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/bastion-katello-bootstrap.js +0 -2
  40. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/bastion_katello.js +0 -3
  41. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/content-views.routes.js +0 -10
  42. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-versions.html +0 -3
  43. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-version-content.controller.js +0 -10
  44. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-versions.module.js +0 -1
  45. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/views/content-view-version.html +0 -7
  46. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/content.service.js +0 -5
  47. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.module.js +0 -1
  48. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.routes.js +0 -11
  49. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/organizations/fenced-pages.service.js +1 -2
  50. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +2 -4
  51. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.filter.js +0 -10
  52. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
  53. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +3 -6
  54. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +4 -1
  55. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/os-versions.service.js +1 -0
  56. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/repositories.routes.js +0 -9
  57. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/views/product-repositories.html +0 -8
  58. data/engines/bastion_katello/lib/bastion_katello/engine.rb +0 -1
  59. data/lib/katello/permission_creator.rb +0 -1
  60. data/lib/katello/plugin.rb +0 -10
  61. data/lib/katello/tasks/reset.rake +2 -2
  62. data/lib/katello/version.rb +1 -1
  63. data/webpack/components/Packages/index.js +63 -0
  64. data/webpack/components/Search/Search.js +7 -1
  65. data/webpack/components/SelectAllCheckbox/index.js +2 -2
  66. data/webpack/components/Table/MainTable.scss +7 -1
  67. data/webpack/components/Table/TableHooks.js +10 -19
  68. data/webpack/components/Table/TableWrapper.js +0 -2
  69. data/webpack/components/WithOrganization/__snapshots__/withOrganization.test.js.snap +3 -3
  70. data/webpack/components/extensions/HostDetails/HostDetailsConstants.js +1 -0
  71. data/webpack/components/extensions/HostDetails/HostDetailsSelectors.js +16 -0
  72. data/webpack/components/extensions/HostDetails/HostErrata/HostErrataConstants.js +2 -0
  73. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesActions.js +11 -0
  74. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesConstants.js +2 -0
  75. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesSelectors.js +16 -0
  76. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +4 -0
  77. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +1 -0
  78. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab.js +119 -25
  79. data/webpack/components/extensions/HostDetails/Tabs/HostTracesConstants.js +1 -0
  80. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab.js +127 -0
  81. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab.scss +11 -0
  82. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +30 -4
  83. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +1 -0
  84. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js +73 -0
  85. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsConstants.js +2 -0
  86. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsSelectors.js +16 -0
  87. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +347 -0
  88. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.scss +7 -0
  89. data/webpack/components/extensions/HostDetails/Tabs/TracesTab.js +38 -31
  90. data/webpack/components/extensions/HostDetails/Tabs/__tests__/bookmarks.fixtures.json +12 -0
  91. data/webpack/components/extensions/HostDetails/Tabs/__tests__/contentOverrides.fixtures.json +227 -0
  92. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +423 -2
  93. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packages.fixtures.json +28 -0
  94. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +91 -0
  95. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySets.fixtures.json +120 -0
  96. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +307 -0
  97. data/webpack/components/extensions/HostDetails/Tabs/__tests__/resolveErrata.fixtures.json +35 -0
  98. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +55 -9
  99. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +28 -14
  100. data/webpack/containers/Application/overrides.scss +31 -9
  101. data/webpack/global_index.js +4 -2
  102. data/webpack/redux/reducers/RedHatRepositories/enabled.fixtures.js +0 -2
  103. data/webpack/scenes/Content/ContentConfig.js +23 -7
  104. data/webpack/scenes/ContentCredentials/ContentCredentialActions.js +18 -0
  105. data/webpack/scenes/ContentCredentials/ContentCredentialConstants.js +2 -0
  106. data/webpack/scenes/ContentCredentials/ContentCredentialSelectors.js +12 -0
  107. data/webpack/scenes/ContentCredentials/__tests__/contentCredentials.fixtures.js +73 -0
  108. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +1 -1
  109. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +3 -3
  110. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +7 -2
  111. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.scss +7 -0
  112. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +9 -9
  113. data/webpack/scenes/ContentViews/Delete/ContentViewDeleteWizard.js +6 -6
  114. data/webpack/scenes/ContentViews/Delete/Steps/CVDeleteEnvironmentsSelection.js +39 -37
  115. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReview.js +35 -33
  116. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +7 -5
  117. data/webpack/scenes/ContentViews/Delete/__tests__/cvVersionsData.fixtures.json +2 -6
  118. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentEnvironments.js +13 -14
  119. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +18 -9
  120. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +3 -2
  121. data/webpack/scenes/ContentViews/Details/Filters/Add/__tests__/cvFilterCreateResult.fixtures.json +1 -2
  122. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +1 -1
  123. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewErrataByDateDetails.fixtures.json +1 -8
  124. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetail.fixtures.json +1 -2
  125. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetails.test.js +3 -8
  126. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvAllRepos.fixtures.json +0 -2
  127. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvErratumFilterDetails.fixtures.json +1 -2
  128. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvFilterDetailModuleAffectedRepos.fixtures.json +1 -8
  129. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvFilterDetailWithAffectedRepos.fixtures.json +1 -8
  130. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvModuleStreamFilterDetails.fixtures.json +1 -2
  131. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvPackageFilterDetail.fixtures.json +1 -3
  132. data/webpack/scenes/ContentViews/Details/Promote/ContentViewVersionPromote.js +44 -28
  133. data/webpack/scenes/ContentViews/Details/Repositories/ContentCounts.js +2 -1
  134. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +1 -1
  135. data/webpack/scenes/ContentViews/Details/Repositories/LastSync.js +46 -8
  136. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewDetailRepos.fixtures.json +0 -2
  137. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionContent.js +19 -3
  138. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionEnvironments.js +2 -2
  139. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionErrata.js +5 -3
  140. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionErrata.scss +5 -2
  141. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +7 -4
  142. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVEnvironmentSelectionForm.js +59 -53
  143. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionRemoveReview.js +24 -17
  144. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/versionsResponseData.fixtures.json +1 -4
  145. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionRepositoryCell.js +8 -3
  146. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionComponent.fixtures.json +1 -4
  147. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.fixtures.json +1 -2
  148. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetailsCounts.fixtures.json +1 -2
  149. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionRepositories.fixtures.json +1 -18
  150. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.fixtures.json +5 -5
  151. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +1 -0
  152. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersionsWithTask.fixtures.json +1 -3
  153. data/webpack/scenes/ContentViews/Details/contentViewInfo.scss +0 -4
  154. data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +66 -53
  155. data/webpack/scenes/ContentViews/Publish/CVPublishReview.js +40 -28
  156. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +3 -3
  157. data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +14 -14
  158. data/webpack/scenes/ContentViews/Publish/cvPublishForm.scss +6 -0
  159. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +53 -12
  160. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +12 -6
  161. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +6 -6
  162. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +6 -5
  163. data/webpack/scenes/ContentViews/components/ContentViewsCounter.js +2 -2
  164. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +26 -27
  165. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.scss +18 -6
  166. data/webpack/scenes/ContentViews/components/WizardHeader.js +44 -0
  167. data/webpack/scenes/ContentViews/components/contentViewIcon.scss +13 -2
  168. data/webpack/scenes/Organizations/OrganizationActions.js +22 -24
  169. data/webpack/scenes/Organizations/OrganizationConstants.js +1 -3
  170. data/webpack/scenes/Organizations/OrganizationReducer.js +0 -7
  171. data/webpack/scenes/Organizations/OrganizationSelectors.js +16 -0
  172. data/webpack/scenes/Organizations/__tests__/OrganizationActions.test.js +1 -21
  173. data/webpack/scenes/Organizations/__tests__/OrganizationReducer.test.js +0 -20
  174. data/webpack/scenes/Organizations/__tests__/organizations.fixtures.js +34 -23
  175. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +151 -14
  176. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +150 -31
  177. data/webpack/scenes/Subscriptions/Manifest/index.js +14 -3
  178. data/webpack/utils/dateTimeHelpers.js +7 -0
  179. data/webpack/utils/helpers.js +1 -1
  180. metadata +45 -43
  181. data/app/controllers/katello/api/v2/ostree_branches_controller.rb +0 -16
  182. data/app/lib/actions/pulp/repository/presenters/ostree_presenter.rb +0 -91
  183. data/app/models/katello/ostree_branch.rb +0 -12
  184. data/app/models/katello/repository_ostree_branch.rb +0 -7
  185. data/app/services/katello/pulp/ostree_branch.rb +0 -14
  186. data/app/services/katello/pulp/repository/ostree.rb +0 -48
  187. data/app/views/katello/api/v2/ostree_branches/compare.json.rabl +0 -10
  188. data/app/views/katello/api/v2/ostree_branches/index.json.rabl +0 -7
  189. data/app/views/katello/api/v2/ostree_branches/show.json.rabl +0 -5
  190. data/app/views/katello/api/v2/root/resource_list.json.rabl +0 -3
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/views/content-view-version-ostree-branches.html +0 -26
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-ostree.html +0 -27
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/ostree-branch-repositories.controller.js +0 -77
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/ostree-branch.controller.js +0 -31
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch-info.html +0 -15
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch-repositories.html +0 -72
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch.html +0 -30
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branch.factory.js +0 -27
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.controller.js +0 -67
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.module.js +0 -15
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.routes.js +0 -50
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/views/ostree-branches.html +0 -40
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-manage-ostree-branches.html +0 -40
  204. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/ostree-upstream-sync-policy.service.js +0 -26
  205. data/webpack/components/extensions/HostDetails/Tabs/SubscriptionTab.js +0 -12
  206. data/webpack/scenes/Content/Details/ContentCounts.js +0 -42
  207. data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +0 -108
  208. data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +0 -158
@@ -1,5 +1,3 @@
1
- import axios from 'axios';
2
- import MockAdapter from 'axios-mock-adapter';
3
1
  import thunk from 'redux-thunk';
4
2
  import Immutable from 'seamless-immutable';
5
3
  import configureMockStore from 'redux-mock-store';
@@ -8,11 +6,9 @@ import {
8
6
  requestSuccessResponse,
9
7
  getSuccessActions,
10
8
  getFailureActions,
11
- saveSuccessActions,
12
- saveFailureActions,
13
9
  } from './organizations.fixtures';
14
10
 
15
- import { loadOrganization, saveOrganization } from '../OrganizationActions';
11
+ import { loadOrganization } from '../OrganizationActions';
16
12
 
17
13
  const mockStore = configureMockStore([thunk]);
18
14
  const store = mockStore({ organization: Immutable({}) });
@@ -40,20 +36,4 @@ describe('organization actions', () => {
40
36
  await store.dispatch(loadOrganization());
41
37
  expect(store.getActions()).toEqual(getSuccessActions);
42
38
  });
43
-
44
- it('creates SAVE_ORGANIZATION_REQUEST and then fails with 422', async () => {
45
- const mock = new MockAdapter(axios);
46
- mock.onPut('/katello/api/v2/organizations/1').reply(422);
47
-
48
- await store.dispatch(saveOrganization());
49
- expect(store.getActions()).toEqual(saveFailureActions);
50
- });
51
-
52
- it('creates SAVE_ORGANIZATION_REQUEST and ends with success', async () => {
53
- const mock = new MockAdapter(axios);
54
- mock.onPut('/katello/api/v2/organizations/1').reply(200, requestSuccessResponse);
55
-
56
- await store.dispatch(saveOrganization());
57
- expect(store.getActions()).toEqual(saveSuccessActions);
58
- });
59
39
  });
@@ -33,24 +33,4 @@ describe('organizations reducer', () => {
33
33
  error: 'Unable to process request.',
34
34
  })).toEqual(errorState);
35
35
  });
36
-
37
- it('should keep loading state on SAVE_ORGANIZATION_REQUEST', () => {
38
- expect(reducer(initialState, {
39
- type: types.SAVE_ORGANIZATION_REQUEST,
40
- })).toEqual(loadingState);
41
- });
42
-
43
- it('should flatten organization response SAVE_ORGANIZATION_SUCCESS', () => {
44
- expect(reducer(initialState, {
45
- type: types.SAVE_ORGANIZATION_SUCCESS,
46
- response: requestSuccessResponse,
47
- })).toEqual(successState);
48
- });
49
-
50
- it('should have error on SAVE_ORGANIZATION_FAILURE', () => {
51
- expect(reducer(initialState, {
52
- type: types.SAVE_ORGANIZATION_FAILURE,
53
- error: 'Unable to process request.',
54
- })).toEqual(errorState);
55
- });
56
36
  });
@@ -8,6 +8,40 @@ export const loadingState = Immutable({
8
8
  loading: true,
9
9
  });
10
10
 
11
+ export const updateCdnConfigurationSuccessResponse = Immutable({
12
+ id: '6c536461-e7e3-421a-9d7a-780a39cd8fb4',
13
+ label: 'Actions::Katello::CdnConfiguration::Update',
14
+ pending: false,
15
+ action: 'Update CDN Configuration',
16
+ username: 'admin',
17
+ started_at: '2021-11-16 12:00:46 -0500',
18
+ ended_at: '2021-11-16 12:00:47 -0500',
19
+ state: 'stopped',
20
+ result: 'success',
21
+ progress: 1,
22
+ input: {
23
+ locale: 'en',
24
+ current_request_id: '7a0d7e03-ced1-4925-8790-79b73d25d29b',
25
+ current_timezone: 'America/New_York',
26
+ current_organization_id: 4,
27
+ current_location_id: 2,
28
+ current_user_id: 4,
29
+ },
30
+ output: {},
31
+ humanized: {
32
+ action: 'Update CDN Configuration',
33
+ input: [],
34
+ output: '',
35
+ errors: [],
36
+ },
37
+ cli_example: null,
38
+ start_at: '2021-11-16 12:00:46 -0500',
39
+ available_actions: {
40
+ cancellable: false,
41
+ resumable: false,
42
+ },
43
+ });
44
+
11
45
  export const requestSuccessResponse = Immutable({
12
46
  label: 'Default_Organization',
13
47
  owner_details: {
@@ -77,26 +111,3 @@ export const getFailureActions = [
77
111
  type: 'GET_ORGANIZATION_FAILURE',
78
112
  },
79
113
  ];
80
-
81
- export const saveSuccessActions = [
82
- {
83
- type: 'SAVE_ORGANIZATION_REQUEST',
84
- },
85
- {
86
- response: requestSuccessResponse,
87
- type: 'SAVE_ORGANIZATION_SUCCESS',
88
- },
89
- {
90
- type: 'GET_ORGANIZATION_REQUEST',
91
- },
92
- ];
93
-
94
- export const saveFailureActions = [
95
- {
96
- type: 'SAVE_ORGANIZATION_REQUEST',
97
- },
98
- {
99
- result: new Error('Request failed with status code 422'),
100
- type: 'SAVE_ORGANIZATION_FAILURE',
101
- },
102
- ];
@@ -12,21 +12,28 @@ import { Table } from '../../../components/pf3Table';
12
12
  import { columns } from './ManifestHistoryTableSchema';
13
13
  import DeleteManifestModalText from './DeleteManifestModalText';
14
14
  import { MANAGE_MANIFEST_MODAL_ID, DELETE_MANIFEST_MODAL_ID } from './ManifestConstants';
15
+ import { CONTENT_CREDENTIAL_CERT_TYPE } from '../../ContentCredentials/ContentCredentialConstants';
15
16
  import SimpleContentAccess from './SimpleContentAccess';
16
17
 
17
18
  import './ManageManifestModal.scss';
18
19
 
20
+ const PASSWORD_PLACEHOLDER = '******';
21
+
19
22
  class ManageManifestModal extends Component {
20
23
  constructor(props) {
21
24
  super(props);
22
-
23
25
  this.state = {
24
- redhat_repository_url: null,
26
+ cdn_url: null,
27
+ cdn_username: null,
28
+ cdn_password: null,
29
+ cdn_organization_label: null,
30
+ cdn_ssl_ca_credential_id: null,
25
31
  };
26
32
  }
27
33
 
28
34
  componentDidMount() {
29
35
  this.props.loadManifestHistory();
36
+ this.props.getContentCredentials({ content_type: CONTENT_CREDENTIAL_CERT_TYPE });
30
37
  }
31
38
 
32
39
  componentDidUpdate(prevProps) {
@@ -57,12 +64,46 @@ class ManageManifestModal extends Component {
57
64
  }
58
65
  };
59
66
 
60
- updateRepositoryUrl = (event) => {
61
- this.setState({ redhat_repository_url: event.target.value });
67
+ updateCdnUrl = (event) => {
68
+ this.setState({ cdn_url: event.target.value });
69
+ };
70
+
71
+ updateCdnUsername = (event) => {
72
+ this.setState({ cdn_username: event.target.value });
73
+ };
74
+
75
+ hidePasswordPlaceholder = (event) => {
76
+ const { target } = event;
77
+ target.value = this.state.cdn_password;
78
+ };
79
+
80
+ showPasswordPlaceholder = (event) => {
81
+ if (this.state.cdn_password || this.props.organization.cdn_configuration.password_exists) {
82
+ const { target } = event;
83
+ target.value = PASSWORD_PLACEHOLDER;
84
+ }
85
+ };
86
+
87
+ updateCdnPassword = (event) => {
88
+ this.setState({ cdn_password: event.target.value });
62
89
  };
63
90
 
64
- saveOrganization = () => {
65
- this.props.saveOrganization({ redhat_repository_url: this.state.redhat_repository_url });
91
+ updateCdnOrganizationLabel = (event) => {
92
+ this.setState({ cdn_organization_label: event.target.value });
93
+ };
94
+
95
+ updateCdnSSLCaCredentialId = (event) => {
96
+ this.setState({ cdn_ssl_ca_credential_id: event.target.value });
97
+ };
98
+
99
+ updateCdnConfiguration = () => {
100
+ this.props.updateCdnConfiguration({
101
+ url: this.state.cdn_url,
102
+ username: this.state.cdn_username,
103
+ password: this.state.cdn_password,
104
+ upstream_organization_label: this.state.cdn_organization_label,
105
+ ssl_ca_credential_id: this.state.cdn_ssl_ca_credential_id,
106
+ });
66
107
  };
67
108
 
68
109
  uploadManifest = (fileList) => {
@@ -102,8 +143,19 @@ class ManageManifestModal extends Component {
102
143
  disableSimpleContentAccess,
103
144
  taskInProgress,
104
145
  manifestActionStarted,
146
+ updatingCdnConfiguration,
147
+ contentCredentials,
105
148
  } = this.props;
106
149
 
150
+ const contentCredentialOptions = contentCredentials.map(({ name, id }) => (
151
+ <option key={id} value={id}>
152
+ {name}
153
+ </option>
154
+ ));
155
+
156
+ const cdnPasswordDefaultValue = organization?.cdn_configuration?.password_exists ?
157
+ PASSWORD_PLACEHOLDER : this.state.cdn_password;
158
+
107
159
  const actionInProgress = (taskInProgress || manifestActionStarted);
108
160
  const showRedHatProviderDetails = canEditOrganizations;
109
161
  const showSubscriptionManifest = (canImportManifest || canDeleteManifest);
@@ -159,22 +211,87 @@ class ManageManifestModal extends Component {
159
211
  <Form className="form-horizontal">
160
212
  {showRedHatProviderDetails &&
161
213
  <React.Fragment>
162
- <h3>{__('Red Hat Provider Details')}</h3>
214
+ <h3>{__('CDN Configuration for Red Hat content')}</h3>
163
215
  <hr />
164
216
  <FormGroup>
165
217
  <Grid>
166
218
  <Row>
167
219
  <Col sm={5}>
168
220
  <ControlLabel htmlFor="cdnUrl">
169
- {__('Red Hat CDN URL')}
221
+ {__('URL')}
170
222
  </ControlLabel>
171
223
  </Col>
172
224
  <Col sm={7}>
173
225
  <FormControl
174
226
  id="cdnUrl"
175
227
  type="text"
176
- defaultValue={this.state.redhat_repository_url || organization.redhat_repository_url || ''}
177
- onBlur={this.updateRepositoryUrl}
228
+ defaultValue={this.state.cdn_url || organization.cdn_configuration.url || ''}
229
+ onChange={this.updateCdnUrl}
230
+ />
231
+ </Col>
232
+ </Row>
233
+ <Row style={{ paddingTop: '10px' }} >
234
+ <Col sm={5}>
235
+ <ControlLabel htmlFor="cdnUsername">
236
+ {__('Username')}
237
+ </ControlLabel>
238
+ </Col>
239
+ <Col sm={7}>
240
+ <FormControl
241
+ id="cdnUsername"
242
+ type="text"
243
+ defaultValue={this.state.cdn_username || organization.cdn_configuration.username || ''}
244
+ onChange={this.updateCdnUsername}
245
+ />
246
+ </Col>
247
+ </Row>
248
+ <Row style={{ paddingTop: '10px' }} >
249
+ <Col sm={5}>
250
+ <ControlLabel htmlFor="cdnPassword">
251
+ {__('Password')}
252
+ </ControlLabel>
253
+ </Col>
254
+ <Col sm={7}>
255
+ <FormControl
256
+ id="cdnPassword"
257
+ type="text"
258
+ defaultValue={cdnPasswordDefaultValue}
259
+ onFocus={this.hidePasswordPlaceholder}
260
+ onBlur={this.showPasswordPlaceholder}
261
+ onChange={this.updateCdnPassword}
262
+ />
263
+ </Col>
264
+ </Row>
265
+ <Row style={{ paddingTop: '10px' }} >
266
+ <Col sm={5}>
267
+ <ControlLabel htmlFor="cdnSSLCaCredential">
268
+ {__('SSL CA Content Credential')}
269
+ </ControlLabel>
270
+ </Col>
271
+ <Col sm={7}>
272
+ <FormControl
273
+ componentClass="select"
274
+ placeholder="select"
275
+ defaultValue={organization.cdn_configuration.ssl_ca_credential_id}
276
+ onChange={this.updateCdnSSLCaCredentialId}
277
+ >
278
+ <option value="" />
279
+ {contentCredentialOptions}
280
+ </FormControl>
281
+ </Col>
282
+ </Row>
283
+ <Row style={{ paddingTop: '10px' }} >
284
+ <Col sm={5}>
285
+ <ControlLabel htmlFor="cdnOrganizationLabel">
286
+ {__('Organization Label')}
287
+ </ControlLabel>
288
+ </Col>
289
+ <Col sm={7}>
290
+ <FormControl
291
+ id="cdnOrganizationLabel"
292
+ type="text"
293
+ defaultValue={this.state.cdn_organization_label || organization.cdn_configuration.upstream_organization_label || ''}
294
+ onChange={this.updateCdnOrganizationLabel}
178
295
  />
179
296
  </Col>
180
297
  </Row>
@@ -184,8 +301,13 @@ class ManageManifestModal extends Component {
184
301
  <Grid>
185
302
  <Row>
186
303
  <Col smOffset={5} sm={7}>
187
- <Button onClick={this.saveOrganization} disabled={organization.loading}>
188
- {organization.loading ? buttonLoading : __('Update')}
304
+ <Button
305
+ id="updateCdnConfiguration"
306
+ data-testid="updateCdnConfiguration"
307
+ onClick={this.updateCdnConfiguration}
308
+ disabled={updatingCdnConfiguration}
309
+ >
310
+ {updatingCdnConfiguration ? buttonLoading : __('Update')}
189
311
  </Button>
190
312
  </Col>
191
313
  </Row>
@@ -315,9 +437,17 @@ ManageManifestModal.propTypes = {
315
437
  enableSimpleContentAccess: PropTypes.func.isRequired,
316
438
  disableSimpleContentAccess: PropTypes.func.isRequired,
317
439
  loadManifestHistory: PropTypes.func.isRequired,
440
+ getContentCredentials: PropTypes.func.isRequired,
318
441
  organization: PropTypes.shape({
442
+ id: PropTypes.number,
319
443
  loading: PropTypes.bool,
320
- redhat_repository_url: PropTypes.string,
444
+ cdn_configuration: PropTypes.shape({
445
+ url: PropTypes.string,
446
+ username: PropTypes.string,
447
+ upstream_organization_label: PropTypes.string,
448
+ ssl_ca_credential_id: PropTypes.number,
449
+ password_exists: PropTypes.bool,
450
+ }),
321
451
  owner_details: PropTypes.shape({
322
452
  upstreamConsumer: PropTypes.shape({
323
453
  uuid: PropTypes.string,
@@ -334,7 +464,7 @@ ManageManifestModal.propTypes = {
334
464
  disableManifestActions: PropTypes.bool,
335
465
  disabledReason: PropTypes.string,
336
466
  loadOrganization: PropTypes.func.isRequired,
337
- saveOrganization: PropTypes.func.isRequired,
467
+ updateCdnConfiguration: PropTypes.func.isRequired,
338
468
  taskInProgress: PropTypes.bool.isRequired,
339
469
  simpleContentAccess: PropTypes.bool,
340
470
  simpleContentAccessEligible: PropTypes.bool,
@@ -347,6 +477,11 @@ ManageManifestModal.propTypes = {
347
477
  setModalClosed: PropTypes.func.isRequired,
348
478
  setModalOpen: PropTypes.func.isRequired,
349
479
  manifestActionStarted: PropTypes.bool,
480
+ contentCredentials: PropTypes.arrayOf(PropTypes.shape({
481
+ id: PropTypes.number,
482
+ name: PropTypes.string,
483
+ })),
484
+ updatingCdnConfiguration: PropTypes.bool,
350
485
  };
351
486
 
352
487
  ManageManifestModal.defaultProps = {
@@ -360,6 +495,8 @@ ManageManifestModal.defaultProps = {
360
495
  simpleContentAccess: false,
361
496
  simpleContentAccessEligible: undefined,
362
497
  manifestActionStarted: false,
498
+ updatingCdnConfiguration: false,
499
+ contentCredentials: [],
363
500
  };
364
501
 
365
502
  export default ManageManifestModal;
@@ -1,33 +1,152 @@
1
1
  import React from 'react';
2
- import { shallow } from 'enzyme';
3
- import toJson from 'enzyme-to-json';
4
- import ManageManifestModal from '../ManageManifestModal';
5
- import { manifestHistorySuccessState } from './manifest.fixtures';
6
-
7
- jest.mock('foremanReact/components/Pagination/PaginationWrapper', () => (<div>Pagination Mock</div>));
8
- jest.mock('foremanReact/components/ForemanModal');
9
-
10
- describe('manage manifest modal', () => {
11
- const noop = jest.fn();
12
- const organization = { id: 1, redhat_repository_url: 'https://redhat.com' };
13
-
14
- it('should render', () => {
15
- const page = shallow(<ManageManifestModal
16
- setModalOpen={noop}
17
- setModalClosed={noop}
18
- upload={noop}
19
- refresh={noop}
20
- delete={noop}
21
- enableSimpleContentAccess={noop}
22
- disableSimpleContentAccess={noop}
23
- loadManifestHistory={noop}
24
- organization={organization}
25
- loadOrganization={noop}
26
- saveOrganization={noop}
27
- bulkSearch={noop}
28
- manifestHistory={manifestHistorySuccessState}
29
- taskInProgress={false}
30
- />);
31
- expect(toJson(page)).toMatchSnapshot();
32
- });
2
+ import { cleanup } from '@testing-library/react';
3
+ import { renderWithRedux, fireEvent, patientlyWaitFor } from 'react-testing-lib-wrapper';
4
+ import ManifestModal from '../../Manifest';
5
+ import { manifestHistorySuccessState, manifestHistorySuccessResponse } from './manifest.fixtures';
6
+ import { updateCdnConfigurationSuccessResponse } from '../../../Organizations/__tests__/organizations.fixtures';
7
+ import { contentCredentialsResponse } from '../../../ContentCredentials/__tests__/contentCredentials.fixtures';
8
+ import { nockInstance, assertNockRequest } from '../../../../test-utils/nockWrapper';
9
+ import api from '../../../../services/api';
10
+
11
+ afterEach(cleanup);
12
+
13
+ const noop = jest.fn();
14
+ const organization = {
15
+ id: 1,
16
+ redhat_repository_url: 'https://redhat.com',
17
+ cdn_configuration: {
18
+
19
+ },
20
+ owner_details: {
21
+ upstreamConsumer: {
22
+ webUrl: 'https://example.com/',
23
+ },
24
+ },
25
+ };
26
+
27
+ const defaultProps = {
28
+ disableManifestActions: false,
29
+ disabledReason: '',
30
+ canImportManifest: true,
31
+ canDeleteManifest: true,
32
+ canEditOrganizations: true,
33
+ upload: noop,
34
+ refresh: noop,
35
+ delete: noop,
36
+ enableSimpleContentAccess: noop,
37
+ disableSimpleContentAccess: noop,
38
+ loadManifestHistory: noop,
39
+ organization,
40
+ loadOrganization: noop,
41
+ taskInProgress: false,
42
+ simpleContentAccess: true,
43
+ manifestHistory: manifestHistorySuccessState,
44
+ setModalClosed: noop,
45
+ setModalOpen: noop,
46
+ updateCdnConfiguration: noop,
47
+ getContentCredentials: noop,
48
+ };
49
+
50
+ const initialState = {
51
+ katello: {
52
+ organization: {
53
+ simple_content_access: false,
54
+ ...organization,
55
+ },
56
+ },
57
+ foremanModals: {
58
+ manageManifestModal: {
59
+ isOpen: true,
60
+ },
61
+ },
62
+ };
63
+
64
+ const enableSimpleContetAccessPath = api.getApiUrl('/organizations/1/simple_content_access/enable');
65
+ const disableSimpleContetAccessPath = api.getApiUrl('/organizations/1/simple_content_access/disable');
66
+ const manifestHistoryPath = api.getApiUrl('/organizations/1/subscriptions/manifest_history');
67
+ const getContentCredentialsPath = api.getApiUrl('/content_credentials?organization_id=1&content_type=cert');
68
+ const updateCdnConfigurationPath = api.getApiUrl('/organizations/1/cdn_configuration');
69
+
70
+ test('Can update the CDN configuration', async (done) => {
71
+ const { getByTestId } = renderWithRedux(<ManifestModal {...defaultProps} />, { initialState });
72
+
73
+ const getscope = nockInstance
74
+ .get(manifestHistoryPath)
75
+ .query(true)
76
+ .reply(200, manifestHistorySuccessResponse);
77
+
78
+ const contentCredentialsRequest = nockInstance
79
+ .get(getContentCredentialsPath)
80
+ .reply(200, contentCredentialsResponse);
81
+
82
+ const updateCdnConfigurationRequest = nockInstance
83
+ .put(updateCdnConfigurationPath)
84
+ .reply(200, updateCdnConfigurationSuccessResponse);
85
+
86
+ const updateButton = getByTestId('updateCdnConfiguration');
87
+ await patientlyWaitFor(() => { expect(updateButton).toBeInTheDocument(); });
88
+
89
+ fireEvent.click(updateButton);
90
+
91
+ assertNockRequest(contentCredentialsRequest);
92
+ assertNockRequest(getscope);
93
+ assertNockRequest(updateCdnConfigurationRequest, done);
94
+ });
95
+
96
+ test('Enable Simple Content Access after toggle switch value to true', async (done) => {
97
+ const { getByTestId } = renderWithRedux(<ManifestModal {...defaultProps} />, { initialState });
98
+
99
+ const updatescope = nockInstance
100
+ .put(enableSimpleContetAccessPath)
101
+ .reply(202, true);
102
+
103
+ const getscope = nockInstance
104
+ .get(manifestHistoryPath)
105
+ .query(true)
106
+ .reply(200, manifestHistorySuccessResponse);
107
+
108
+ const contentCredentialsRequest = nockInstance
109
+ .get(getContentCredentialsPath)
110
+ .reply(200, {});
111
+
112
+ const toggleButton = getByTestId('switch');
113
+
114
+ await patientlyWaitFor(() => { expect(toggleButton).toBeInTheDocument(); });
115
+ expect(toggleButton.checked).toEqual(false);
116
+
117
+ fireEvent.click(toggleButton);
118
+
119
+ assertNockRequest(contentCredentialsRequest);
120
+ assertNockRequest(getscope);
121
+ assertNockRequest(updatescope, done);
122
+ });
123
+
124
+ test('Disable Simple Content Access after toggle switch value to false', async (done) => {
125
+ initialState.katello.organization.simple_content_access = true;
126
+
127
+ const updatescope = nockInstance
128
+ .put(disableSimpleContetAccessPath)
129
+ .reply(202, true);
130
+
131
+ const getscope = nockInstance
132
+ .get(manifestHistoryPath)
133
+ .query(true)
134
+ .reply(200, manifestHistorySuccessResponse);
135
+
136
+ const contentCredentialsRequest = nockInstance
137
+ .get(getContentCredentialsPath)
138
+ .reply(200, {});
139
+
140
+ const { getByTestId } = renderWithRedux(<ManifestModal {...defaultProps} />, { initialState });
141
+
142
+ const toggleButton = getByTestId('switch');
143
+
144
+ await patientlyWaitFor(() => { expect(toggleButton).toBeInTheDocument(); });
145
+ expect(toggleButton.checked).toEqual(true);
146
+
147
+ fireEvent.click(toggleButton);
148
+
149
+ assertNockRequest(contentCredentialsRequest);
150
+ assertNockRequest(getscope);
151
+ assertNockRequest(updatescope, done);
33
152
  });
@@ -4,10 +4,16 @@ import { connect } from 'react-redux';
4
4
  import * as foremanModalActions from 'foremanReact/components/ForemanModal/ForemanModalActions';
5
5
  import * as manifestActions from './ManifestActions';
6
6
  import * as organizationActions from '../../Organizations/OrganizationActions';
7
+ import * as contentCredentialActions from '../../ContentCredentials/ContentCredentialActions';
7
8
  import * as tasksActions from '../../Tasks/TaskActions';
8
9
  import history from './ManifestHistoryReducer';
9
- import { selectSimpleContentAccessEnabled, selectIsManifestImported } from '../../Organizations/OrganizationSelectors';
10
+ import {
11
+ selectSimpleContentAccessEnabled,
12
+ selectIsManifestImported,
13
+ selectUpdatingCdnConfiguration,
14
+ } from '../../Organizations/OrganizationSelectors';
10
15
  import { selectManifestActionStarted, selectSimpleContentAccessEligible } from '../SubscriptionsSelectors';
16
+ import { selectContentCredentials } from '../../ContentCredentials/ContentCredentialSelectors';
11
17
 
12
18
  import ManifestModal from './ManageManifestModal';
13
19
 
@@ -19,15 +25,20 @@ const mapStateToProps = state => ({
19
25
  manifestHistory: state.katello.manifestHistory,
20
26
  simpleContentAccess: selectSimpleContentAccessEnabled(state),
21
27
  isManifestImported: selectIsManifestImported(state),
22
- modalOpenState: state.foremanModals.ManageManifestModal,
23
28
  deleteManifestModalExists: !!state.foremanModals.deleteManifestModal,
24
29
  manifestActionStarted: selectManifestActionStarted(state),
25
30
  simpleContentAccessEligible: selectSimpleContentAccessEligible(state),
31
+ updatingCdnConfiguration: selectUpdatingCdnConfiguration(state),
32
+ contentCredentials: selectContentCredentials(state),
26
33
  });
27
34
 
28
35
  // map action dispatchers to props
29
36
  const actions = {
30
- ...manifestActions, ...organizationActions, ...tasksActions, ...foremanModalActions,
37
+ ...manifestActions,
38
+ ...organizationActions,
39
+ ...tasksActions,
40
+ ...foremanModalActions,
41
+ ...contentCredentialActions,
31
42
  };
32
43
  const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
33
44
 
@@ -0,0 +1,7 @@
1
+ import moment from 'moment';
2
+
3
+ // Example: "2021-11-08 12:01:23 -0700" => November 08, 2021, 12:01 PM
4
+ export const makeReadableDate = dateString =>
5
+ moment(dateString, 'YYYY-MM-DD hh:mm:ss Z').format('MMMM DD, YYYY, h:mm A');
6
+
7
+ export default { makeReadableDate };
@@ -40,7 +40,7 @@ export const getResponseErrorMsgs = ({ data, actionType } = {}) => {
40
40
  data.displayMessage ||
41
41
  data.message ||
42
42
  data.errors ||
43
- data.error;
43
+ data.error?.message;
44
44
  return Array.isArray(messages) ? messages : [messages];
45
45
  }
46
46
  return [];