katello 4.19.0.rc1 → 4.19.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +337 -16
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +337 -16
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +337 -16
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +338 -17
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +337 -16
  7. data/app/assets/javascripts/katello/locale/de/katello.js +339 -18
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +337 -16
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +337 -16
  10. data/app/assets/javascripts/katello/locale/el/katello.js +337 -16
  11. data/app/assets/javascripts/katello/locale/en/katello.js +338 -17
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +337 -16
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +337 -16
  14. data/app/assets/javascripts/katello/locale/es/katello.js +337 -16
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +337 -16
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +340 -19
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +337 -16
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +337 -16
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +337 -16
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +337 -16
  21. data/app/assets/javascripts/katello/locale/id/katello.js +337 -16
  22. data/app/assets/javascripts/katello/locale/it/katello.js +337 -16
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +340 -19
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +339 -18
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +337 -16
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +339 -18
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +337 -16
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +337 -16
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +337 -16
  30. data/app/assets/javascripts/katello/locale/or/katello.js +337 -16
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +337 -16
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +337 -16
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +337 -16
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +337 -16
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +337 -16
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +337 -16
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +337 -16
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +337 -16
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +337 -16
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +337 -16
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +337 -16
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +337 -16
  43. data/app/assets/javascripts/katello/locale/te/katello.js +337 -16
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +337 -16
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +337 -16
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +337 -16
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +337 -16
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +340 -19
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +337 -16
  50. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +10 -0
  51. data/app/lib/actions/katello/repository/metadata_generate.rb +16 -1
  52. data/app/models/katello/authorization/repository.rb +4 -13
  53. data/app/services/katello/pulp3/repository/apt.rb +14 -6
  54. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn.po +10 -0
  55. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn_IN.po +10 -0
  56. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ca.po +10 -0
  57. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/cs_CZ.po +10 -0
  58. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +10 -0
  59. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_AT.po +10 -0
  60. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_DE.po +10 -0
  61. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +10 -0
  62. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_GB.po +10 -0
  63. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_US.po +10 -0
  64. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +10 -0
  65. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/et_EE.po +10 -0
  66. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +10 -0
  67. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gl.po +10 -0
  68. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gu.po +10 -0
  69. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/he_IL.po +10 -0
  70. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/hi.po +10 -0
  71. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/id.po +10 -0
  72. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +10 -0
  73. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +10 -0
  74. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ka.po +10 -0
  75. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/kn.po +10 -0
  76. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +10 -0
  77. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ml_IN.po +10 -0
  78. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/mr.po +10 -0
  79. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/nl_NL.po +10 -0
  80. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/or.po +10 -0
  81. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pa.po +10 -0
  82. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl.po +10 -0
  83. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl_PL.po +10 -0
  84. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt.po +10 -0
  85. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +10 -0
  86. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro.po +10 -0
  87. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro_RO.po +10 -0
  88. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +10 -0
  89. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sl.po +10 -0
  90. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sv_SE.po +10 -0
  91. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta.po +10 -0
  92. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta_IN.po +10 -0
  93. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/te.po +10 -0
  94. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/tr.po +10 -0
  95. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi.po +10 -0
  96. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi_VN.po +10 -0
  97. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh.po +10 -0
  98. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +10 -0
  99. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +10 -0
  100. data/lib/katello/plugin.rb +1 -0
  101. data/lib/katello/version.rb +1 -1
  102. data/locale/action_names.rb +180 -0
  103. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  104. data/locale/bn/katello.po +337 -16
  105. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  106. data/locale/bn_IN/katello.po +337 -16
  107. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  108. data/locale/ca/katello.po +337 -16
  109. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  110. data/locale/cs/katello.po +338 -18
  111. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  112. data/locale/cs_CZ/katello.po +337 -16
  113. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  114. data/locale/de/katello.po +340 -19
  115. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  116. data/locale/de_AT/katello.po +337 -16
  117. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  118. data/locale/de_DE/katello.po +337 -16
  119. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  120. data/locale/el/katello.po +337 -16
  121. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  122. data/locale/en/katello.po +338 -18
  123. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  124. data/locale/en_GB/katello.po +337 -16
  125. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  126. data/locale/en_US/katello.po +337 -16
  127. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  128. data/locale/es/katello.po +337 -16
  129. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  130. data/locale/et_EE/katello.po +337 -16
  131. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  132. data/locale/fr/katello.po +341 -20
  133. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  134. data/locale/gl/katello.po +337 -16
  135. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  136. data/locale/gu/katello.po +337 -16
  137. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  138. data/locale/he_IL/katello.po +337 -16
  139. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  140. data/locale/hi/katello.po +337 -16
  141. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  142. data/locale/id/katello.po +337 -16
  143. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  144. data/locale/it/katello.po +337 -16
  145. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  146. data/locale/ja/katello.po +342 -20
  147. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  148. data/locale/ka/katello.po +339 -18
  149. data/locale/katello.pot +811 -296
  150. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  151. data/locale/kn/katello.po +337 -16
  152. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  153. data/locale/ko/katello.po +340 -19
  154. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  155. data/locale/ml_IN/katello.po +337 -16
  156. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  157. data/locale/mr/katello.po +337 -16
  158. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  159. data/locale/nl_NL/katello.po +337 -16
  160. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  161. data/locale/or/katello.po +337 -16
  162. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  163. data/locale/pa/katello.po +337 -16
  164. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  165. data/locale/pl/katello.po +337 -16
  166. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  167. data/locale/pl_PL/katello.po +337 -16
  168. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  169. data/locale/pt/katello.po +337 -16
  170. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  171. data/locale/pt_BR/katello.po +337 -16
  172. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  173. data/locale/ro/katello.po +337 -16
  174. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  175. data/locale/ro_RO/katello.po +337 -16
  176. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  177. data/locale/ru/katello.po +337 -16
  178. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  179. data/locale/sl/katello.po +337 -16
  180. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  181. data/locale/sv_SE/katello.po +337 -16
  182. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  183. data/locale/ta/katello.po +337 -16
  184. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  185. data/locale/ta_IN/katello.po +337 -16
  186. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  187. data/locale/te/katello.po +337 -16
  188. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  189. data/locale/tr/katello.po +337 -16
  190. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  191. data/locale/vi/katello.po +337 -16
  192. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  193. data/locale/vi_VN/katello.po +337 -16
  194. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  195. data/locale/zh/katello.po +337 -16
  196. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  197. data/locale/zh_CN/katello.po +341 -20
  198. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  199. data/locale/zh_TW/katello.po +337 -16
  200. data/webpack/ForemanColumnExtensions/index.js +46 -2
  201. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/02_BulkErrataTable.js +1 -1
  202. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +1 -1
  203. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js +1 -1
  204. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +1 -1
  205. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +15 -5
  206. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +22 -5
  207. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +141 -0
  208. metadata +22 -24
@@ -12,6 +12,7 @@ import {
12
12
  FlexItem,
13
13
  Popover,
14
14
  Badge,
15
+ Button,
15
16
  DescriptionList,
16
17
  DescriptionListGroup,
17
18
  DescriptionListDescription as Dd,
@@ -206,9 +207,9 @@ const hostsIndexColumnExtensions = [
206
207
  </Flex>
207
208
  }
208
209
  >
209
- <FlexItem>
210
+ <Button variant="plain" style={{ padding: 0, color: 'inherit' }} ouiaId="content-view-environments-button">
210
211
  {truncate(contentViewEnvironments.map(cve => cve.label).join(', '), 35)}
211
- </FlexItem>
212
+ </Button>
212
213
  </Popover>
213
214
  </Flex>
214
215
  );
@@ -237,6 +238,49 @@ const hostsIndexColumnExtensions = [
237
238
  weight: 2600,
238
239
  isSorted: true,
239
240
  },
241
+ {
242
+ columnName: 'host_collections',
243
+ title: __('Host collections'),
244
+ wrapper: (hostDetails) => {
245
+ const hostCollections = hostDetails?.host_collections ?? [];
246
+ if (hostCollections.length === 0) return '—';
247
+
248
+ // Show count badge if more than one collection
249
+ if (hostCollections.length > 1) {
250
+ return (
251
+ <Flex>
252
+ <FlexItem>
253
+ <Badge isRead>{hostCollections.length}</Badge>
254
+ </FlexItem>
255
+ <Popover
256
+ id="host-collections-tooltip"
257
+ className="host-collections-tooltip"
258
+ maxWidth="34rem"
259
+ headerContent={hostDetails.display_name}
260
+ bodyContent={
261
+ <Flex direction={{ default: 'column' }}>
262
+ {hostCollections.map((hc, index) => (
263
+ <FlexItem key={hc.id}>
264
+ <Text component={TextVariants.p} ouiaId={`host-collection-name-${index}`}>{hc.name}</Text>
265
+ </FlexItem>
266
+ ))}
267
+ </Flex>
268
+ }
269
+ >
270
+ <Button variant="plain" style={{ padding: 0, color: 'inherit' }} ouiaId="host-collections-button">
271
+ {truncate(hostCollections.map(hc => hc.name).join(', '), 35)}
272
+ </Button>
273
+ </Popover>
274
+ </Flex>
275
+ );
276
+ }
277
+
278
+ // Just show the name if only one collection
279
+ return truncate(hostCollections[0].name, 35);
280
+ },
281
+ weight: 2700,
282
+ isSorted: false,
283
+ },
240
284
  ];
241
285
 
242
286
  hostsIndexColumnExtensions.forEach((column) => {
@@ -11,7 +11,7 @@ import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableInde
11
11
  import { translate as __ } from 'foremanReact/common/I18n';
12
12
  import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
13
13
  import { STATUS, getControllerSearchProps } from 'foremanReact/constants';
14
- import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
14
+ import { RowSelectTd } from 'foremanReact/components/PF4/TableIndexPage/RowSelectTd';
15
15
  import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
16
16
  import { BulkErrataWizardContext, ERRATA_URL } from './BulkErrataWizard';
17
17
  import { ErrataType, ErrataSeverity } from '../../../../../components/Errata';
@@ -12,7 +12,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
12
12
  import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
13
13
  import { getControllerSearchProps } from 'foremanReact/constants';
14
14
  import { noop } from 'foremanReact/common/helpers';
15
- import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
15
+ import { RowSelectTd } from 'foremanReact/components/PF4/TableIndexPage/RowSelectTd';
16
16
  import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
17
17
  import { BulkPackagesWizardContext, getPackagesUrl } from './BulkPackagesWizard';
18
18
  import katelloApi from '../../../../../services/api';
@@ -14,7 +14,7 @@ import { useSet } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHo
14
14
  import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
15
15
  import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
16
16
  import { translate as __ } from 'foremanReact/common/I18n';
17
- import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
17
+ import { RowSelectTd } from 'foremanReact/components/PF4/TableIndexPage/RowSelectTd';
18
18
  import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
19
19
  import { noop } from 'foremanReact/common/helpers';
20
20
 
@@ -11,7 +11,7 @@ import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableInde
11
11
  import { HOSTS_API_PATH } from 'foremanReact/routes/Hosts/constants';
12
12
  import { translate as __ } from 'foremanReact/common/I18n';
13
13
  import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
14
- import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
14
+ import { RowSelectTd } from 'foremanReact/components/PF4/TableIndexPage/RowSelectTd';
15
15
  import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
16
16
 
17
17
  const HostReview = ({
@@ -115,15 +115,25 @@ export default (state = initialState, action) => {
115
115
  });
116
116
  }
117
117
 
118
- case SUBSCRIPTIONS_FAILURE:
118
+ case SUBSCRIPTIONS_FAILURE: {
119
+ // Try multiple paths to extract permission errors
120
+ const explicitMissingPermissions = get(action, ['payload', 'messages', 0, 'missing_permissions']);
121
+ const statusCode = get(action, ['payload', 'result', 'response', 'status']);
122
+ const errorMessages = get(action, ['payload', 'messages'], []);
123
+
124
+ // If we got a 403 Forbidden or 404 Not Found, treat it as a permission error
125
+ let missingPermissions = explicitMissingPermissions;
126
+ if (!missingPermissions && (statusCode === 403 || statusCode === 404)) {
127
+ // Use error messages as missing permissions
128
+ missingPermissions = errorMessages.length > 0 ? errorMessages : ['view_subscriptions'];
129
+ }
130
+
119
131
  return state
120
132
  .set('loading', false)
121
133
  .set('results', [])
122
134
  .set('itemCount', 0)
123
- .set(
124
- 'missingPermissions',
125
- get(action, ['payload', 'messages', 0, 'missing_permissions']),
126
- );
135
+ .set('missingPermissions', missingPermissions);
136
+ }
127
137
 
128
138
  case SUBSCRIPTIONS_QUANTITIES_REQUEST:
129
139
  return state.merge({
@@ -32,11 +32,9 @@ class SubscriptionsPage extends Component {
32
32
 
33
33
  componentDidMount() {
34
34
  this.props.resetTasks();
35
-
36
- const { id } = this.props.organization;
37
- if (id) { // navigating from another react page
38
- this.loadData();
39
- }
35
+ // Always load data, even if organization doesn't have an ID yet
36
+ // This allows us to detect permission errors
37
+ this.loadData();
40
38
  }
41
39
 
42
40
  componentDidUpdate(prevProps) {
@@ -137,7 +135,21 @@ class SubscriptionsPage extends Component {
137
135
  deleteButtonDisabled, disableDeleteButton, enableDeleteButton,
138
136
  searchQuery, updateSearchQuery, hasUpstreamConnection,
139
137
  task, activePermissions, subscriptions, subscriptionTableSettings, isManifestImported,
138
+ organization,
140
139
  } = this.props;
140
+
141
+ // If organization failed to load (404/403), the user doesn't have
142
+ // permission to view this organization. Show permission denied
143
+ // regardless of whether subscriptions returned results
144
+ if (organization?.error && !organization.loading) {
145
+ const statusCode = organization.error.response?.status;
146
+
147
+ if (statusCode === 404 || statusCode === 403) {
148
+ const errorMessage = 'You do not have permission to view this organization.';
149
+ return <PermissionDenied missingPermissions={[errorMessage]} />;
150
+ }
151
+ }
152
+
141
153
  // Basic permissions - should we even show this page?
142
154
  if (subscriptions.missingPermissions && subscriptions.missingPermissions.length > 0) {
143
155
  return <PermissionDenied missingPermissions={subscriptions.missingPermissions} />;
@@ -345,6 +357,11 @@ SubscriptionsPage.propTypes = {
345
357
  uuid: PropTypes.string,
346
358
  }),
347
359
  }),
360
+ error: PropTypes.shape({
361
+ response: PropTypes.shape({
362
+ status: PropTypes.number,
363
+ }),
364
+ }),
348
365
  }),
349
366
  task: PropTypes.shape({
350
367
  id: PropTypes.string,
@@ -106,6 +106,147 @@ describe('subscriptions page', () => {
106
106
  expect(toJson(permissionDeniedPage)).toMatchSnapshot();
107
107
  });
108
108
 
109
+ it('should render <PermissionDenied /> when organization load fails with 403', async () => {
110
+ const orgWith403Error = {
111
+ loading: false,
112
+ error: {
113
+ response: {
114
+ status: 403,
115
+ },
116
+ },
117
+ };
118
+ const pageWithOrgError = shallow(<SubscriptionsPage
119
+ setModalOpen={noop}
120
+ setModalClosed={noop}
121
+ organization={orgWith403Error}
122
+ subscriptions={successState}
123
+ subscriptionTableSettings={settingsSuccessState}
124
+ loadTables={loadTables}
125
+ loadTableColumns={loadTableColumns}
126
+ createColumns={createColumns}
127
+ updateColumns={updateColumns}
128
+ loadSubscriptions={loadSubscriptions}
129
+ loadAvailableQuantities={loadAvailableQuantities}
130
+ pingUpstreamSubscriptions={pingUpstreamSubscriptions}
131
+ checkSimpleContentAccessEligible={checkSimpleContentAccessEligible}
132
+ updateQuantity={updateQuantity}
133
+ handleStartTask={handleStartTask}
134
+ handleFinishedTask={handleFinishedTask}
135
+ pollTaskUntilDone={noop}
136
+ pollBulkSearch={noop}
137
+ pollTasks={pollTasks}
138
+ cancelPollTasks={noop}
139
+ deleteSubscriptions={() => {}}
140
+ resetTasks={noop}
141
+ uploadManifest={noop}
142
+ deleteManifest={noop}
143
+ refreshManifest={noop}
144
+ updateSearchQuery={noop}
145
+ openManageManifestModal={noop}
146
+ closeManageManifestModal={noop}
147
+ openDeleteModal={noop}
148
+ closeDeleteModal={noop}
149
+ disableDeleteButton={noop}
150
+ enableDeleteButton={noop}
151
+ />);
152
+ expect(pageWithOrgError.find('PermissionDenied')).toHaveLength(1);
153
+ });
154
+
155
+ it('should render <PermissionDenied /> when organization load fails with 404', async () => {
156
+ const orgWith404Error = {
157
+ loading: false,
158
+ error: {
159
+ response: {
160
+ status: 404,
161
+ },
162
+ },
163
+ };
164
+ const pageWithOrgError = shallow(<SubscriptionsPage
165
+ setModalOpen={noop}
166
+ setModalClosed={noop}
167
+ organization={orgWith404Error}
168
+ subscriptions={successState}
169
+ subscriptionTableSettings={settingsSuccessState}
170
+ loadTables={loadTables}
171
+ loadTableColumns={loadTableColumns}
172
+ createColumns={createColumns}
173
+ updateColumns={updateColumns}
174
+ loadSubscriptions={loadSubscriptions}
175
+ loadAvailableQuantities={loadAvailableQuantities}
176
+ pingUpstreamSubscriptions={pingUpstreamSubscriptions}
177
+ checkSimpleContentAccessEligible={checkSimpleContentAccessEligible}
178
+ updateQuantity={updateQuantity}
179
+ handleStartTask={handleStartTask}
180
+ handleFinishedTask={handleFinishedTask}
181
+ pollTaskUntilDone={noop}
182
+ pollBulkSearch={noop}
183
+ pollTasks={pollTasks}
184
+ cancelPollTasks={noop}
185
+ deleteSubscriptions={() => {}}
186
+ resetTasks={noop}
187
+ uploadManifest={noop}
188
+ deleteManifest={noop}
189
+ refreshManifest={noop}
190
+ updateSearchQuery={noop}
191
+ openManageManifestModal={noop}
192
+ closeManageManifestModal={noop}
193
+ openDeleteModal={noop}
194
+ closeDeleteModal={noop}
195
+ disableDeleteButton={noop}
196
+ enableDeleteButton={noop}
197
+ />);
198
+
199
+ expect(pageWithOrgError.find('PermissionDenied')).toHaveLength(1);
200
+ });
201
+
202
+ it('should not render <PermissionDenied /> when organization is still loading', async () => {
203
+ const orgStillLoading = {
204
+ loading: true,
205
+ error: {
206
+ response: {
207
+ status: 403,
208
+ },
209
+ },
210
+ };
211
+ const pageWithLoadingOrg = shallow(<SubscriptionsPage
212
+ setModalOpen={noop}
213
+ setModalClosed={noop}
214
+ organization={orgStillLoading}
215
+ subscriptions={successState}
216
+ subscriptionTableSettings={settingsSuccessState}
217
+ loadTables={loadTables}
218
+ loadTableColumns={loadTableColumns}
219
+ createColumns={createColumns}
220
+ updateColumns={updateColumns}
221
+ loadSubscriptions={loadSubscriptions}
222
+ loadAvailableQuantities={loadAvailableQuantities}
223
+ pingUpstreamSubscriptions={pingUpstreamSubscriptions}
224
+ checkSimpleContentAccessEligible={checkSimpleContentAccessEligible}
225
+ updateQuantity={updateQuantity}
226
+ handleStartTask={handleStartTask}
227
+ handleFinishedTask={handleFinishedTask}
228
+ pollTaskUntilDone={noop}
229
+ pollBulkSearch={noop}
230
+ pollTasks={pollTasks}
231
+ cancelPollTasks={noop}
232
+ deleteSubscriptions={() => {}}
233
+ resetTasks={noop}
234
+ uploadManifest={noop}
235
+ deleteManifest={noop}
236
+ refreshManifest={noop}
237
+ updateSearchQuery={noop}
238
+ openManageManifestModal={noop}
239
+ closeManageManifestModal={noop}
240
+ openDeleteModal={noop}
241
+ closeDeleteModal={noop}
242
+ disableDeleteButton={noop}
243
+ enableDeleteButton={noop}
244
+ />);
245
+
246
+ // Should not show PermissionDenied while organization is still loading
247
+ expect(pageWithLoadingOrg.find('PermissionDenied')).toHaveLength(0);
248
+ });
249
+
109
250
  it('should poll tasks when org changes', async () => {
110
251
  page.setProps({ organization: { id: 1 } });
111
252
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katello
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.19.0.rc1
4
+ version: 4.19.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - N/A
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-11-11 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -249,7 +248,7 @@ dependencies:
249
248
  version: 3.85.0
250
249
  - - "<"
251
250
  - !ruby/object:Gem::Version
252
- version: 3.86.0
251
+ version: 3.85.4
253
252
  type: :runtime
254
253
  prerelease: false
255
254
  version_requirements: !ruby/object:Gem::Requirement
@@ -259,7 +258,7 @@ dependencies:
259
258
  version: 3.85.0
260
259
  - - "<"
261
260
  - !ruby/object:Gem::Version
262
- version: 3.86.0
261
+ version: 3.85.4
263
262
  - !ruby/object:Gem::Dependency
264
263
  name: pulp_file_client
265
264
  requirement: !ruby/object:Gem::Requirement
@@ -269,7 +268,7 @@ dependencies:
269
268
  version: 3.85.0
270
269
  - - "<"
271
270
  - !ruby/object:Gem::Version
272
- version: 3.86.0
271
+ version: 3.85.4
273
272
  type: :runtime
274
273
  prerelease: false
275
274
  version_requirements: !ruby/object:Gem::Requirement
@@ -279,7 +278,7 @@ dependencies:
279
278
  version: 3.85.0
280
279
  - - "<"
281
280
  - !ruby/object:Gem::Version
282
- version: 3.86.0
281
+ version: 3.85.4
283
282
  - !ruby/object:Gem::Dependency
284
283
  name: pulp_ansible_client
285
284
  requirement: !ruby/object:Gem::Requirement
@@ -289,7 +288,7 @@ dependencies:
289
288
  version: 0.28.0
290
289
  - - "<"
291
290
  - !ruby/object:Gem::Version
292
- version: 0.29.0
291
+ version: 0.28.1
293
292
  type: :runtime
294
293
  prerelease: false
295
294
  version_requirements: !ruby/object:Gem::Requirement
@@ -299,7 +298,7 @@ dependencies:
299
298
  version: 0.28.0
300
299
  - - "<"
301
300
  - !ruby/object:Gem::Version
302
- version: 0.29.0
301
+ version: 0.28.1
303
302
  - !ruby/object:Gem::Dependency
304
303
  name: pulp_container_client
305
304
  requirement: !ruby/object:Gem::Requirement
@@ -309,7 +308,7 @@ dependencies:
309
308
  version: 2.26.0
310
309
  - - "<"
311
310
  - !ruby/object:Gem::Version
312
- version: 2.27.0
311
+ version: 2.26.3
313
312
  type: :runtime
314
313
  prerelease: false
315
314
  version_requirements: !ruby/object:Gem::Requirement
@@ -319,7 +318,7 @@ dependencies:
319
318
  version: 2.26.0
320
319
  - - "<"
321
320
  - !ruby/object:Gem::Version
322
- version: 2.27.0
321
+ version: 2.26.3
323
322
  - !ruby/object:Gem::Dependency
324
323
  name: pulp_deb_client
325
324
  requirement: !ruby/object:Gem::Requirement
@@ -329,7 +328,7 @@ dependencies:
329
328
  version: 3.7.0
330
329
  - - "<"
331
330
  - !ruby/object:Gem::Version
332
- version: 3.8.0
331
+ version: 3.7.1
333
332
  type: :runtime
334
333
  prerelease: false
335
334
  version_requirements: !ruby/object:Gem::Requirement
@@ -339,7 +338,7 @@ dependencies:
339
338
  version: 3.7.0
340
339
  - - "<"
341
340
  - !ruby/object:Gem::Version
342
- version: 3.8.0
341
+ version: 3.7.1
343
342
  - !ruby/object:Gem::Dependency
344
343
  name: pulp_rpm_client
345
344
  requirement: !ruby/object:Gem::Requirement
@@ -369,7 +368,7 @@ dependencies:
369
368
  version: 3.85.0
370
369
  - - "<"
371
370
  - !ruby/object:Gem::Version
372
- version: 3.86.0
371
+ version: 3.85.4
373
372
  type: :runtime
374
373
  prerelease: false
375
374
  version_requirements: !ruby/object:Gem::Requirement
@@ -379,7 +378,7 @@ dependencies:
379
378
  version: 3.85.0
380
379
  - - "<"
381
380
  - !ruby/object:Gem::Version
382
- version: 3.86.0
381
+ version: 3.85.4
383
382
  - !ruby/object:Gem::Dependency
384
383
  name: pulp_python_client
385
384
  requirement: !ruby/object:Gem::Requirement
@@ -389,7 +388,7 @@ dependencies:
389
388
  version: 3.19.0
390
389
  - - "<"
391
390
  - !ruby/object:Gem::Version
392
- version: 3.20.0
391
+ version: 3.19.2
393
392
  type: :runtime
394
393
  prerelease: false
395
394
  version_requirements: !ruby/object:Gem::Requirement
@@ -399,7 +398,7 @@ dependencies:
399
398
  version: 3.19.0
400
399
  - - "<"
401
400
  - !ruby/object:Gem::Version
402
- version: 3.20.0
401
+ version: 3.19.2
403
402
  - !ruby/object:Gem::Dependency
404
403
  name: pulp_ostree_client
405
404
  requirement: !ruby/object:Gem::Requirement
@@ -409,7 +408,7 @@ dependencies:
409
408
  version: 2.5.0
410
409
  - - "<"
411
410
  - !ruby/object:Gem::Version
412
- version: 2.6.0
411
+ version: 2.5.1
413
412
  type: :runtime
414
413
  prerelease: false
415
414
  version_requirements: !ruby/object:Gem::Requirement
@@ -419,7 +418,7 @@ dependencies:
419
418
  version: 2.5.0
420
419
  - - "<"
421
420
  - !ruby/object:Gem::Version
422
- version: 2.6.0
421
+ version: 2.5.1
423
422
  - !ruby/object:Gem::Dependency
424
423
  name: deface
425
424
  requirement: !ruby/object:Gem::Requirement
@@ -4456,6 +4455,7 @@ files:
4456
4455
  - lib/proxy_api/pulp_node.rb
4457
4456
  - locale/Makefile
4458
4457
  - locale/README
4458
+ - locale/action_names.rb
4459
4459
  - locale/bn/LC_MESSAGES/katello.mo
4460
4460
  - locale/bn/katello.po
4461
4461
  - locale/bn/katello.po.time_stamp
@@ -5613,7 +5613,6 @@ homepage: http://www.katello.org
5613
5613
  licenses:
5614
5614
  - GPL-2.0
5615
5615
  metadata: {}
5616
- post_install_message:
5617
5616
  rdoc_options: []
5618
5617
  require_paths:
5619
5618
  - lib
@@ -5627,12 +5626,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
5627
5626
  version: '4'
5628
5627
  required_rubygems_version: !ruby/object:Gem::Requirement
5629
5628
  requirements:
5630
- - - ">"
5629
+ - - ">="
5631
5630
  - !ruby/object:Gem::Version
5632
- version: 1.3.1
5631
+ version: '0'
5633
5632
  requirements: []
5634
- rubygems_version: 3.2.33
5635
- signing_key:
5633
+ rubygems_version: 3.6.9
5636
5634
  specification_version: 4
5637
5635
  summary: Content and Subscription Management plugin for Foreman
5638
5636
  test_files: []