@rancher/shell 3.0.9-rc.5 → 3.0.9

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 (172) hide show
  1. package/assets/images/providers/oci-open-containers.svg +22 -0
  2. package/assets/images/providers/traefik.png +0 -0
  3. package/assets/styles/themes/_dark.scss +2 -0
  4. package/assets/styles/themes/_light.scss +2 -0
  5. package/assets/styles/themes/_modern.scss +6 -0
  6. package/assets/translations/en-us.yaml +129 -25
  7. package/components/CruResource.vue +3 -1
  8. package/components/ExplorerProjectsNamespaces.vue +12 -12
  9. package/components/IconOrSvg.vue +61 -42
  10. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
  11. package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
  12. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +19 -2
  13. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
  14. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
  15. package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
  16. package/components/Resource/Detail/ResourceRow.vue +2 -2
  17. package/components/ResourceList/index.vue +7 -4
  18. package/components/SortableTable/index.vue +2 -2
  19. package/components/Window/ContainerLogs.vue +48 -37
  20. package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
  21. package/components/fleet/FleetClusterTargets/index.vue +6 -1
  22. package/components/fleet/GitRepoAdvancedTab.vue +333 -0
  23. package/components/fleet/GitRepoMetadataTab.vue +43 -0
  24. package/components/fleet/GitRepoRepositoryTab.vue +101 -0
  25. package/components/fleet/GitRepoTargetTab.vue +77 -0
  26. package/components/fleet/HelmOpAdvancedTab.vue +247 -0
  27. package/components/fleet/HelmOpChartTab.vue +158 -0
  28. package/components/fleet/HelmOpMetadataTab.vue +46 -0
  29. package/components/fleet/HelmOpTargetTab.vue +84 -0
  30. package/components/fleet/HelmOpValuesTab.vue +147 -0
  31. package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
  32. package/components/form/BannerSettings.vue +2 -2
  33. package/components/form/NodeScheduling.vue +81 -7
  34. package/components/form/NotificationSettings.vue +2 -2
  35. package/components/form/PodAffinity.vue +1 -36
  36. package/components/form/ResourceLabeledSelect.vue +8 -4
  37. package/components/form/ResourceQuota/Namespace.vue +30 -9
  38. package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
  39. package/components/form/ResourceQuota/Project.vue +140 -82
  40. package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
  41. package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
  42. package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
  43. package/components/form/ResourceQuota/__tests__/Project.test.ts +274 -27
  44. package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
  45. package/components/form/SchedulingCustomization.vue +14 -6
  46. package/components/form/SelectOrCreateAuthSecret.vue +107 -18
  47. package/components/form/__tests__/NodeScheduling.test.ts +12 -9
  48. package/components/form/__tests__/PodAffinity.test.ts +21 -2
  49. package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
  50. package/components/formatter/ClusterLink.vue +8 -0
  51. package/components/formatter/SecretOrigin.vue +79 -0
  52. package/config/labels-annotations.js +7 -6
  53. package/config/pagination-table-headers.js +6 -4
  54. package/config/product/explorer.js +1 -11
  55. package/config/product/manager.js +0 -1
  56. package/config/query-params.js +3 -0
  57. package/config/settings.ts +15 -2
  58. package/config/table-headers.js +21 -17
  59. package/config/types.js +23 -8
  60. package/detail/fleet.cattle.io.cluster.vue +1 -1
  61. package/detail/workload/index.vue +11 -16
  62. package/dialog/DeactivateDriverDialog.vue +1 -1
  63. package/dialog/FeatureFlagListDialog.vue +1 -1
  64. package/dialog/Ipv6NetworkingDialog.vue +156 -0
  65. package/dialog/ScalePoolDownDialog.vue +2 -2
  66. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
  67. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +1 -0
  68. package/edit/__tests__/management.cattle.io.project.test.js +56 -128
  69. package/edit/auth/oidc.vue +1 -1
  70. package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
  71. package/edit/fleet.cattle.io.gitrepo.vue +153 -283
  72. package/edit/fleet.cattle.io.helmop.vue +190 -332
  73. package/edit/management.cattle.io.project.vue +5 -42
  74. package/edit/management.cattle.io.setting.vue +6 -0
  75. package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/auth.spec.ts +145 -0
  76. package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/index.test.ts +202 -0
  77. package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/tls.spec.ts +226 -0
  78. package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +24 -21
  79. package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/opsgenie.spec.ts +157 -0
  80. package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/pagerduty.spec.ts +132 -0
  81. package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/slack.spec.ts +108 -0
  82. package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +2 -1
  83. package/edit/monitoring.coreos.com.receiver/__tests__/auth.spec.ts +165 -0
  84. package/edit/monitoring.coreos.com.receiver/__tests__/index.test.ts +153 -0
  85. package/edit/monitoring.coreos.com.receiver/__tests__/tls.spec.ts +115 -0
  86. package/edit/monitoring.coreos.com.receiver/types/__tests__/email.spec.ts +86 -0
  87. package/edit/monitoring.coreos.com.receiver/types/__tests__/opsgenie.spec.ts +209 -0
  88. package/edit/monitoring.coreos.com.receiver/types/__tests__/pagerduty.spec.ts +105 -0
  89. package/edit/monitoring.coreos.com.receiver/types/__tests__/slack.spec.ts +92 -0
  90. package/edit/monitoring.coreos.com.receiver/types/__tests__/webhook.spec.ts +131 -0
  91. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
  92. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
  93. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
  94. package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
  95. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -49
  96. package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +114 -0
  97. package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
  98. package/edit/provisioning.cattle.io.cluster/rke2.vue +167 -69
  99. package/edit/provisioning.cattle.io.cluster/shared.ts +36 -1
  100. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
  101. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +70 -7
  102. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +343 -0
  103. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
  104. package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
  105. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
  106. package/edit/secret/index.vue +1 -1
  107. package/edit/token.vue +68 -29
  108. package/edit/workload/__tests__/index.test.ts +2 -37
  109. package/edit/workload/index.vue +6 -2
  110. package/edit/workload/mixins/workload.js +0 -32
  111. package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
  112. package/list/management.cattle.io.setting.vue +13 -0
  113. package/list/provisioning.cattle.io.cluster.vue +50 -1
  114. package/list/secret.vue +4 -9
  115. package/list/service.vue +6 -8
  116. package/machine-config/amazonec2.vue +11 -4
  117. package/machine-config/components/EC2Networking.vue +46 -30
  118. package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
  119. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
  120. package/machine-config/digitalocean.vue +3 -3
  121. package/models/__tests__/chart.test.ts +2 -2
  122. package/models/__tests__/namespace.test.ts +11 -0
  123. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
  124. package/models/__tests__/workload.test.ts +42 -1
  125. package/models/catalog.cattle.io.clusterrepo.js +30 -4
  126. package/models/chart.js +3 -3
  127. package/models/ext.cattle.io.token.js +48 -0
  128. package/models/kontainerdriver.js +2 -2
  129. package/models/namespace.js +7 -1
  130. package/models/nodedriver.js +2 -2
  131. package/models/provisioning.cattle.io.cluster.js +28 -7
  132. package/models/secret.js +0 -17
  133. package/models/service.js +44 -1
  134. package/models/token.js +4 -0
  135. package/models/workload.js +12 -6
  136. package/package.json +1 -1
  137. package/pages/account/index.vue +96 -67
  138. package/pages/auth/setup.vue +5 -14
  139. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +45 -18
  140. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
  141. package/pages/c/_cluster/apps/charts/index.vue +82 -3
  142. package/pages/c/_cluster/apps/charts/install.vue +317 -42
  143. package/pages/c/_cluster/explorer/tools/index.vue +1 -1
  144. package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
  145. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
  146. package/pages/c/_cluster/settings/index.vue +3 -1
  147. package/pages/c/_cluster/uiplugins/index.vue +1 -1
  148. package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
  149. package/plugins/dashboard-store/__tests__/resource-class.test.ts +27 -0
  150. package/plugins/dashboard-store/actions.js +3 -8
  151. package/plugins/dashboard-store/getters.js +7 -5
  152. package/plugins/dashboard-store/mutations.js +4 -1
  153. package/plugins/dashboard-store/resource-class.js +3 -3
  154. package/plugins/steve/__tests__/steve-class.test.ts +102 -141
  155. package/plugins/steve/steve-class.js +12 -3
  156. package/plugins/steve/steve-pagination-utils.ts +6 -2
  157. package/rancher-components/RcIcon/types.ts +2 -0
  158. package/rancher-components/RcItemCard/RcItemCard.vue +72 -20
  159. package/store/prefs.js +3 -0
  160. package/types/aws-sdk.d.ts +121 -0
  161. package/types/resources/node.ts +15 -0
  162. package/types/shell/index.d.ts +537 -506
  163. package/types/store/pagination.types.ts +5 -5
  164. package/utils/__tests__/array.test.ts +1 -29
  165. package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
  166. package/utils/array.ts +0 -11
  167. package/utils/aws.ts +21 -0
  168. package/utils/cluster.js +22 -2
  169. package/utils/selector-typed.ts +1 -1
  170. package/utils/svg-filter.js +4 -3
  171. package/components/__tests__/ProjectRow.test.ts +0 -206
  172. package/components/form/ResourceQuota/ProjectRow.vue +0 -277
@@ -27,119 +27,75 @@ const defaultMountOptions = {
27
27
  };
28
28
 
29
29
  describe('component: ManagementCattleIoProject', () => {
30
- it('should remove a standard resource quota correctly', async() => {
31
- const value = {
32
- spec: {
33
- resourceQuota: { limit: { limitsCpu: '100m', limitsMemory: '1Gi' } },
34
- namespaceDefaultResourceQuota: { limit: { limitsCpu: '50m', limitsMemory: '500Mi' } }
35
- },
36
- metadata: { namespace: 'test-ns', annotations: {} },
37
- save: jest.fn(),
38
- listLocation: { name: 'list' }
39
- };
40
-
41
- const wrapper = shallowMount(
42
- ManagementCattleIoProject,
43
- {
44
- ...defaultMountOptions,
45
- props: {
46
- ...defaultMountOptions.props,
47
- value,
30
+ describe('onQuotasInput', () => {
31
+ it('should update resourceQuota limit while preserving other resourceQuota fields', () => {
32
+ const value = {
33
+ spec: {
34
+ resourceQuota: { limit: { limitsCpu: '100m' }, usedLimit: { limitsCpu: '50m' } },
35
+ namespaceDefaultResourceQuota: { limit: { limitsCpu: '50m' } }
48
36
  },
49
- }
50
- );
51
-
52
- wrapper.vm.removeQuota('limitsCpu');
37
+ metadata: { namespace: 'test-ns', annotations: {} },
38
+ save: jest.fn(),
39
+ listLocation: { name: 'list' }
40
+ };
53
41
 
54
- expect(wrapper.vm.value.spec.resourceQuota.limit.limitsCpu).toBeUndefined();
55
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.limitsCpu).toBeUndefined();
56
- expect(wrapper.vm.value.spec.resourceQuota.limit.limitsMemory).toBe('1Gi'); // Ensure other quotas are not affected
57
- });
58
-
59
- it('should remove a custom resource quota with single period in name correctly', async() => {
60
- const value = {
61
- spec: {
62
- resourceQuota: { limit: { extended: { test2: '1' } } },
63
- namespaceDefaultResourceQuota: { limit: { extended: { test2: '2' } } }
64
- },
65
- metadata: { namespace: 'test-ns', annotations: {} },
66
- save: jest.fn(),
67
- listLocation: { name: 'list' }
68
- };
69
-
70
- const wrapper = shallowMount(
71
- ManagementCattleIoProject,
72
- {
42
+ const wrapper = shallowMount(ManagementCattleIoProject, {
73
43
  ...defaultMountOptions,
74
- props: {
75
- ...defaultMountOptions.props,
76
- value,
77
- },
78
- }
79
- );
44
+ props: { ...defaultMountOptions.props, value },
45
+ });
80
46
 
81
- wrapper.vm.removeQuota(`extended.test2`);
47
+ wrapper.vm.onQuotasInput({ projectLimit: { limitsCpu: '200m' }, nsLimit: { limitsCpu: '100m' } });
82
48
 
83
- expect(wrapper.vm.value.spec.resourceQuota.limit.extended).toBeUndefined();
84
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.extended).toBeUndefined();
85
- });
49
+ expect(wrapper.vm.value.spec.resourceQuota.limit).toStrictEqual({ limitsCpu: '200m' });
50
+ expect(wrapper.vm.value.spec.resourceQuota.usedLimit).toStrictEqual({ limitsCpu: '50m' });
51
+ });
86
52
 
87
- it('should remove a custom resource quota with multiple periods in name correctly', async() => {
88
- const value = {
89
- spec: {
90
- resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
91
- namespaceDefaultResourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '2' } } }
92
- },
93
- metadata: { namespace: 'test-ns', annotations: {} },
94
- save: jest.fn(),
95
- listLocation: { name: 'list' }
96
- };
97
-
98
- const wrapper = shallowMount(
99
- ManagementCattleIoProject,
100
- {
101
- ...defaultMountOptions,
102
- props: {
103
- ...defaultMountOptions.props,
104
- value,
53
+ it('should update namespaceDefaultResourceQuota limit while preserving other namespaceDefaultResourceQuota fields', () => {
54
+ const value = {
55
+ spec: {
56
+ resourceQuota: { limit: { limitsCpu: '100m' } },
57
+ namespaceDefaultResourceQuota: { limit: { limitsCpu: '50m' }, extraField: 'preserved' }
105
58
  },
106
- }
107
- );
59
+ metadata: { namespace: 'test-ns', annotations: {} },
60
+ save: jest.fn(),
61
+ listLocation: { name: 'list' }
62
+ };
108
63
 
109
- wrapper.vm.removeQuota(`extended.requests.nvidia.com/gpu`);
64
+ const wrapper = shallowMount(ManagementCattleIoProject, {
65
+ ...defaultMountOptions,
66
+ props: { ...defaultMountOptions.props, value },
67
+ });
110
68
 
111
- expect(wrapper.vm.value.spec.resourceQuota.limit.extended).toBeUndefined();
112
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.extended).toBeUndefined();
113
- });
69
+ wrapper.vm.onQuotasInput({ projectLimit: { limitsCpu: '200m' }, nsLimit: { limitsCpu: '100m' } });
114
70
 
115
- it('should remove one of multiple custom resource quotas correctly', async() => {
116
- const value = {
117
- spec: {
118
- resourceQuota: { limit: { extended: { test1: '1', test2: '2' } } },
119
- namespaceDefaultResourceQuota: { limit: { extended: { test1: '3', test2: '4' } } }
120
- },
121
- metadata: { namespace: 'test-ns', annotations: {} },
122
- save: jest.fn(),
123
- listLocation: { name: 'list' }
124
- };
125
-
126
- const wrapper = shallowMount(
127
- ManagementCattleIoProject,
128
- {
129
- ...defaultMountOptions,
130
- props: {
131
- ...defaultMountOptions.props,
132
- value,
71
+ expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit).toStrictEqual({ limitsCpu: '100m' });
72
+ expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.extraField).toStrictEqual('preserved');
73
+ });
74
+
75
+ it('should set both resourceQuota and namespaceDefaultResourceQuota limits from input', () => {
76
+ const value = {
77
+ spec: {
78
+ resourceQuota: { limit: {} },
79
+ namespaceDefaultResourceQuota: { limit: {} }
133
80
  },
134
- }
135
- );
81
+ metadata: { namespace: 'test-ns', annotations: {} },
82
+ save: jest.fn(),
83
+ listLocation: { name: 'list' }
84
+ };
85
+
86
+ const wrapper = shallowMount(ManagementCattleIoProject, {
87
+ ...defaultMountOptions,
88
+ props: { ...defaultMountOptions.props, value },
89
+ });
136
90
 
137
- wrapper.vm.removeQuota('extended.test1');
91
+ wrapper.vm.onQuotasInput({
92
+ projectLimit: { limitsCpu: '500m', limitsMemory: '2Gi' },
93
+ nsLimit: { limitsCpu: '250m', limitsMemory: '1Gi' },
94
+ });
138
95
 
139
- expect(wrapper.vm.value.spec.resourceQuota.limit.extended.test1).toBeUndefined();
140
- expect(wrapper.vm.value.spec.resourceQuota.limit.extended.test2).toBe('2');
141
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.extended.test1).toBeUndefined();
142
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.extended.test2).toBe('4');
96
+ expect(wrapper.vm.value.spec.resourceQuota.limit).toStrictEqual({ limitsCpu: '500m', limitsMemory: '2Gi' });
97
+ expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit).toStrictEqual({ limitsCpu: '250m', limitsMemory: '1Gi' });
98
+ });
143
99
  });
144
100
 
145
101
  it('should update isQuotasValid when validateQuotas is called', () => {
@@ -161,32 +117,4 @@ describe('component: ManagementCattleIoProject', () => {
161
117
 
162
118
  expect(cruResource.props('validationPassed')).toStrictEqual(false);
163
119
  });
164
-
165
- it('should remove an extended resource quota correctly with fixed startsWith', async() => {
166
- const value = {
167
- spec: {
168
- resourceQuota: { limit: { extended: { test2: '1' } } },
169
- namespaceDefaultResourceQuota: { limit: { extended: { test2: '2' } } }
170
- },
171
- metadata: { namespace: 'test-ns', annotations: {} },
172
- save: jest.fn(),
173
- listLocation: { name: 'list' }
174
- };
175
-
176
- const wrapper = shallowMount(
177
- ManagementCattleIoProject,
178
- {
179
- ...defaultMountOptions,
180
- props: {
181
- ...defaultMountOptions.props,
182
- value,
183
- },
184
- }
185
- );
186
-
187
- wrapper.vm.removeQuota('extended.test2');
188
-
189
- expect(wrapper.vm.value.spec.resourceQuota.limit.extended).toBeUndefined();
190
- expect(wrapper.vm.value.spec.namespaceDefaultResourceQuota.limit.extended).toBeUndefined();
191
- });
192
120
  });
@@ -273,7 +273,7 @@ export default {
273
273
 
274
274
  this.model.issuer = `${ url }/${ realmsPath }/${ this.oidcUrls.realm || '' }`;
275
275
 
276
- if ( isKeycloak ) {
276
+ if ( isKeycloak || this.isGenericOidc ) {
277
277
  this.model.authEndpoint = `${ this.model.issuer || '' }/protocol/openid-connect/auth`;
278
278
  }
279
279
  },
@@ -1,15 +1,21 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import CreateEditView from '@shell/mixins/create-edit-view';
3
3
  import Footer from '@shell/components/form/Footer';
4
4
  import { LabeledInput } from '@components/Form/LabeledInput';
5
- import { RadioGroup } from '@components/Form/Radio';
6
5
  import NameNsDescription from '@shell/components/form/NameNsDescription';
7
6
  import Labels from '@shell/components/form/Labels';
8
7
  import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthSecret';
9
8
  import Banner from '@components/Banner/Banner.vue';
10
9
  import { Checkbox } from '@components/Form/Checkbox';
11
- import { MANAGEMENT, NAMESPACE, CLUSTER_REPO_TYPES } from '@shell/config/types';
10
+ import {
11
+ MANAGEMENT, NAMESPACE, CLUSTER_REPO_TYPES, AUTH_TYPE,
12
+ CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME, CLUSTER_REPO_AUTH_GENERATE_NAME
13
+ } from '@shell/config/types';
12
14
  import UnitInput from '@shell/components/form/UnitInput.vue';
15
+ import { getVersionData } from '@shell/config/version';
16
+ import { RcItemCard } from '@components/RcItemCard';
17
+ import { _CREATE, _EDIT, TARGET, _VIEW } from '@shell/config/query-params';
18
+ import { RcIconType } from '@components/RcIcon/types';
13
19
 
14
20
  export default {
15
21
  name: 'CruCatalogRepo',
@@ -18,30 +24,88 @@ export default {
18
24
 
19
25
  components: {
20
26
  Footer,
21
- RadioGroup,
22
27
  LabeledInput,
23
28
  NameNsDescription,
24
29
  Labels,
25
30
  SelectOrCreateAuthSecret,
26
31
  Banner,
27
32
  Checkbox,
28
- UnitInput
33
+ UnitInput,
34
+ RcItemCard,
29
35
  },
30
36
 
31
37
  mixins: [CreateEditView],
32
38
 
33
39
  data() {
34
- const clusterRepoType = !!this.value.spec.gitRepo ? CLUSTER_REPO_TYPES.GIT_REPO : this.value.isOciType ? CLUSTER_REPO_TYPES.OCI_URL : CLUSTER_REPO_TYPES.HELM_URL;
40
+ // Determine the cluster repo type based on existing values (for edit mode)
41
+ let clusterRepoType = '';
42
+
43
+ if (!!this.value.spec.gitRepo) {
44
+ clusterRepoType = CLUSTER_REPO_TYPES.GIT_REPO;
45
+ } else if (this.value.isOciType) {
46
+ clusterRepoType = this.value?.isSuseAppCollectionFromUI ? CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION : CLUSTER_REPO_TYPES.OCI_URL;
47
+ } else {
48
+ clusterRepoType = CLUSTER_REPO_TYPES.HELM_URL;
49
+ }
50
+
51
+ const clusterRepoTargets = [
52
+ {
53
+ id: CLUSTER_REPO_TYPES.HELM_URL,
54
+ header: { title: { key: 'catalog.repo.target.http.title' } },
55
+ image: { icon: 'helm' as RcIconType, alt: { key: 'catalog.repo.target.http.title' } },
56
+ content: { key: 'catalog.repo.target.http.description' },
57
+ },
58
+ {
59
+ id: CLUSTER_REPO_TYPES.GIT_REPO,
60
+ header: { title: { key: 'catalog.repo.target.git.title' } },
61
+ image: { icon: 'git' as RcIconType, alt: { key: 'catalog.repo.target.git.title' } },
62
+ content: { key: 'catalog.repo.target.git.description' },
63
+ },
64
+ {
65
+ id: CLUSTER_REPO_TYPES.OCI_URL,
66
+ header: { title: { key: 'catalog.repo.target.oci.title' } },
67
+ image: { src: require('@shell/assets/images/providers/oci-open-containers.svg'), alt: { key: 'catalog.repo.target.oci.title' } },
68
+ content: { key: 'catalog.repo.target.oci.description' },
69
+ },
70
+ ];
71
+
72
+ // Only show SUSE App Collection option for RancherPrime
73
+ if (getVersionData()?.RancherPrime === 'true') {
74
+ clusterRepoTargets.push({
75
+ id: CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION,
76
+ header: { title: { key: 'catalog.repo.target.suseAppCollection.title' } },
77
+ image: { src: require('@shell/assets/images/content/suse.svg'), alt: { key: 'catalog.repo.target.suseAppCollection.title' } },
78
+ content: { key: 'catalog.repo.target.suseAppCollection.description' },
79
+ });
80
+ }
35
81
 
36
82
  return {
37
83
  CLUSTER_REPO_TYPES,
84
+ AUTH_TYPE,
85
+ CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME,
86
+ CLUSTER_REPO_AUTH_GENERATE_NAME,
38
87
  clusterRepoType,
39
- ociMinWait: this.value.spec.exponentialBackOffValues?.minWait,
40
- ociMaxWait: this.value.spec.exponentialBackOffValues?.maxWait,
41
- ociMaxRetries: this.value.spec.exponentialBackOffValues?.maxRetries
88
+ ociMinWait: this.value.spec.exponentialBackOffValues?.minWait,
89
+ ociMaxWait: this.value.spec.exponentialBackOffValues?.maxWait,
90
+ ociMaxRetries: this.value.spec.exponentialBackOffValues?.maxRetries,
91
+ getVersionData,
92
+ isView: this.mode === _VIEW,
93
+ clusterRepoTargets,
94
+ previousName: '',
95
+ previousDescription: '',
42
96
  };
43
97
  },
44
98
 
99
+ created() {
100
+ // When creating a new repo with a target query parameter, initialize the form properly
101
+ const targetFromQuery = this.mode === _CREATE ? this.$route.query[TARGET] : null;
102
+
103
+ if (targetFromQuery && Object.values(CLUSTER_REPO_TYPES).includes(targetFromQuery)) {
104
+ // Trigger onTargetChange to properly initialize form fields for the selected target
105
+ this.onTargetChange(targetFromQuery);
106
+ }
107
+ },
108
+
45
109
  computed: {
46
110
  inStore() {
47
111
  return this.$store.getters['currentProduct']?.inStore || MANAGEMENT;
@@ -62,20 +126,33 @@ export default {
62
126
  methods: {
63
127
  onTargetChange(clusterRepoType) {
64
128
  // reset input fields when switching options
129
+ const oldClusterRepoType = this.clusterRepoType;
130
+
131
+ this.clusterRepoType = clusterRepoType;
65
132
  switch (clusterRepoType) {
66
133
  case CLUSTER_REPO_TYPES.GIT_REPO:
67
134
  this.resetOciValues();
68
135
  this.resetHelmValues();
136
+ this.resetNameAndDescription(oldClusterRepoType, this.clusterRepoType);
69
137
  break;
70
138
  case CLUSTER_REPO_TYPES.OCI_URL:
71
139
  // set insecurePlainHttp to false as a secondary flag, alongside checking for 'oci://' in the URL, to determine OCI type later
72
140
  this.value.spec['insecurePlainHttp'] = false;
73
141
  this.resetGitRepoValues();
74
142
  this.resetHelmValues();
143
+ this.resetNameAndDescription(oldClusterRepoType, this.clusterRepoType);
75
144
  break;
76
145
  case CLUSTER_REPO_TYPES.HELM_URL:
77
146
  this.resetOciValues();
78
147
  this.resetGitRepoValues();
148
+ this.resetNameAndDescription(oldClusterRepoType, this.clusterRepoType);
149
+ break;
150
+ case CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION:
151
+ this.resetOciValues();
152
+ this.resetGitRepoValues();
153
+ this.resetHelmValues();
154
+ this.value.spec['url'] = 'oci://dp.apps.rancher.io/charts';
155
+ this.resetNameAndDescription(oldClusterRepoType, this.clusterRepoType);
79
156
  break;
80
157
  }
81
158
  this.resetClientSecret();
@@ -124,6 +201,25 @@ export default {
124
201
  },
125
202
  resetClientSecret() {
126
203
  this.value.spec['clientSecret'] = null;
204
+ },
205
+ resetNameAndDescription(old, neu) {
206
+ if (this.mode === _EDIT) {
207
+ return;
208
+ }
209
+
210
+ if (!this.value?.metadata?.annotations) {
211
+ this.value.metadata.annotations = {};
212
+ }
213
+
214
+ if (neu === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION) {
215
+ this.previousName = this.value.metadata.name || '';
216
+ this.previousDescription = this.value.metadata.annotations?.['field.cattle.io/description'] || '';
217
+ this.value.metadata['name'] = CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION;
218
+ this.value.metadata.annotations['field.cattle.io/description'] = this.t('catalog.repo.target.suseAppCollection.description');
219
+ } else if (old === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION) {
220
+ this.value.metadata['name'] = this.previousName;
221
+ this.value.metadata.annotations['field.cattle.io/description'] = this.previousDescription;
222
+ }
127
223
  }
128
224
  },
129
225
  };
@@ -131,28 +227,33 @@ export default {
131
227
 
132
228
  <template>
133
229
  <form>
230
+ <h2>{{ t('catalog.repo.target.label') }}</h2>
231
+ <div class="row mb-20">
232
+ <div class="col span-12 target-groups">
233
+ <RcItemCard
234
+ v-for="card in clusterRepoTargets"
235
+ :id="card.id"
236
+ :key="card.id"
237
+ :header="card.header"
238
+ :image="card.image"
239
+ :content="card.content"
240
+ :selected="clusterRepoType === card.id"
241
+ :clickable="true"
242
+ :disabled="isView"
243
+ variant="small"
244
+ @card-click="onTargetChange(card.id)"
245
+ />
246
+ </div>
247
+ </div>
248
+
134
249
  <NameNsDescription
250
+ :key="clusterRepoType"
135
251
  :value="value"
136
252
  :mode="mode"
137
253
  :namespaced="isNamespaced"
138
254
  @update:value="$emit('input', $event)"
139
255
  />
140
256
 
141
- <h2>{{ t('catalog.repo.target.label') }}</h2>
142
- <div class="row mb-10">
143
- <div class="col span-8">
144
- <RadioGroup
145
- v-model:value="clusterRepoType"
146
- :name="clusterRepoType"
147
- :options="[CLUSTER_REPO_TYPES.HELM_URL, CLUSTER_REPO_TYPES.GIT_REPO, CLUSTER_REPO_TYPES.OCI_URL]"
148
- :labels="[t('catalog.repo.target.http'), t('catalog.repo.target.git'), t('catalog.repo.target.oci', null, true)]"
149
- :mode="mode"
150
- data-testid="clusterrepo-radio-input"
151
- @update:value="onTargetChange"
152
- />
153
- </div>
154
- </div>
155
-
156
257
  <template v-if="clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL">
157
258
  <Banner
158
259
  label-key="catalog.repo.oci.warning"
@@ -201,6 +302,20 @@ export default {
201
302
  </div>
202
303
  </template>
203
304
 
305
+ <template v-else-if="clusterRepoType === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION">
306
+ <div class="col span-6">
307
+ <LabeledInput
308
+ v-model:value.trim="value.spec.url"
309
+ :required="true"
310
+ :label="t('catalog.repo.oci.urlLabel')"
311
+ :placeholder="t('catalog.repo.oci.placeholder', null, true)"
312
+ :mode="mode"
313
+ data-testid="clusterrepo-oci-url-input"
314
+ :disabled="true"
315
+ />
316
+ </div>
317
+ </template>
318
+
204
319
  <div
205
320
  v-else
206
321
  class="col span-6"
@@ -240,8 +355,12 @@ export default {
240
355
  :limit-to-namespace="false"
241
356
  :in-store="inStore"
242
357
  :allow-ssh="clusterRepoType !== CLUSTER_REPO_TYPES.OCI_URL"
243
- generate-name="clusterrepo-auth-"
358
+ :pre-select="clusterRepoType === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION ? { selected: AUTH_TYPE._BASIC } : null"
359
+ :allow-none="clusterRepoType !== CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION"
360
+ :generate-name="clusterRepoType === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION ? CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME : CLUSTER_REPO_AUTH_GENERATE_NAME"
244
361
  :cache-secrets="true"
362
+ :fixed-http-basic-auth="clusterRepoType === CLUSTER_REPO_TYPES.SUSE_APP_COLLECTION"
363
+ :filter-basic-auth="CLUSTER_REPO_APPCO_AUTH_GENERATE_NAME"
245
364
  />
246
365
 
247
366
  <div v-if="clusterRepoType === CLUSTER_REPO_TYPES.OCI_URL">
@@ -334,3 +453,14 @@ export default {
334
453
  />
335
454
  </form>
336
455
  </template>
456
+
457
+ <style lang="css" scoped>
458
+ .target-groups {
459
+ display: grid;
460
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
461
+ grid-gap: var(--gap-md);
462
+ width: 100%;
463
+ height: max-content;
464
+ overflow: hidden;
465
+ }
466
+ </style>