katello 3.16.0.rc1.1 → 3.16.0.rc4

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/api_controller.rb +8 -4
  3. data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
  4. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +13 -1
  5. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +11 -0
  6. data/app/controllers/katello/remote_execution_controller.rb +1 -1
  7. data/app/lib/actions/katello/applicability/hosts/{generate.rb → bulk_generate.rb} +11 -2
  8. data/app/lib/actions/katello/applicability/repository/regenerate.rb +7 -2
  9. data/app/lib/actions/katello/host/generate_applicability.rb +7 -2
  10. data/app/lib/actions/katello/host/upload_profiles.rb +20 -11
  11. data/app/lib/actions/katello/repository/sync.rb +1 -2
  12. data/app/lib/actions/katello/repository/update.rb +12 -1
  13. data/app/lib/actions/katello/repository/update_cv_repo_cert_guard.rb +17 -0
  14. data/app/lib/actions/pulp3/ContentGuard/refresh.rb +19 -0
  15. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +6 -8
  16. data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +1 -1
  17. data/app/lib/actions/pulp3/repository/copy_content.rb +1 -0
  18. data/app/lib/actions/pulp3/repository/refresh_distribution.rb +1 -0
  19. data/app/lib/actions/pulp3/repository/save_distribution_references.rb +3 -1
  20. data/app/lib/actions/pulp3/repository/save_version.rb +3 -1
  21. data/app/lib/actions/pulp3/repository/update_cv_repository_cert_guard.rb +15 -0
  22. data/app/lib/katello/concerns/base_template_scope_extensions.rb +5 -1
  23. data/app/lib/katello/errors.rb +25 -0
  24. data/app/lib/katello/logging.rb +14 -0
  25. data/app/lib/katello/resources/candlepin.rb +1 -1
  26. data/app/lib/katello/resources/candlepin/upstream_consumer.rb +6 -0
  27. data/app/lib/katello/util/errata.rb +13 -0
  28. data/app/lib/katello/util/pulpcore_content_filters.rb +32 -0
  29. data/app/models/katello/concerns/host_managed_extensions.rb +7 -0
  30. data/app/models/katello/concerns/http_proxy_extensions.rb +30 -7
  31. data/app/models/katello/concerns/organization_extensions.rb +14 -0
  32. data/app/models/katello/concerns/pulp_database_unit.rb +2 -2
  33. data/app/models/katello/content_view_erratum_filter.rb +29 -0
  34. data/app/models/katello/content_view_package_filter.rb +16 -1
  35. data/app/models/katello/content_view_package_group_filter.rb +7 -0
  36. data/app/models/katello/events/generate_host_applicability.rb +6 -5
  37. data/app/models/katello/glue/candlepin/candlepin_object.rb +9 -5
  38. data/app/models/katello/glue/candlepin/pool.rb +8 -3
  39. data/app/models/katello/glue/provider.rb +11 -4
  40. data/app/models/katello/host/content_facet.rb +1 -1
  41. data/app/models/katello/host_queue_element.rb +4 -0
  42. data/app/models/katello/package_group.rb +2 -1
  43. data/app/models/katello/pool.rb +1 -1
  44. data/app/models/katello/pulp3/content_guard.rb +14 -0
  45. data/app/models/katello/rhsm_fact_parser.rb +4 -0
  46. data/app/models/katello/root_repository.rb +4 -1
  47. data/app/models/setting/content.rb +3 -1
  48. data/app/services/katello/applicable_host_queue.rb +21 -0
  49. data/app/services/katello/candlepin/message_handler.rb +2 -3
  50. data/app/services/katello/pulp/pulp_content_unit.rb +4 -0
  51. data/app/services/katello/pulp3/api/content_guard.rb +45 -0
  52. data/app/services/katello/pulp3/api/yum.rb +24 -0
  53. data/app/services/katello/pulp3/erratum.rb +4 -0
  54. data/app/services/katello/pulp3/pulp_content_unit.rb +4 -0
  55. data/app/services/katello/pulp3/repository.rb +29 -6
  56. data/app/services/katello/pulp3/repository/yum.rb +98 -3
  57. data/app/services/katello/pulp3/rpm.rb +3 -2
  58. data/app/services/katello/ui_notifications/subscriptions/manifest_expired_warning.rb +20 -8
  59. data/app/services/katello/upstream_connection_checker.rb +48 -0
  60. data/app/views/katello/api/v2/srpms/backend.json.rabl +11 -0
  61. data/app/views/katello/api/v2/srpms/base.json.rabl +5 -0
  62. data/app/views/katello/api/v2/srpms/compare.json.rabl +10 -0
  63. data/app/views/katello/api/v2/srpms/index.json.rabl +1 -1
  64. data/app/views/katello/api/v2/srpms/show.json.rabl +3 -3
  65. data/config/routes/api/v2.rb +2 -0
  66. data/db/migrate/20200407171926_create_content_guard.rb +10 -0
  67. data/db/migrate/20200511204005_create_katello_host_queue_elements.rb +12 -0
  68. data/db/migrate/20200526200422_encrypt_root_repository_upstream_password.rb +47 -0
  69. data/db/seeds.d/109-katello-notification-blueprints.rb +1 -1
  70. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-repository-sets.html +1 -1
  71. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-traces.html +1 -1
  72. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +1 -1
  73. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-version.factory.js +2 -2
  74. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +367 -450
  75. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +4046 -2509
  76. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +4277 -2503
  77. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +4372 -2591
  78. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +4013 -2500
  79. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +4127 -2630
  80. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +4024 -2530
  81. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +4492 -2766
  82. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +4293 -2667
  83. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +4072 -2460
  84. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +4004 -2442
  85. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +10 -10
  86. data/lib/katello/permission_creator.rb +1 -1
  87. data/lib/katello/version.rb +1 -1
  88. data/locale/action_names.rb +51 -43
  89. data/locale/bn/katello.po +4015 -2558
  90. data/locale/cs/katello.po +3756 -2221
  91. data/locale/de/katello.po +4303 -3044
  92. data/locale/en/katello.po +3137 -1558
  93. data/locale/es/katello.po +4280 -3012
  94. data/locale/fr/katello.po +4302 -3080
  95. data/locale/gu/katello.po +4034 -2584
  96. data/locale/hi/katello.po +4034 -2575
  97. data/locale/it/katello.po +4291 -3040
  98. data/locale/ja/katello.po +4345 -2863
  99. data/locale/katello.pot +2631 -1460
  100. data/locale/kn/katello.po +4033 -2585
  101. data/locale/ko/katello.po +4320 -2815
  102. data/locale/mr/katello.po +3971 -2506
  103. data/locale/or/katello.po +4018 -2559
  104. data/locale/pa/katello.po +3985 -2514
  105. data/locale/pt/katello.po +3358 -1810
  106. data/locale/pt_BR/katello.po +4252 -2959
  107. data/locale/ru/katello.po +4308 -2902
  108. data/locale/ta/katello.po +4012 -2562
  109. data/locale/te/katello.po +4046 -2585
  110. data/locale/zh_CN/katello.po +4344 -2803
  111. data/locale/zh_TW/katello.po +4470 -2957
  112. data/package.json +3 -3
  113. data/webpack/components/Content/ContentTable.js +2 -0
  114. data/webpack/components/Content/Details/ContentDetails.js +3 -0
  115. data/webpack/global_test_setup.js +3 -0
  116. data/webpack/scenes/AnsibleCollections/Details/AnsibleCollectionDetails.js +3 -0
  117. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +3 -0
  118. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +2 -0
  119. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +2 -0
  120. data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository/RepositorySetRepository.js +2 -0
  121. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailAssociations.js +2 -0
  122. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProductContent.js +2 -0
  123. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProducts.js +2 -0
  124. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +2 -0
  125. data/webpack/scenes/Subscriptions/SubscriptionActions.js +19 -21
  126. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +3 -1
  127. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +15 -1
  128. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +66 -9
  129. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +11 -0
  130. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +15 -1
  131. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/{UpstreamSubscriptionsContstants.js → UpstreamSubscriptionsConstants.js} +3 -0
  132. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -0
  133. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +1 -1
  134. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +1 -1
  135. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsActions.test.js +10 -34
  136. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +17 -7
  137. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -4
  138. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +6 -4
  139. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +26 -25
  140. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +0 -58
  141. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +10 -4
  142. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +1 -0
  143. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +1 -68
  144. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/UpdateDialog.js +1 -1
  145. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/index.js +4 -4
  146. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Table.js +12 -10
  147. data/webpack/scenes/Subscriptions/index.js +11 -4
  148. data/webpack/scenes/Tasks/TaskActions.js +2 -1
  149. data/webpack/test-utils/nockWrapper.js +1 -1
  150. metadata +54 -24
@@ -29,8 +29,8 @@
29
29
  "@storybook/storybook-deployer": "^2.0.0",
30
30
  "@testing-library/jest-dom": "^5.3.0",
31
31
  "@testing-library/react": "^10.0.2",
32
- "@theforeman/builder": "^4.2.0",
33
- "@theforeman/vendor-dev": "^4.2.0",
32
+ "@theforeman/builder": "4.3.0",
33
+ "@theforeman/vendor-dev": "4.3.0",
34
34
  "axios-mock-adapter": "^1.10.0",
35
35
  "babel-eslint": "^10.0.3",
36
36
  "babel-jest": "^24.9.0",
@@ -56,8 +56,8 @@
56
56
  "react-test-renderer": "^16.0.0",
57
57
  "redux-mock-store": "^1.3.0"
58
58
  },
59
- "_comment": "We don't include @theforeman/vendor because it's assumed to be present in Foreman",
60
59
  "dependencies": {
60
+ "@theforeman/vendor-core": "4.3.0",
61
61
  "@patternfly/react-icons": "^3.15.15",
62
62
  "@patternfly/react-tokens": "^2.8.13",
63
63
  "angular": "1.7.9",
@@ -34,6 +34,8 @@ const ContentTable = ({ content, tableSchema, onPaginationChange }) => {
34
34
  ContentTable.propTypes = {
35
35
  content: PropTypes.shape({
36
36
  loading: PropTypes.bool,
37
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
38
+ // eslint-disable-next-line react/forbid-prop-types
37
39
  results: PropTypes.array,
38
40
  pagination: PropTypes.shape({}),
39
41
  itemCount: PropTypes.number,
@@ -59,9 +59,12 @@ ContentDetails.propTypes = {
59
59
  contentDetails: PropTypes.shape({
60
60
  loading: PropTypes.bool,
61
61
  name: PropTypes.string,
62
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
63
+ /* eslint-disable react/forbid-prop-types */
62
64
  profiles: PropTypes.array,
63
65
  repositories: PropTypes.array,
64
66
  artifacts: PropTypes.array,
67
+ /* eslint-enable react/forbid-prop-types */
65
68
  stream: PropTypes.string,
66
69
  }).isRequired,
67
70
  schema: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
@@ -4,3 +4,6 @@
4
4
  global.console.error = (error) => {
5
5
  throw new Error(error);
6
6
  };
7
+
8
+ // Increase jest timeout as some tests using multiple http mocks can time out on CI systems.
9
+ jest.setTimeout(10000);
@@ -83,8 +83,11 @@ AnsibleCollectionDetails.propTypes = {
83
83
  name: PropTypes.string,
84
84
  namespace: PropTypes.string,
85
85
  version: PropTypes.string,
86
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
87
+ /* eslint-disable react/forbid-prop-types */
86
88
  repositories: PropTypes.array,
87
89
  tags: PropTypes.array,
90
+ /* eslint-enable react/forbid-prop-types */
88
91
  }).isRequired,
89
92
  };
90
93
 
@@ -81,9 +81,12 @@ ModuleStreamDetails.propTypes = {
81
81
  moduleStreamDetails: PropTypes.shape({
82
82
  loading: PropTypes.bool,
83
83
  name: PropTypes.string,
84
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
85
+ /* eslint-disable react/forbid-prop-types */
84
86
  profiles: PropTypes.array,
85
87
  repositories: PropTypes.array,
86
88
  artifacts: PropTypes.array,
89
+ /* eslint-enable react/forbid-prop-types */
87
90
  stream: PropTypes.string,
88
91
  }).isRequired,
89
92
  };
@@ -111,6 +111,8 @@ RedHatRepositoriesPage.propTypes = {
111
111
  recommended: PropTypes.bool,
112
112
  loading: PropTypes.bool,
113
113
  search: PropTypes.shape({}),
114
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
115
+ // eslint-disable-next-line react/forbid-prop-types
114
116
  missingPermissions: PropTypes.array,
115
117
  }).isRequired,
116
118
  };
@@ -94,6 +94,8 @@ EnabledRepository.propTypes = {
94
94
  search: PropTypes.shape({
95
95
  query: PropTypes.string,
96
96
  searchList: PropTypes.string,
97
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
98
+ // eslint-disable-next-line react/forbid-prop-types
97
99
  filters: PropTypes.array,
98
100
  }),
99
101
  pagination: PropTypes.shape({
@@ -141,6 +141,8 @@ RepositorySetRepository.propTypes = {
141
141
  enabledSearch: PropTypes.shape({
142
142
  query: PropTypes.string,
143
143
  searchList: PropTypes.string,
144
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
145
+ // eslint-disable-next-line react/forbid-prop-types
144
146
  filters: PropTypes.array,
145
147
  }),
146
148
  enabledPagination: PropTypes.shape({
@@ -45,6 +45,8 @@ SubscriptionDetailAssociations.propTypes = {
45
45
  subscriptionDetails: PropTypes.shape({
46
46
  id: PropTypes.number,
47
47
  host_count: PropTypes.number,
48
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
49
+ // eslint-disable-next-line react/forbid-prop-types
48
50
  activation_keys: PropTypes.array,
49
51
  }).isRequired,
50
52
  };
@@ -50,6 +50,8 @@ const SubscriptionDetailProductContent = ({ productContent }) => {
50
50
 
51
51
  SubscriptionDetailProductContent.propTypes = {
52
52
  productContent: PropTypes.shape({
53
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
54
+ // eslint-disable-next-line react/forbid-prop-types
53
55
  results: PropTypes.array,
54
56
  }).isRequired,
55
57
  };
@@ -18,6 +18,8 @@ const SubscriptionDetailProducts = ({ subscriptionDetails }) => (
18
18
 
19
19
  SubscriptionDetailProducts.propTypes = {
20
20
  subscriptionDetails: PropTypes.shape({
21
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
22
+ // eslint-disable-next-line react/forbid-prop-types
21
23
  provided_products: PropTypes.array,
22
24
  }).isRequired,
23
25
  };
@@ -352,6 +352,8 @@ ManageManifestModal.propTypes = {
352
352
  simpleContentAccess: PropTypes.bool,
353
353
  manifestHistory: PropTypes.shape({
354
354
  loading: PropTypes.bool,
355
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
356
+ // eslint-disable-next-line react/forbid-prop-types
355
357
  results: PropTypes.array,
356
358
  }).isRequired,
357
359
  setModalClosed: PropTypes.func.isRequired,
@@ -28,8 +28,9 @@ import {
28
28
  SUBSCRIPTIONS_ENABLE_DELETE_BUTTON,
29
29
  BLOCKING_FOREMAN_TASK_TYPES,
30
30
  SUBSCRIPTIONS_RESET_TASKS,
31
+ MANIFEST_DELETE_TASK_LABEL,
31
32
  } from './SubscriptionConstants';
32
- import { filterRHSubscriptions, selectSubscriptionsQuantitiesFromResponse } from './SubscriptionHelpers.js';
33
+ import { selectSubscriptionsQuantitiesFromResponse } from './SubscriptionHelpers.js';
33
34
  import { apiError } from '../../move_to_foreman/common/helpers.js';
34
35
  import {
35
36
  startPollingTask,
@@ -38,7 +39,8 @@ import {
38
39
  stopPollingTasks,
39
40
  toastTaskFinished,
40
41
  } from '../Tasks/TaskActions';
41
- import { selectIsPollingTasks, selectIsPollingTask } from '../Tasks/TaskSelectors';
42
+ import { selectIsPollingTasks } from '../Tasks/TaskSelectors';
43
+ import { pingUpstreamSubscriptions } from './UpstreamSubscriptions/UpstreamSubscriptionsActions';
42
44
 
43
45
  export const createSubscriptionParams = (extendedParams = {}) => ({
44
46
  ...{
@@ -51,10 +53,8 @@ export const createSubscriptionParams = (extendedParams = {}) => ({
51
53
  export const loadAvailableQuantities = (extendedParams = {}) => async (dispatch) => {
52
54
  dispatch({ type: SUBSCRIPTIONS_QUANTITIES_REQUEST });
53
55
 
54
- const params = createSubscriptionParams(extendedParams);
55
-
56
56
  try {
57
- const { data } = await api.get(`/organizations/${orgId()}/upstream_subscriptions`, {}, params);
57
+ const { data } = await api.get(`/organizations/${orgId()}/upstream_subscriptions`, {}, propsToSnakeCase(extendedParams));
58
58
  return dispatch({
59
59
  type: SUBSCRIPTIONS_QUANTITIES_SUCCESS,
60
60
  payload: selectSubscriptionsQuantitiesFromResponse(data),
@@ -76,10 +76,6 @@ export const loadSubscriptions = (extendedParams = {}) => async (dispatch) => {
76
76
  response: data,
77
77
  search: extendedParams.search,
78
78
  });
79
- const poolIds = filterRHSubscriptions(data.results).map(subs => subs.id);
80
- if (poolIds.length > 0) {
81
- dispatch(loadAvailableQuantities({ poolIds }));
82
- }
83
79
  return result;
84
80
  } catch (error) {
85
81
  return dispatch(apiError(SUBSCRIPTIONS_FAILURE, error));
@@ -104,21 +100,23 @@ export const resetTasks = () => (dispatch) => {
104
100
  });
105
101
  };
106
102
 
107
- export const handleTask = task => async (dispatch, getState) => {
108
- if (selectIsPollingTask(getState(), SUBSCRIPTIONS)) {
109
- if (!task.pending) {
110
- dispatch(stopPollingTask(SUBSCRIPTIONS));
111
- dispatch(toastTaskFinished(task));
112
- dispatch(resetTasks());
113
- dispatch(pollTasks());
114
- dispatch(loadSubscriptions());
115
- }
116
- } else {
117
- dispatch(cancelPollTasks());
118
- dispatch(startPollingTask(SUBSCRIPTIONS, task));
103
+ export const handleFinishedTask = task => (dispatch) => {
104
+ dispatch(stopPollingTask(SUBSCRIPTIONS));
105
+ dispatch(toastTaskFinished(task));
106
+ dispatch(resetTasks());
107
+ dispatch(pollTasks());
108
+ dispatch(loadSubscriptions());
109
+
110
+ if (task.label !== MANIFEST_DELETE_TASK_LABEL) {
111
+ dispatch(pingUpstreamSubscriptions());
119
112
  }
120
113
  };
121
114
 
115
+ export const handleStartTask = task => (dispatch) => {
116
+ dispatch(cancelPollTasks());
117
+ dispatch(startPollingTask(SUBSCRIPTIONS, task));
118
+ };
119
+
122
120
  export const updateQuantity = (quantities = {}) => async (dispatch) => {
123
121
  dispatch({ type: UPDATE_QUANTITY_REQUEST });
124
122
 
@@ -37,10 +37,12 @@ export const SUBSCRIPTIONS_CLOSE_DELETE_MODAL = 'SUBSCRIPTIONS_CLOSE_DELETE_MODA
37
37
  export const SUBSCRIPTIONS_DISABLE_DELETE_BUTTON = 'SUBSCRIPTIONS_DISABLE_DELETE_BUTTON';
38
38
  export const SUBSCRIPTIONS_ENABLE_DELETE_BUTTON = 'SUBSCRIPTIONS_ENABLE_DELETE_BUTTON';
39
39
 
40
+ export const MANIFEST_DELETE_TASK_LABEL = 'Actions::Katello::Organization::ManifestDelete';
41
+
40
42
  export const BLOCKING_FOREMAN_TASK_TYPES = [
41
43
  'Actions::Katello::Organization::ManifestImport',
42
44
  'Actions::Katello::Organization::ManifestRefresh',
43
- 'Actions::Katello::Organization::ManifestDelete',
45
+ MANIFEST_DELETE_TASK_LABEL,
44
46
  'Actions::Katello::UpstreamSubscriptions::BindEntitlements',
45
47
  'Actions::Katello::UpstreamSubscriptions::UpdateEntitlement',
46
48
  'Actions::Katello::UpstreamSubscriptions::RemoveEntitlements',
@@ -32,9 +32,13 @@ import {
32
32
  REFRESH_MANIFEST_SUCCESS,
33
33
  } from './Manifest/ManifestConstants';
34
34
 
35
+ import {
36
+ PING_UPSTREAM_SUBSCRIPTIONS_SUCCESS,
37
+ PING_UPSTREAM_SUBSCRIPTIONS_FAILURE,
38
+ } from './UpstreamSubscriptions/UpstreamSubscriptionsConstants';
39
+
35
40
  const initialState = Immutable({
36
41
  ...initialApiState,
37
- disconnected: false,
38
42
  searchQuery: '',
39
43
  deleteModalOpened: false,
40
44
  deleteButtonDisabled: true,
@@ -43,10 +47,15 @@ const initialState = Immutable({
43
47
  task: null,
44
48
  tableColumns: [],
45
49
  selectedTableColumns: [],
50
+ hasUpstreamConnection: false,
46
51
  });
47
52
 
48
53
  export default (state = initialState, action) => {
49
54
  switch (action.type) {
55
+ case PING_UPSTREAM_SUBSCRIPTIONS_SUCCESS:
56
+ return state.set('hasUpstreamConnection', true);
57
+ case PING_UPSTREAM_SUBSCRIPTIONS_FAILURE:
58
+ return state.set('hasUpstreamConnection', false);
50
59
  case SUBSCRIPTIONS_REQUEST:
51
60
  return state.set('loading', true);
52
61
  case SUBSCRIPTIONS_COLUMNS_REQUEST:
@@ -130,6 +139,11 @@ export default (state = initialState, action) => {
130
139
  }
131
140
 
132
141
  case DELETE_MANIFEST_SUCCESS:
142
+ return state.merge({
143
+ task: action.response,
144
+ hasUpstreamConnection: false,
145
+ });
146
+
133
147
  case UPLOAD_MANIFEST_SUCCESS:
134
148
  case REFRESH_MANIFEST_SUCCESS:
135
149
  case UPDATE_QUANTITY_SUCCESS:
@@ -11,7 +11,7 @@ import ManageManifestModal from './Manifest/';
11
11
  import { MANAGE_MANIFEST_MODAL_ID } from './Manifest/ManifestConstants';
12
12
  import { SubscriptionsTable } from './components/SubscriptionsTable';
13
13
  import SubscriptionsToolbar from './components/SubscriptionsToolbar';
14
- import { manifestExists } from './SubscriptionHelpers';
14
+ import { filterRHSubscriptions, manifestExists } from './SubscriptionHelpers';
15
15
  import api, { orgId } from '../../services/api';
16
16
 
17
17
  import { createSubscriptionParams } from './SubscriptionActions.js';
@@ -25,6 +25,7 @@ class SubscriptionsPage extends Component {
25
25
  super(props);
26
26
  this.state = {
27
27
  selectedRows: [],
28
+ availableQuantitiesLoaded: false,
28
29
  };
29
30
  }
30
31
 
@@ -39,17 +40,52 @@ class SubscriptionsPage extends Component {
39
40
 
40
41
  componentDidUpdate(prevProps) {
41
42
  const {
42
- organization, task, handleTask,
43
+ handleStartTask,
44
+ handleFinishedTask,
45
+ isTaskPending,
46
+ isPollingTask,
47
+ hasUpstreamConnection,
48
+ loadAvailableQuantities,
49
+ organization,
50
+ pingUpstreamSubscriptions,
51
+ subscriptions,
52
+ task,
43
53
  } = this.props;
44
54
 
55
+ const { disconnected } = subscriptions;
56
+
45
57
  if (task) {
46
- handleTask(task);
58
+ if (isPollingTask) {
59
+ if (prevProps.isTaskPending && !isTaskPending) {
60
+ handleFinishedTask(task);
61
+ }
62
+ } else {
63
+ handleStartTask(task);
64
+ }
47
65
  }
48
66
 
49
67
  if (organization) {
50
68
  if (!prevProps.organization || prevProps.organization.id !== organization.id) {
51
69
  this.loadData();
52
70
  }
71
+
72
+ if (disconnected === false && disconnected !== prevProps.subscriptions.disconnected) {
73
+ if (manifestExists(organization)) {
74
+ pingUpstreamSubscriptions();
75
+ this.state.availableQuantitiesLoaded = false;
76
+ }
77
+ }
78
+ }
79
+
80
+ if (hasUpstreamConnection) {
81
+ const subscriptionsChanged = subscriptions.results !== prevProps.subscriptions.results;
82
+ if (subscriptionsChanged || !this.state.availableQuantitiesLoaded) {
83
+ const poolIds = filterRHSubscriptions(subscriptions.results).map(subs => subs.id);
84
+ if (poolIds.length > 0) {
85
+ loadAvailableQuantities({ poolIds });
86
+ this.state.availableQuantitiesLoaded = true;
87
+ }
88
+ }
53
89
  }
54
90
  }
55
91
 
@@ -58,7 +94,12 @@ class SubscriptionsPage extends Component {
58
94
  }
59
95
 
60
96
  getDisabledReason(deleteButton) {
61
- const { task, subscriptions, organization } = this.props;
97
+ const {
98
+ hasUpstreamConnection,
99
+ task,
100
+ subscriptions,
101
+ organization,
102
+ } = this.props;
62
103
  const { disconnected } = subscriptions;
63
104
  let disabledReason = null;
64
105
 
@@ -70,6 +111,8 @@ class SubscriptionsPage extends Component {
70
111
  disabledReason = __('This is disabled because no subscriptions are selected.');
71
112
  } else if (!manifestExists(organization)) {
72
113
  disabledReason = __('This is disabled because no manifest has been uploaded.');
114
+ } else if (!hasUpstreamConnection) {
115
+ disabledReason = __('This is disabled because no connection could be made to the upstream Subscription Allocation.');
73
116
  }
74
117
 
75
118
  return disabledReason;
@@ -101,8 +144,8 @@ class SubscriptionsPage extends Component {
101
144
  const {
102
145
  deleteModalOpened, openDeleteModal, closeDeleteModal,
103
146
  deleteButtonDisabled, disableDeleteButton, enableDeleteButton,
104
- searchQuery, updateSearchQuery, simpleContentAccess,
105
- task, activePermissions, subscriptions, organization, subscriptionTableSettings,
147
+ searchQuery, updateSearchQuery, simpleContentAccess, hasUpstreamConnection,
148
+ task, activePermissions, subscriptions, subscriptionTableSettings,
106
149
  } = this.props;
107
150
  // Basic permissions - should we even show this page?
108
151
  if (subscriptions.missingPermissions && subscriptions.missingPermissions.length > 0) {
@@ -117,7 +160,7 @@ class SubscriptionsPage extends Component {
117
160
  canEditOrganizations,
118
161
  } = permissions;
119
162
  const { disconnected } = subscriptions;
120
- const disableManifestActions = !!task || disconnected;
163
+ const disableManifestActions = !!task || disconnected || !hasUpstreamConnection;
121
164
 
122
165
  const openManageManifestModal = () => this.props.setModalOpen({ id: MANAGE_MANIFEST_MODAL_ID });
123
166
 
@@ -194,7 +237,7 @@ class SubscriptionsPage extends Component {
194
237
  disableManifestReason={this.getDisabledReason()}
195
238
  disableDeleteButton={deleteButtonDisabled}
196
239
  disableDeleteReason={this.getDisabledReason(true)}
197
- disableAddButton={!manifestExists(organization)}
240
+ disableAddButton={disableManifestActions}
198
241
  getAutoCompleteParams={getAutoCompleteParams}
199
242
  updateSearchQuery={updateSearchQuery}
200
243
  onDeleteButtonClick={openDeleteModal}
@@ -240,6 +283,7 @@ class SubscriptionsPage extends Component {
240
283
  task={task}
241
284
  selectedRows={this.state.selectedRows}
242
285
  onSelectedRowsChange={this.handleSelectedRowsChange}
286
+ selectionEnabled={!disableManifestActions}
243
287
  />
244
288
  <ModalProgressBar
245
289
  show={!!task}
@@ -256,7 +300,9 @@ class SubscriptionsPage extends Component {
256
300
  }
257
301
 
258
302
  SubscriptionsPage.propTypes = {
303
+ pingUpstreamSubscriptions: PropTypes.func.isRequired,
259
304
  loadSubscriptions: PropTypes.func.isRequired,
305
+ loadAvailableQuantities: PropTypes.func.isRequired,
260
306
  uploadManifest: PropTypes.func.isRequired,
261
307
  deleteManifest: PropTypes.func.isRequired,
262
308
  resetTasks: PropTypes.func.isRequired,
@@ -265,9 +311,13 @@ SubscriptionsPage.propTypes = {
265
311
  simpleContentAccess: PropTypes.bool,
266
312
  subscriptions: PropTypes.shape({
267
313
  disconnected: PropTypes.bool,
314
+ // Disabling rule as existing code failed due to an eslint-plugin-react update
315
+ /* eslint-disable react/forbid-prop-types */
268
316
  tableColumns: PropTypes.array,
269
317
  selectedTableColumns: PropTypes.array,
270
318
  missingPermissions: PropTypes.array,
319
+ results: PropTypes.array,
320
+ /* eslint-enable react/forbid-prop-types */
271
321
  }).isRequired,
272
322
  activePermissions: PropTypes.shape({
273
323
  can_delete_manifest: PropTypes.bool,
@@ -291,9 +341,13 @@ SubscriptionsPage.propTypes = {
291
341
  }),
292
342
  pending: PropTypes.bool,
293
343
  }),
344
+ isTaskPending: PropTypes.bool,
345
+ isPollingTask: PropTypes.bool,
294
346
  pollTasks: PropTypes.func.isRequired,
295
347
  cancelPollTasks: PropTypes.func.isRequired,
296
- handleTask: PropTypes.func.isRequired,
348
+ handleStartTask: PropTypes.func.isRequired,
349
+ handleFinishedTask: PropTypes.func.isRequired,
350
+ hasUpstreamConnection: PropTypes.bool,
297
351
  loadSetting: PropTypes.func.isRequired,
298
352
  loadTables: PropTypes.func.isRequired,
299
353
  createColumns: PropTypes.func.isRequired,
@@ -314,12 +368,15 @@ SubscriptionsPage.propTypes = {
314
368
 
315
369
  SubscriptionsPage.defaultProps = {
316
370
  task: undefined,
371
+ isTaskPending: undefined,
372
+ isPollingTask: undefined,
317
373
  organization: undefined,
318
374
  searchQuery: '',
319
375
  deleteModalOpened: false,
320
376
  deleteButtonDisabled: true,
321
377
  subscriptionTableSettings: {},
322
378
  simpleContentAccess: false,
379
+ hasUpstreamConnection: false,
323
380
  activePermissions: {
324
381
  can_import_manifest: false,
325
382
  can_manage_subscription_allocations: false,