@rancher/shell 3.0.0-rc.6 → 3.0.0-rc.8

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 (53) hide show
  1. package/assets/styles/global/_tooltip.scss +1 -12
  2. package/assets/translations/en-us.yaml +13 -1
  3. package/chart/monitoring/alerting/index.vue +4 -20
  4. package/chart/monitoring/grafana/index.vue +3 -3
  5. package/chart/monitoring/prometheus/index.vue +7 -14
  6. package/components/CodeMirror.vue +18 -15
  7. package/components/PromptRemove.vue +2 -2
  8. package/components/Questions/index.vue +2 -2
  9. package/components/ResourceDetail/Masthead.vue +1 -0
  10. package/components/ResourceDetail/index.vue +7 -4
  11. package/components/auth/RoleDetailEdit.vue +1 -6
  12. package/components/auth/__tests__/RoleDetailEdit.test.ts +53 -16
  13. package/components/form/ArrayList.vue +7 -3
  14. package/components/form/PodAffinity.vue +1 -1
  15. package/components/formatter/CloudCredExpired.vue +69 -0
  16. package/components/formatter/Date.vue +1 -1
  17. package/components/nav/Header.vue +9 -5
  18. package/components/nav/TopLevelMenu.vue +115 -51
  19. package/components/nav/__tests__/TopLevelMenu.test.ts +49 -23
  20. package/config/labels-annotations.js +9 -5
  21. package/core/types.ts +2 -2
  22. package/detail/provisioning.cattle.io.cluster.vue +0 -4
  23. package/edit/auth/googleoauth.vue +2 -2
  24. package/edit/auth/ldap/config.vue +2 -2
  25. package/edit/auth/oidc.vue +2 -2
  26. package/edit/autoscaling.horizontalpodautoscaler/metrics-row.vue +4 -5
  27. package/edit/management.cattle.io.project.vue +4 -1
  28. package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +1 -5
  29. package/edit/monitoring.coreos.com.alertmanagerconfig/types/slack.vue +1 -5
  30. package/edit/monitoring.coreos.com.receiver/types/slack.vue +1 -5
  31. package/edit/provisioning.cattle.io.cluster/index.vue +7 -2
  32. package/edit/provisioning.cattle.io.cluster/rke2.vue +28 -5
  33. package/edit/service.vue +6 -15
  34. package/list/provisioning.cattle.io.cluster.vue +57 -10
  35. package/machine-config/vmwarevsphere.vue +133 -95
  36. package/mixins/create-edit-view/impl.js +2 -0
  37. package/mixins/labeled-form-element.ts +2 -0
  38. package/models/catalog.cattle.io.app.js +4 -3
  39. package/models/cloudcredential.js +158 -2
  40. package/models/management.cattle.io.globalrole.js +6 -0
  41. package/models/management.cattle.io.roletemplate.js +6 -0
  42. package/models/nodedriver.js +5 -0
  43. package/models/provisioning.cattle.io.cluster.js +35 -1
  44. package/package.json +1 -1
  45. package/pages/c/_cluster/apps/charts/index.vue +0 -6
  46. package/pages/c/_cluster/manager/cloudCredential/index.vue +68 -4
  47. package/pages/home.vue +1 -0
  48. package/plugins/dashboard-store/mutations.js +24 -3
  49. package/plugins/dashboard-store/resource-class.js +6 -0
  50. package/store/type-map.js +4 -2
  51. package/types/shell/index.d.ts +17 -3
  52. package/utils/v-sphere.ts +17 -3
  53. package/vue.config.js +2 -0
@@ -28,11 +28,7 @@ export default {
28
28
  this.value['send_resolved'] = this.value.send_resolved || false;
29
29
 
30
30
  if (this.mode === _CREATE) {
31
- this.$set(
32
- this.value,
33
- 'text',
34
- this.value.text || '{{ template "slack.rancher.text" . }}'
35
- );
31
+ this.value.text = this.value.text || '{{ template "slack.rancher.text" . }}';
36
32
  }
37
33
 
38
34
  return {};
@@ -86,10 +86,15 @@ export default {
86
86
  // These aren't explicitly used, but need to be listening for change events
87
87
  mgmtClusters: this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }),
88
88
  provClusters: this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }),
89
-
90
- catalog: this.$store.dispatch('catalog/load'),
91
89
  };
92
90
 
91
+ // No need to fetch charts when editing an RKE1 cluster
92
+ // The computed property `isRke1` in this file is based on the RKE1/RKE2 toggle, which is not applicable in this case
93
+ // Instead, we should rely on the value from the model: `this.value.isRke1`
94
+ if (!this.value.isRke1 || (this.value.isRke1 && this.mode !== 'edit')) {
95
+ hash['catalog'] = this.$store.dispatch('catalog/load');
96
+ }
97
+
93
98
  if (this.$store.getters[`management/canList`](MANAGEMENT.NODE_DRIVER)) {
94
99
  hash.nodeDrivers = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_DRIVER });
95
100
  }
@@ -42,6 +42,7 @@ import Tabbed from '@shell/components/Tabbed';
42
42
  import { canViewClusterMembershipEditor } from '@shell/components/form/Members/ClusterMembershipEditor';
43
43
  import semver from 'semver';
44
44
 
45
+ import { CLOUD_CREDENTIAL_OVERRIDE } from '@shell/models/nodedriver';
45
46
  import { SETTING } from '@shell/config/settings';
46
47
  import { base64Encode } from '@shell/utils/crypto';
47
48
  import { CAPI as CAPI_ANNOTATIONS, CLUSTER_BADGE } from '@shell/config/labels-annotations';
@@ -413,11 +414,22 @@ export default {
413
414
  },
414
415
 
415
416
  needCredential() {
416
- if (this.provider === 'custom' || this.provider === 'import' || this.isElementalCluster || this.mode === _VIEW || (this.providerConfig?.spec?.builtin === false && this.providerConfig?.spec?.addCloudCredential === false)) {
417
+ // Check non-provider specific config
418
+ if (
419
+ this.provider === 'custom' ||
420
+ this.provider === 'import' ||
421
+ this.isElementalCluster || // Elemental cluster can make use of `cloud-credential`: false
422
+ this.mode === _VIEW
423
+ ) {
417
424
  return false;
418
425
  }
419
426
 
420
- if (this.customCredentialComponentRequired === false) {
427
+ // Check provider specific config
428
+ if (this.cloudCredentialsOverride === true || this.cloudCredentialsOverride === false) {
429
+ return this.cloudCredentialsOverride;
430
+ }
431
+
432
+ if (this.providerConfig?.spec?.builtin === false && this.providerConfig?.spec?.addCloudCredential === false) {
421
433
  return false;
422
434
  }
423
435
 
@@ -425,10 +437,21 @@ export default {
425
437
  },
426
438
 
427
439
  /**
428
- * Only for extensions - extension can register a 'false' cloud credential to indicate that a cloud credential is not needed
440
+ * Override the native way of determining if cloud credentials are required (builtin ++ node driver spec.addCloudCredentials)
441
+ *
442
+ * 1) Override via extensions
443
+ * - `true` or actual component - return true
444
+ * - `false` - return false
445
+ * 2) Override via hardcoded setting
429
446
  */
430
- customCredentialComponentRequired() {
431
- return this.$plugin.getDynamic('cloud-credential', this.provider);
447
+ cloudCredentialsOverride() {
448
+ const cloudCredential = this.$plugin.getDynamic('cloud-credential', this.provider);
449
+
450
+ if (cloudCredential === undefined) {
451
+ return CLOUD_CREDENTIAL_OVERRIDE[this.provider];
452
+ }
453
+
454
+ return !!cloudCredential;
432
455
  },
433
456
 
434
457
  hasMachinePools() {
package/edit/service.vue CHANGED
@@ -226,11 +226,7 @@ export default {
226
226
  this.value.spec.sessionAffinityConfig = { clientIP: { timeoutSeconds: null } };
227
227
 
228
228
  // set it null and then set it with vue to make reactive.
229
- this.$set(
230
- this.value.spec.sessionAffinityConfig.clientIP,
231
- 'timeoutSeconds',
232
- SESSION_STICKY_TIME_DEFAULT
233
- );
229
+ this.value.spec.sessionAffinityConfig.clientIP.timeoutSeconds = SESSION_STICKY_TIME_DEFAULT;
234
230
  } else if (
235
231
  this.value?.spec?.sessionAffinityConfig?.clientIP?.timeoutSeconds
236
232
  ) {
@@ -425,7 +421,7 @@ export default {
425
421
  :mode="mode"
426
422
  :initial-empty-row="true"
427
423
  :protip="false"
428
- @update:value="(e) => $set(value.spec, 'selector', e)"
424
+ @update:value="(e) => value.spec.selector = e"
429
425
  />
430
426
  </div>
431
427
  </div>
@@ -448,7 +444,7 @@ export default {
448
444
  :tooltip-key="
449
445
  hasClusterIp ? 'servicesPage.ips.clusterIpHelpText' : null
450
446
  "
451
- @update:value="(e) => $set(value.spec, 'clusterIP', e)"
447
+ @update:value="(e) => value.spec.clusterIP = e"
452
448
  />
453
449
  </div>
454
450
  </div>
@@ -465,7 +461,7 @@ export default {
465
461
  :tooltip-key="
466
462
  hasClusterIp ? 'servicesPage.ips.loadBalancerIp.helpText' : null
467
463
  "
468
- @update:value="(e) => $set(value.spec, 'loadBalancerIP', e)"
464
+ @update:value="(e) => value.spec.loadBalancerIP = e"
469
465
  />
470
466
  </div>
471
467
  </div>
@@ -478,7 +474,7 @@ export default {
478
474
  :value-placeholder="t('servicesPage.ips.external.placeholder')"
479
475
  :mode="mode"
480
476
  :protip="false"
481
- @update:value="(e) => $set(value.spec, 'externalIPs', e)"
477
+ @update:value="(e) => value.spec.externalIPs = e"
482
478
  />
483
479
  </div>
484
480
  </div>
@@ -527,12 +523,7 @@ export default {
527
523
  :label="t('servicesPage.affinity.timeout.label')"
528
524
  :placeholder="t('servicesPage.affinity.timeout.placeholder')"
529
525
  @input="
530
- (e) =>
531
- $set(
532
- value.spec.sessionAffinityConfig.clientIP,
533
- 'timeoutSeconds',
534
- e
535
- )
526
+ (e) => value.spec.sessionAffinityConfig.clientIP.timeoutSeconds = e
536
527
  "
537
528
  />
538
529
  </div>
@@ -10,10 +10,11 @@ import { mapFeature, HARVESTER as HARVESTER_FEATURE } from '@shell/store/feature
10
10
  import { NAME as EXPLORER } from '@shell/config/product/explorer';
11
11
  import ResourceFetch from '@shell/mixins/resource-fetch';
12
12
  import { BadgeState } from '@components/BadgeState';
13
+ import CloudCredExpired from '@shell/components/formatter/CloudCredExpired';
13
14
 
14
15
  export default {
15
16
  components: {
16
- Banner, ResourceTable, Masthead, BadgeState
17
+ Banner, ResourceTable, Masthead, BadgeState, CloudCredExpired
17
18
  },
18
19
  mixins: [ResourceFetch],
19
20
  props: {
@@ -41,6 +42,8 @@ export default {
41
42
  mgmtClusters: this.$fetchType(MANAGEMENT.CLUSTER),
42
43
  };
43
44
 
45
+ this.$store.dispatch('rancher/findAll', { type: NORMAN.CLOUD_CREDENTIAL });
46
+
44
47
  if ( this.$store.getters['management/canList'](SNAPSHOT) ) {
45
48
  hash.etcdSnapshots = this.$fetchType(SNAPSHOT);
46
49
  }
@@ -141,17 +144,36 @@ export default {
141
144
  // This will be used when there's clusters from extension based provisioners
142
145
  // We should re-visit this for scaling reasons
143
146
  return this.filteredRows.some((c) => c.metadata.namespace !== 'fleet-local' && c.metadata.namespace !== 'fleet-default');
147
+ },
148
+
149
+ tokenExpiredData() {
150
+ const counts = this.rows.reduce((res, provCluster) => {
151
+ const expireData = provCluster.cloudCredential?.expireData;
152
+
153
+ if (expireData?.expiring) {
154
+ res.expiring++;
155
+ }
156
+ if (expireData?.expired) {
157
+ res.expired++;
158
+ }
159
+
160
+ return res;
161
+ }, {
162
+ expiring: 0,
163
+ expired: 0
164
+ });
165
+
166
+ return {
167
+ expiring: counts.expiring ? this.t('cluster.cloudCredentials.banners.expiring', { count: counts.expiring }) : '',
168
+ expired: counts.expired ? this.t('cluster.cloudCredentials.banners.expired', { count: counts.expired }) : '',
169
+ };
144
170
  }
145
171
  },
146
172
 
147
173
  $loadingResources() {
148
174
  // results are filtered so we wouldn't get the correct count on indicator...
149
175
  return { loadIndeterminate: true };
150
- },
151
-
152
- mounted() {
153
- window.c = this;
154
- },
176
+ }
155
177
  };
156
178
  </script>
157
179
 
@@ -186,6 +208,17 @@ export default {
186
208
  </template>
187
209
  </Masthead>
188
210
 
211
+ <Banner
212
+ v-if="tokenExpiredData.expiring"
213
+ color="warning"
214
+ :label="tokenExpiredData.expiring"
215
+ />
216
+ <Banner
217
+ v-if="tokenExpiredData.expired"
218
+ color="error"
219
+ :label="tokenExpiredData.expired"
220
+ />
221
+
189
222
  <ResourceTable
190
223
  :schema="schema"
191
224
  :rows="filteredRows"
@@ -194,6 +227,7 @@ export default {
194
227
  :use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
195
228
  :data-testid="'cluster-list'"
196
229
  :force-update-live-and-delayed="forceUpdateLiveAndDelayed"
230
+ :sub-rows="true"
197
231
  >
198
232
  <!-- Why are state column and subrow overwritten here? -->
199
233
  <!-- for rke1 clusters, where they try to use the mgmt cluster stateObj instead of prov cluster stateObj, -->
@@ -207,19 +241,32 @@ export default {
207
241
  </template>
208
242
  <template #sub-row="{fullColspan, row, keyField, componentTestid, i, onRowMouseEnter, onRowMouseLeave}">
209
243
  <tr
210
- v-if="row.stateDescription"
211
244
  :key="row[keyField] + '-description'"
212
245
  :data-testid="componentTestid + '-' + i + '-row-description'"
213
246
  class="state-description sub-row"
214
247
  @mouseenter="onRowMouseEnter"
215
248
  @mouseleave="onRowMouseLeave"
216
249
  >
217
- <td>&nbsp;</td>
250
+ <td v-if="row.cloudCredentialWarning || row.stateDescription">
251
+ &nbsp;
252
+ </td>
218
253
  <td
254
+ v-if="row.cloudCredentialWarning || row.stateDescription"
219
255
  :colspan="fullColspan - 1"
220
- :class="{ 'text-error' : row.stateObj.error }"
221
256
  >
222
- {{ row.stateDescription }}
257
+ <CloudCredExpired
258
+ v-if="row.cloudCredentialWarning"
259
+ :value="row.cloudCredential.expires"
260
+ :row="row.cloudCredential"
261
+ :verbose="true"
262
+ :class="{'mb-10': row.stateDescription}"
263
+ />
264
+ <div
265
+ v-if="row.stateDescription"
266
+ :class="{ 'text-error' : row.stateObj.error }"
267
+ >
268
+ {{ row.stateDescription }}
269
+ </div>
223
270
  </td>
224
271
  </tr>
225
272
  </template>
@@ -64,48 +64,26 @@ const networksToVappProperties = (networks) => {
64
64
  }
65
65
 
66
66
  return networks.reduce(networkToVappProperties, [
67
- `guestinfo.dns.servers=\${dns:${ networks[0] }}`,
68
- `guestinfo.dns.domains=\${searchPath:${ networks[0] }}`
67
+ `guestinfo.dns.servers=\${dns:${ nameOnly(networks[0]) }}`,
68
+ `guestinfo.dns.domains=\${searchPath:${ nameOnly(networks[0]) }}`
69
69
  ]);
70
70
  };
71
71
 
72
72
  const networkToVappProperties = (props, network, i) => {
73
73
  const n = i.toString();
74
+ const networkName = nameOnly(network);
74
75
 
75
76
  props.push(
76
- `guestinfo.interface.${ n }.ip.0.address=ip:${ network }`,
77
- `guestinfo.interface.${ n }.ip.0.netmask=\${netmask:${ network }}`,
78
- `guestinfo.interface.${ n }.route.0.gateway=\${gateway:${ network }}`
77
+ `guestinfo.interface.${ n }.ip.0.address=ip:${ networkName }`,
78
+ `guestinfo.interface.${ n }.ip.0.netmask=\${netmask:${ networkName }}`,
79
+ `guestinfo.interface.${ n }.route.0.gateway=\${gateway:${ networkName }}`
79
80
  );
80
81
 
81
82
  return props;
82
83
  };
83
84
 
84
- const getInitialVappMode = (c) => {
85
- const vappProperty = c.vappProperty || [];
86
-
87
- if (
88
- !c.vappIpprotocol &&
89
- !c.vappIpallocationpolicy &&
90
- !c.vappTransport &&
91
- vappProperty.length === 0
92
- ) {
93
- return VAPP_MODE.DISABLED;
94
- }
95
-
96
- const d = getDefaultVappOptions(c.network || []);
97
-
98
- if (
99
- c.vappIpprotocol === d.vappIpprotocol &&
100
- c.vappIpallocationpolicy === d.vappIpallocationpolicy &&
101
- c.vappTransport === d.vappTransport &&
102
- vappProperty.length === d.vappProperty.length &&
103
- vappProperty.join() === d.vappProperty.join()
104
- ) {
105
- return VAPP_MODE.AUTO;
106
- }
107
-
108
- return VAPP_MODE.MANUAL;
85
+ const nameOnly = (network) => {
86
+ return network.split('/').pop();
109
87
  };
110
88
 
111
89
  /**
@@ -266,9 +244,10 @@ export default {
266
244
  haveAttributes: null,
267
245
  haveTemplates: null,
268
246
  vAppOptions,
269
- vappMode: getInitialVappMode(this.value),
270
- osOptions: OS_OPTIONS,
271
- validationErrors: {},
247
+ vappMode: VAPP_MODE.DISABLED,
248
+
249
+ osOptions: OS_OPTIONS,
250
+ validationErrors: {},
272
251
  };
273
252
  },
274
253
 
@@ -288,6 +267,21 @@ export default {
288
267
  ...createOptionHelpers('attributeKeys'),
289
268
  ...createOptionHelpers('networks'),
290
269
 
270
+ networkNames() {
271
+ const { network = [] } = this.value;
272
+
273
+ return network.reduce((names, id) => {
274
+ // previously this form used network names instead of ids -- need to account for both possibilities
275
+ const name = this.networks.find((nw) => nw.value === id || nw.name === id)?.name;
276
+
277
+ if (name && !names.includes(name)) {
278
+ names.push(name);
279
+ }
280
+
281
+ return names;
282
+ }, []);
283
+ },
284
+
291
285
  isDisabled() {
292
286
  return this.disabled || this.mode === _VIEW;
293
287
  },
@@ -390,13 +384,14 @@ export default {
390
384
  },
391
385
  vappMode(value) {
392
386
  if (value === VAPP_MODE.AUTO) {
393
- const defaultVappOptions = getDefaultVappOptions(this.value.network || []);
387
+ const defaultVappOptions = getDefaultVappOptions(this.networkNames || []);
394
388
 
395
389
  return this.updateVappOptions(defaultVappOptions);
390
+ } else {
391
+ this.updateVappOptions(INITIAL_VAPP_OPTIONS);
396
392
  }
397
-
398
- this.updateVappOptions(INITIAL_VAPP_OPTIONS);
399
393
  },
394
+
400
395
  validationErrors(value) {
401
396
  this.$emit('error', value);
402
397
  }
@@ -546,12 +541,17 @@ export default {
546
541
  async loadNetworks() {
547
542
  set(this, 'networksResults', null);
548
543
 
549
- const options = await this.requestOptions('networks', this.value.datacenter);
550
- const content = this.mapPathOptionsToContent(options);
544
+ const options = await this.requestOptions('networks-extended', this.value.datacenter);
545
+ const content = options.map((opt) => {
546
+ return {
547
+ label: `${ opt.name } (${ opt.moid })`, value: opt.moid, name: opt.name
548
+ };
549
+ });
551
550
 
552
551
  this.resetValueIfNecessary('network', content, options, true);
553
552
 
554
553
  set(this, 'networksResults', content);
554
+ this.vappMode = this.getInitialVappMode(this.value);
555
555
  },
556
556
 
557
557
  async loadContentLibraries() {
@@ -724,6 +724,34 @@ export default {
724
724
  this.validationErrors = Object.assign({}, this.validationErrors, { [this.poolId]: this.validationErrors[this.poolId].filter((x) => x === key) }) ;
725
725
  }
726
726
  },
727
+
728
+ getInitialVappMode(c) {
729
+ const vappProperty = c.vappProperty || [];
730
+
731
+ if (
732
+ !c.vappIpprotocol &&
733
+ !c.vappIpallocationpolicy &&
734
+ !c.vappTransport &&
735
+ vappProperty.length === 0
736
+ ) {
737
+ return VAPP_MODE.DISABLED;
738
+ }
739
+
740
+ const d = getDefaultVappOptions(this.networkNames || []);
741
+
742
+ if (
743
+ c.vappIpprotocol === d.vappIpprotocol &&
744
+ c.vappIpallocationpolicy === d.vappIpallocationpolicy &&
745
+ c.vappTransport === d.vappTransport &&
746
+ vappProperty.length === d.vappProperty.length &&
747
+ vappProperty.join() === d.vappProperty.join()
748
+ ) {
749
+ return VAPP_MODE.AUTO;
750
+ }
751
+
752
+ return VAPP_MODE.MANUAL;
753
+ }
754
+
727
755
  }
728
756
  };
729
757
  </script>
@@ -1132,68 +1160,78 @@ export default {
1132
1160
  </template>
1133
1161
  <template #body>
1134
1162
  <div>
1135
- <div class="row mb-10">
1136
- <div class="col span-6">
1137
- <RadioGroup
1138
- v-model:value="vappMode"
1139
- name="restoreMode"
1140
- :label="t('cluster.machineConfig.vsphere.vAppOptions.restoreType')"
1141
- :options="vAppOptions"
1142
- :disabled="isDisabled"
1143
- />
1144
- </div>
1145
- </div>
1146
1163
  <div
1147
- v-if="showManual"
1148
- class="row mb-10"
1164
+ v-if="networksLoading"
1165
+ class="row flex-justify-center"
1149
1166
  >
1150
- <div class="col span-4">
1151
- <LabeledInput
1152
- v-model:value="value.vappTransport"
1153
- :mode="mode"
1154
- :label="t('cluster.machineConfig.vsphere.vAppOptions.transport.label')"
1155
- :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.transport.tooltip')"
1156
- :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.transport.placeholder')"
1157
- :disabled="isDisabled"
1158
- />
1159
- </div>
1160
- <div class="col span-4">
1161
- <LabeledInput
1162
- v-model:value="value.vappIpprotocol"
1163
- :mode="mode"
1164
- :label="t('cluster.machineConfig.vsphere.vAppOptions.protocol.label')"
1165
- :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.protocol.tooltip')"
1166
- :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.protocol.placeholder')"
1167
- :disabled="isDisabled"
1168
- />
1167
+ <i
1168
+ class="icon icon-spinner icon-spin"
1169
+ />
1170
+ </div>
1171
+ <template v-else>
1172
+ <div class="row mb-10">
1173
+ <div class="col span-6">
1174
+ <RadioGroup
1175
+ v-model:value="vappMode"
1176
+ name="restoreMode"
1177
+ :label="t('cluster.machineConfig.vsphere.vAppOptions.restoreType')"
1178
+ :options="vAppOptions"
1179
+ :disabled="isDisabled"
1180
+ />
1181
+ </div>
1169
1182
  </div>
1170
- <div class="col span-4">
1171
- <LabeledInput
1172
- v-model:value="value.vappIpallocationpolicy"
1173
- :mode="mode"
1174
- :label="t('cluster.machineConfig.vsphere.vAppOptions.allocation.label')"
1175
- :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.allocation.tooltip')"
1176
- :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.allocation.placeholder')"
1177
- :disabled="isDisabled"
1178
- />
1183
+ <div
1184
+ v-if="showManual"
1185
+ class="row mb-10"
1186
+ >
1187
+ <div class="col span-4">
1188
+ <LabeledInput
1189
+ v-model:value="value.vappTransport"
1190
+ :mode="mode"
1191
+ :label="t('cluster.machineConfig.vsphere.vAppOptions.transport.label')"
1192
+ :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.transport.tooltip')"
1193
+ :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.transport.placeholder')"
1194
+ :disabled="isDisabled"
1195
+ />
1196
+ </div>
1197
+ <div class="col span-4">
1198
+ <LabeledInput
1199
+ v-model:value="value.vappIpprotocol"
1200
+ :mode="mode"
1201
+ :label="t('cluster.machineConfig.vsphere.vAppOptions.protocol.label')"
1202
+ :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.protocol.tooltip')"
1203
+ :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.protocol.placeholder')"
1204
+ :disabled="isDisabled"
1205
+ />
1206
+ </div>
1207
+ <div class="col span-4">
1208
+ <LabeledInput
1209
+ v-model:value="value.vappIpallocationpolicy"
1210
+ :mode="mode"
1211
+ :label="t('cluster.machineConfig.vsphere.vAppOptions.allocation.label')"
1212
+ :tooltip="t('cluster.machineConfig.vsphere.vAppOptions.allocation.tooltip')"
1213
+ :placeholder="t('cluster.machineConfig.vsphere.vAppOptions.allocation.placeholder')"
1214
+ :disabled="isDisabled"
1215
+ />
1216
+ </div>
1179
1217
  </div>
1180
- </div>
1181
- <div
1182
- v-if="showManual"
1183
- class="row"
1184
- >
1185
- <div class="col span-12">
1186
- <KeyValue
1187
- v-model:value="vappProperty"
1188
- :title="t('cluster.machineConfig.vsphere.vAppOptions.properties.label')"
1189
- :key-placeholder="t('cluster.machineConfig.vsphere.vAppOptions.properties.keyPlaceholder')"
1190
- :value-placeholder="t('cluster.machineConfig.vsphere.vAppOptions.properties.valuePlaceholder')"
1191
- :add-label="t('cluster.machineConfig.vsphere.vAppOptions.properties.add')"
1192
- :read-allowed="false"
1193
- :disabled="isDisabled"
1194
- />
1218
+ <div
1219
+ v-if="showManual"
1220
+ class="row"
1221
+ >
1222
+ <div class="col span-12">
1223
+ <KeyValue
1224
+ v-model:value="vappProperty"
1225
+ :title="t('cluster.machineConfig.vsphere.vAppOptions.properties.label')"
1226
+ :key-placeholder="t('cluster.machineConfig.vsphere.vAppOptions.properties.keyPlaceholder')"
1227
+ :value-placeholder="t('cluster.machineConfig.vsphere.vAppOptions.properties.valuePlaceholder')"
1228
+ :add-label="t('cluster.machineConfig.vsphere.vAppOptions.properties.add')"
1229
+ :read-allowed="false"
1230
+ :disabled="isDisabled"
1231
+ />
1232
+ </div>
1195
1233
  </div>
1196
- </div>
1234
+ </template>
1197
1235
  </div>
1198
1236
  </template>
1199
1237
  </Card>
@@ -12,6 +12,8 @@ export default {
12
12
 
13
13
  mixins: [ChildHook],
14
14
 
15
+ emits: ['done'],
16
+
15
17
  data() {
16
18
  // Keep label and annotation filters in data so each resource CRUD page can alter individually
17
19
  return { errors: [] };
@@ -10,6 +10,8 @@ interface LabeledFormElement {
10
10
  export default {
11
11
  inheritAttrs: false,
12
12
 
13
+ emits: ['update:validation', 'on-focus', 'on-blur'],
14
+
13
15
  props: {
14
16
  mode: {
15
17
  type: String,
@@ -55,12 +55,13 @@ export default class CatalogApp extends SteveModel {
55
55
  }
56
56
 
57
57
  const chartName = chart.metadata?.name;
58
- const preferRepoType = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_TYPE];
59
- const preferRepoName = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME];
58
+ const repoName = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME] || this.metadata?.labels?.[CATALOG_ANNOTATIONS.CLUSTER_REPO_NAME];
59
+ const preferRepoType = chart.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_TYPE] || 'cluster';
60
+
60
61
  const match = this.$rootGetters['catalog/chart']({
61
62
  chartName,
63
+ repoName,
62
64
  preferRepoType,
63
- preferRepoName,
64
65
  includeHidden
65
66
  });
66
67