@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
@@ -1,17 +1,24 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import { mapGetters } from 'vuex';
3
3
  import { RadioGroup } from '@components/Form/Radio';
4
- import LabeledSelect from '@shell/components/form/LabeledSelect';
5
- import NodeAffinity from '@shell/components/form/NodeAffinity';
4
+ import ResourceLabeledSelect from '@shell/components/form/ResourceLabeledSelect.vue';
5
+ import NodeAffinity from '@shell/components/form/NodeAffinity.vue';
6
6
  import { HARVESTER_NAME as VIRTUAL } from '@shell/config/features';
7
7
  import { _VIEW } from '@shell/config/query-params';
8
8
  import { isEmpty } from '@shell/utils/object';
9
9
  import { HOSTNAME } from '@shell/config/labels-annotations';
10
+ import { ResourceLabeledSelectPaginateSettings, ResourceLabeledSelectSettings } from '@shell/types/components/resourceLabeledSelect';
11
+ import { NODE } from '@shell/config/types';
12
+ import { LabelSelectPaginationFunctionOptions } from '@shell/components/form/labeled-select-utils/labeled-select.utils';
13
+ import { PaginationFilterEquality, PaginationParamFilter } from '@shell/types/store/pagination.types';
14
+ import { KubeNode, KubeNodeTaint } from '@shell/types/resources/node';
15
+
16
+ const parseNode = (node: string | KubeNode) => typeof node === 'string' ? node : node.id;
10
17
 
11
18
  export default {
12
19
  components: {
13
20
  RadioGroup,
14
- LabeledSelect,
21
+ ResourceLabeledSelect,
15
22
  NodeAffinity,
16
23
  },
17
24
 
@@ -23,6 +30,9 @@ export default {
23
30
  }
24
31
  },
25
32
 
33
+ /**
34
+ * HARVESTER ONLY PROPERTY
35
+ */
26
36
  nodes: {
27
37
  type: Array,
28
38
  default: () => []
@@ -39,12 +49,71 @@ export default {
39
49
  },
40
50
  },
41
51
 
42
- data() {
52
+ data(): {
53
+ selectNode: string | null;
54
+ nodeName: string;
55
+ nodeAffinity: any;
56
+ nodeSelector: any;
57
+ nodeSchedulingAllSettings: ResourceLabeledSelectSettings;
58
+ nodeSchedulingPaginationSettings: ResourceLabeledSelectPaginateSettings;
59
+ NODE: string;
60
+ } {
61
+ const keys = [
62
+ `node-role.kubernetes.io/control-plane`,
63
+ `node-role.kubernetes.io/etcd`
64
+ ];
65
+
66
+ // Settings used by ResourceLabeledSelect when node pagination disabled
67
+ const nodeSchedulingAllSettings: ResourceLabeledSelectSettings = {
68
+ updateResources(nodes: (string | KubeNode)[]) {
69
+ return nodes
70
+ .filter((node) => {
71
+ if (typeof node === 'string') {
72
+ // Already passed check
73
+ return true;
74
+ }
75
+
76
+ const taints = node.spec?.taints || [];
77
+
78
+ return taints.every((taint: KubeNodeTaint) => !keys.includes(taint.key));
79
+ })
80
+ .map(parseNode);
81
+ },
82
+ };
83
+
84
+ // Settings used by ResourceLabeledSelect when node pagination enabled
85
+ const nodeSchedulingPaginationSettings: ResourceLabeledSelectPaginateSettings = {
86
+ updateResources(nodes: (string | KubeNode)[]) {
87
+ return nodes.map(parseNode);
88
+ },
89
+ requestSettings: (opts: LabelSelectPaginationFunctionOptions) => {
90
+ const { filter } = opts.opts;
91
+ const filters = !!filter ? [
92
+ PaginationParamFilter.createSingleField({
93
+ field: 'metadata.name', value: filter, exact: false
94
+ })
95
+ ] : [];
96
+
97
+ filters.push(...keys.map((k) => PaginationParamFilter.createSingleField( ({
98
+ field: 'spec.taints.key', value: k, equality: PaginationFilterEquality.NOT_CONTAINS
99
+ }))));
100
+
101
+ opts.filters = filters;
102
+ opts.groupByNamespace = false;
103
+ opts.sort = [{ asc: true, field: 'metadata.name' }];
104
+
105
+ return opts;
106
+ }
107
+ };
108
+
43
109
  return {
44
110
  selectNode: null,
45
111
  nodeName: '',
46
112
  nodeAffinity: {},
47
113
  nodeSelector: {},
114
+ nodeSchedulingAllSettings,
115
+ nodeSchedulingPaginationSettings,
116
+ NODE
48
117
  };
49
118
  },
50
119
 
@@ -147,6 +216,9 @@ export default {
147
216
  watch: {
148
217
  'value.nodeSelector': {
149
218
  handler(nodeSelector) {
219
+ // Harvester specific code should not live in rancher/dashboard components
220
+ // This was brought into harvester/dashboard via https://github.com/harvester/dashboard/pull/342
221
+ // rancher/dashboard via https://github.com/rancher/dashboard/pull/6310
150
222
  if (this.isHarvester && nodeSelector?.[HOSTNAME]) {
151
223
  this.selectNode = 'nodeSelector';
152
224
  const nodeName = nodeSelector[HOSTNAME];
@@ -187,14 +259,16 @@ export default {
187
259
  <template v-if="selectNode === 'nodeSelector'">
188
260
  <div class="row">
189
261
  <div class="col span-6">
190
- <LabeledSelect
262
+ <ResourceLabeledSelect
191
263
  v-model:value="nodeName"
192
264
  :label="t('workload.scheduling.affinity.nodeName')"
193
- :options="nodes || []"
265
+ :resource-type="NODE"
194
266
  :mode="mode"
195
267
  :multiple="false"
196
268
  :loading="loading"
197
269
  :data-testid="'node-scheduling-nodeSelector'"
270
+ :allResourcesSettings="nodeSchedulingAllSettings"
271
+ :paginatedResourceSettings="nodeSchedulingPaginationSettings"
198
272
  @update:value="update"
199
273
  />
200
274
  </div>
@@ -3,7 +3,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
3
3
  import { Checkbox } from '@components/Form/Checkbox';
4
4
  import { _EDIT, _VIEW } from '@shell/config/query-params';
5
5
 
6
- export default ({
6
+ export default {
7
7
 
8
8
  name: 'NotificationSettings',
9
9
 
@@ -29,7 +29,7 @@ export default ({
29
29
  },
30
30
  },
31
31
 
32
- });
32
+ };
33
33
  </script>
34
34
 
35
35
  <template>
@@ -2,7 +2,7 @@
2
2
  import { mapGetters } from 'vuex';
3
3
  import { _VIEW } from '@shell/config/query-params';
4
4
  import { get, set, isEmpty, clone } from '@shell/utils/object';
5
- import { POD, NODE, NAMESPACE } from '@shell/config/types';
5
+ import { POD, NAMESPACE } from '@shell/config/types';
6
6
  import MatchExpressions from '@shell/components/form/MatchExpressions';
7
7
  import LabeledSelect from '@shell/components/form/LabeledSelect';
8
8
  import { RadioGroup } from '@components/Form/Radio';
@@ -11,7 +11,6 @@ import { randomStr } from '@shell/utils/string';
11
11
  import { sortBy } from '@shell/utils/sort';
12
12
  import debounce from 'lodash/debounce';
13
13
  import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
14
- import { getUniqueLabelKeys } from '@shell/utils/array';
15
14
 
16
15
  const NAMESPACE_SELECTION_OPTION_VALUES = {
17
16
  POD: 'pod',
@@ -47,11 +46,6 @@ export default {
47
46
  default: 'create'
48
47
  },
49
48
 
50
- nodes: {
51
- type: Array,
52
- default: () => []
53
- },
54
-
55
49
  namespaces: {
56
50
  type: Array,
57
51
  default: null
@@ -110,10 +104,6 @@ export default {
110
104
  return POD;
111
105
  },
112
106
 
113
- node() {
114
- return NODE;
115
- },
116
-
117
107
  labeledInputNamespaceLabel() {
118
108
  return this.removeLabeledInputNamespaceLabel ? '' : this.overwriteLabels?.namespaceInputLabel || this.t('workload.scheduling.affinity.matchExpressions.inNamespaces');
119
109
  },
@@ -132,14 +122,6 @@ export default {
132
122
  return out;
133
123
  },
134
124
 
135
- existingNodeLabels() {
136
- return getUniqueLabelKeys(this.nodes);
137
- },
138
-
139
- hasNodes() {
140
- return this.nodes.length;
141
- },
142
-
143
125
  namespaceSelectionOptions() {
144
126
  if (this.allNamespacesOptionAvailable) {
145
127
  return [
@@ -440,24 +422,7 @@ export default {
440
422
  />
441
423
  <div class="row mt-20">
442
424
  <div class="col span-9">
443
- <LabeledSelect
444
- v-if="hasNodes"
445
- v-model:value="props.row.value.topologyKey"
446
- :taggable="true"
447
- :searchable="true"
448
- :close-on-select="false"
449
- :mode="mode"
450
- required
451
- :label="t('workload.scheduling.affinity.topologyKey.label')"
452
- :placeholder="topologyKeyPlaceholder"
453
- :options="existingNodeLabels"
454
- :disabled="mode==='view'"
455
- :loading="loading"
456
- :data-testid="`pod-affinity-topology-select-index${props.i}`"
457
- @update:value="update"
458
- />
459
425
  <LabeledInput
460
- v-else
461
426
  v-model:value="props.row.value.topologyKey"
462
427
  :mode="mode"
463
428
  :label="t('workload.scheduling.affinity.topologyKey.label')"
@@ -137,13 +137,17 @@ export default defineComponent({
137
137
  const filters = !!filter ? [PaginationParamFilter.createSingleField({
138
138
  field: 'metadata.name', value: filter, exact: false
139
139
  })] : [];
140
+ const schema = this.$store.getters[`${ this.validInStore }/schema`](this.resourceType);
141
+ const namespaced = typeof schema?.attributes?.namespaced !== 'undefined' ? schema.attributes.namespaced : false;
142
+
140
143
  const defaultOptions: LabelSelectPaginationFunctionOptions = {
141
144
  opts,
142
145
  filters,
143
- type: this.resourceType,
144
- ctx: { getters: this.$store.getters, dispatch: this.$store.dispatch },
145
- sort: [{ asc: true, field: 'metadata.name' }],
146
- store: this.validInStore
146
+ type: this.resourceType,
147
+ ctx: { getters: this.$store.getters, dispatch: this.$store.dispatch },
148
+ sort: [{ asc: true, field: 'metadata.name' }],
149
+ store: this.validInStore,
150
+ groupByNamespace: namespaced,
147
151
  };
148
152
  const options = this.paginatedResourceSettings?.requestSettings ? this.paginatedResourceSettings.requestSettings(defaultOptions) : defaultOptions;
149
153
  const res = await labelSelectPaginationFunction(options);
@@ -35,11 +35,11 @@ export default {
35
35
  computed: {
36
36
  ...QUOTA_COMPUTED,
37
37
  projectResourceQuotaLimits() {
38
- return this.project?.spec?.resourceQuota?.limit || {};
38
+ return this.flatListFromLimits(this.project?.spec?.resourceQuota?.limit || {});
39
39
  },
40
40
  namespaceResourceQuotaLimits() {
41
41
  return this.project.namespaces.map((namespace) => ({
42
- ...namespace.resourceQuota.limit,
42
+ ...this.flatListFromLimits(namespace.resourceQuota.limit),
43
43
  id: namespace.id
44
44
  }));
45
45
  },
@@ -47,7 +47,7 @@ export default {
47
47
  return Object.keys(this.projectResourceQuotaLimits);
48
48
  },
49
49
  defaultResourceQuotaLimits() {
50
- return this.project.spec.namespaceDefaultResourceQuota.limit;
50
+ return this.flatListFromLimits(this.project.spec.namespaceDefaultResourceQuota.limit || {});
51
51
  }
52
52
  },
53
53
 
@@ -57,14 +57,35 @@ export default {
57
57
  .filter((type) => !this.types.includes(type.value) || type.value === currentType);
58
58
  },
59
59
  update(key, value) {
60
- const resourceQuota = {
61
- limit: {
62
- ...this.value.resourceQuota.limit,
63
- [key]: value
60
+ this.value['resourceQuota'] = { limit: this.limitsFromFlatList(key, value) };
61
+ },
62
+ flatListFromLimits(limit) {
63
+ const result = {};
64
+
65
+ Object.keys(limit || {}).forEach((key) => {
66
+ if (key === 'extended') {
67
+ Object.keys(limit.extended || {}).forEach((extKey) => {
68
+ result[`extended.${ extKey }`] = limit.extended[extKey];
69
+ });
70
+ } else {
71
+ result[key] = limit[key];
64
72
  }
65
- };
73
+ });
74
+
75
+ return result;
76
+ },
77
+ limitsFromFlatList(key, value) {
78
+ const limit = { ...this.value.resourceQuota.limit };
79
+
80
+ if (key.startsWith('extended.')) {
81
+ const resourceIdentifier = key.slice('extended.'.length);
82
+
83
+ limit.extended = { ...(limit.extended || {}), [resourceIdentifier]: value };
84
+ } else {
85
+ limit[key] = value;
86
+ }
66
87
 
67
- this.value['resourceQuota'] = resourceQuota;
88
+ return limit;
68
89
  }
69
90
  },
70
91
  };
@@ -61,17 +61,35 @@ export default {
61
61
  // We want to update the value first so that the value will be rounded to the project limit.
62
62
  // This is relevant when switching projects. If the value is 1200 and the project that it was
63
63
  // switched to only has capacity for 800 more this will force the value to be set to 800.
64
- if (this.value?.limit?.[this.type]) {
65
- this.update(this.value.limit[this.type]);
64
+ if (this.currentLimit) {
65
+ this.update(this.currentLimit);
66
66
  }
67
67
 
68
- if (!this.value?.limit?.[this.type]) {
68
+ if (!this.currentLimit) {
69
69
  this.update(this.defaultResourceQuotaLimits[this.type]);
70
70
  }
71
71
  },
72
72
 
73
73
  computed: {
74
74
  ...ROW_COMPUTED,
75
+ currentLimit() {
76
+ const limit = this.value.limit || {};
77
+
78
+ if (this.type.startsWith('extended.')) {
79
+ const resourceIdentifier = this.type.slice('extended.'.length);
80
+
81
+ return (limit.extended || {})[resourceIdentifier];
82
+ }
83
+
84
+ return limit[this.type];
85
+ },
86
+ displayType() {
87
+ if (this.type.startsWith('extended.')) {
88
+ return this.type.slice('extended.'.length);
89
+ }
90
+
91
+ return this.type;
92
+ },
75
93
  limitValue() {
76
94
  return parseSi(this.projectResourceQuotaLimits[this.type]);
77
95
  },
@@ -92,7 +110,7 @@ export default {
92
110
  return this.namespaceLimits.reduce((sum, limit) => sum + limit, 0);
93
111
  },
94
112
  totalContribution() {
95
- return this.namespaceContribution + parseSi(this.value.limit[this.type] || '0', this.siOptions);
113
+ return this.namespaceContribution + parseSi(this.currentLimit || '0', this.siOptions);
96
114
  },
97
115
  percentageUsed() {
98
116
  return Math.min(this.totalContribution * 100 / this.projectLimit, 100);
@@ -127,7 +145,7 @@ export default {
127
145
  },
128
146
  {
129
147
  label: t('resourceQuota.tooltip.namespace'),
130
- value: this.value.limit[this.type]
148
+ value: this.currentLimit
131
149
  },
132
150
  {
133
151
  label: t('resourceQuota.tooltip.available'),
@@ -178,7 +196,7 @@ export default {
178
196
  <Select
179
197
  class="mr-10"
180
198
  :mode="mode"
181
- :value="type"
199
+ :value="displayType"
182
200
  :disabled="true"
183
201
  :options="types"
184
202
  />
@@ -192,7 +210,7 @@ export default {
192
210
  />
193
211
  </div>
194
212
  <UnitInput
195
- :value="value.limit[type]"
213
+ :value="currentLimit"
196
214
  :mode="mode"
197
215
  :placeholder="typeOption.placeholder"
198
216
  :increment="typeOption.increment"