@rancher/shell 3.0.6 → 3.0.8-rc.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 (146) hide show
  1. package/assets/images/pl/dark/rancher-logo.svg +131 -44
  2. package/assets/images/pl/rancher-logo.svg +120 -44
  3. package/assets/images/vendor/githubapp.svg +13 -0
  4. package/assets/styles/base/_basic.scss +2 -2
  5. package/assets/styles/base/_color-classic.scss +51 -0
  6. package/assets/styles/base/_color.scss +3 -3
  7. package/assets/styles/base/_mixins.scss +1 -1
  8. package/assets/styles/base/_typography.scss +1 -1
  9. package/assets/styles/base/_variables-classic.scss +47 -0
  10. package/assets/styles/global/_button.scss +49 -17
  11. package/assets/styles/global/_form.scss +1 -1
  12. package/assets/styles/themes/_dark.scss +4 -0
  13. package/assets/styles/themes/_light.scss +3 -69
  14. package/assets/styles/themes/_modern.scss +194 -50
  15. package/assets/styles/vendor/vue-select.scss +1 -2
  16. package/assets/translations/en-us.yaml +124 -32
  17. package/assets/translations/zh-hans.yaml +0 -4
  18. package/components/ClusterIconMenu.vue +1 -1
  19. package/components/ClusterProviderIcon.vue +1 -1
  20. package/components/CodeMirror.vue +1 -1
  21. package/components/IconOrSvg.vue +40 -29
  22. package/components/Inactivity.vue +222 -106
  23. package/components/InstallHelmCharts.vue +2 -2
  24. package/components/ResourceDetail/index.vue +2 -1
  25. package/components/SortableTable/index.vue +17 -2
  26. package/components/SortableTable/sorting.js +3 -1
  27. package/components/Tabbed/index.vue +5 -5
  28. package/components/fleet/FleetConfigMapSelector.vue +117 -0
  29. package/components/fleet/FleetSecretSelector.vue +127 -0
  30. package/components/fleet/__tests__/FleetConfigMapSelector.test.ts +125 -0
  31. package/components/fleet/__tests__/FleetSecretSelector.test.ts +82 -0
  32. package/components/form/FileImageSelector.vue +13 -4
  33. package/components/form/FileSelector.vue +11 -2
  34. package/components/form/ResourceLabeledSelect.vue +1 -0
  35. package/components/form/ResourceTabs/index.vue +37 -18
  36. package/components/form/SecretSelector.vue +6 -2
  37. package/components/form/__tests__/ResourceLabeledSelect.test.ts +90 -0
  38. package/components/nav/Group.vue +29 -9
  39. package/components/nav/Header.vue +7 -8
  40. package/components/nav/NamespaceFilter.vue +1 -1
  41. package/components/nav/TopLevelMenu.helper.ts +47 -20
  42. package/components/nav/TopLevelMenu.vue +44 -14
  43. package/components/nav/Type.vue +0 -5
  44. package/components/nav/__tests__/TopLevelMenu.test.ts +2 -0
  45. package/config/pagination-table-headers.js +10 -2
  46. package/config/product/auth.js +1 -0
  47. package/config/product/explorer.js +4 -3
  48. package/config/query-params.js +1 -0
  49. package/config/settings.ts +8 -1
  50. package/config/table-headers.js +9 -0
  51. package/config/types.js +2 -0
  52. package/core/plugin.ts +18 -6
  53. package/core/types.ts +8 -0
  54. package/detail/provisioning.cattle.io.cluster.vue +1 -0
  55. package/dialog/AddonConfigConfirmationDialog.vue +45 -1
  56. package/dialog/InstallExtensionDialog.vue +71 -45
  57. package/dialog/UninstallExtensionDialog.vue +2 -1
  58. package/dialog/__tests__/InstallExtensionDialog.test.ts +111 -0
  59. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +52 -11
  60. package/edit/auth/AuthProviderWarningBanners.vue +14 -1
  61. package/edit/auth/github-app-steps.vue +97 -0
  62. package/edit/auth/github-steps.vue +75 -0
  63. package/edit/auth/github.vue +94 -65
  64. package/edit/auth/oidc.vue +86 -16
  65. package/edit/fleet.cattle.io.helmop.vue +51 -2
  66. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +15 -5
  67. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +11 -9
  68. package/edit/provisioning.cattle.io.cluster/rke2.vue +56 -9
  69. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +28 -2
  70. package/list/projectsecret.vue +1 -1
  71. package/machine-config/azure.vue +1 -1
  72. package/mixins/__tests__/chart.test.ts +1 -1
  73. package/mixins/chart.js +2 -2
  74. package/models/__tests__/chart.test.ts +17 -9
  75. package/models/__tests__/compliance.cattle.io.clusterscanprofile.spec.js +30 -0
  76. package/models/catalog.cattle.io.app.js +1 -1
  77. package/models/chart.js +3 -1
  78. package/models/compliance.cattle.io.clusterscanprofile.js +1 -1
  79. package/models/event.js +7 -0
  80. package/models/management.cattle.io.authconfig.js +1 -0
  81. package/models/provisioning.cattle.io.cluster.js +9 -0
  82. package/package.json +2 -2
  83. package/pages/auth/login.vue +5 -2
  84. package/pages/auth/verify.vue +1 -1
  85. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +3 -2
  86. package/pages/c/_cluster/apps/charts/chart.vue +2 -2
  87. package/pages/c/_cluster/explorer/EventsTable.vue +92 -9
  88. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  89. package/pages/c/_cluster/settings/performance.vue +13 -26
  90. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +159 -62
  91. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +102 -0
  92. package/pages/c/_cluster/uiplugins/__tests__/{index.spec.ts → index.test.ts} +121 -55
  93. package/pages/c/_cluster/uiplugins/index.vue +110 -94
  94. package/pages/home.vue +313 -12
  95. package/plugins/__tests__/subscribe.events.test.ts +194 -0
  96. package/plugins/axios.js +2 -1
  97. package/plugins/dashboard-store/actions.js +4 -1
  98. package/plugins/dashboard-store/getters.js +1 -1
  99. package/plugins/dashboard-store/resource-class.js +20 -5
  100. package/plugins/steve/__tests__/subscribe.spec.ts +27 -24
  101. package/plugins/steve/index.js +18 -10
  102. package/plugins/steve/mutations.js +2 -2
  103. package/plugins/steve/resourceWatcher.js +2 -2
  104. package/plugins/steve/steve-pagination-utils.ts +12 -9
  105. package/plugins/steve/subscribe.js +113 -85
  106. package/plugins/subscribe-events.ts +211 -0
  107. package/rancher-components/BadgeState/BadgeState.vue +8 -6
  108. package/rancher-components/Banner/Banner.vue +2 -1
  109. package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
  110. package/rancher-components/Form/Radio/RadioButton.vue +3 -3
  111. package/scripts/extension/publish +1 -1
  112. package/store/auth.js +8 -3
  113. package/store/aws.js +8 -6
  114. package/store/features.js +1 -0
  115. package/store/index.js +21 -25
  116. package/store/prefs.js +6 -0
  117. package/types/extension-manager.ts +8 -1
  118. package/types/kube/kube-api.ts +2 -1
  119. package/types/rancher/index.d.ts +1 -0
  120. package/types/resources/settings.d.ts +52 -23
  121. package/types/shell/index.d.ts +412 -336
  122. package/types/store/subscribe-events.types.ts +70 -0
  123. package/types/store/subscribe.types.ts +6 -22
  124. package/utils/__tests__/cluster.test.ts +379 -1
  125. package/utils/cluster.js +157 -3
  126. package/utils/dynamic-content/__tests__/config.test.ts +187 -0
  127. package/utils/dynamic-content/__tests__/index.test.ts +390 -0
  128. package/utils/dynamic-content/__tests__/info.test.ts +263 -0
  129. package/utils/dynamic-content/__tests__/new-release.test.ts +216 -0
  130. package/utils/dynamic-content/__tests__/support-notice.test.ts +262 -0
  131. package/utils/dynamic-content/__tests__/util.test.ts +235 -0
  132. package/utils/dynamic-content/config.ts +55 -0
  133. package/utils/dynamic-content/index.ts +273 -0
  134. package/utils/dynamic-content/info.ts +219 -0
  135. package/utils/dynamic-content/new-release.ts +126 -0
  136. package/utils/dynamic-content/support-notice.ts +169 -0
  137. package/utils/dynamic-content/types.d.ts +101 -0
  138. package/utils/dynamic-content/util.ts +122 -0
  139. package/utils/inactivity.ts +104 -0
  140. package/utils/pagination-utils.ts +105 -31
  141. package/utils/pagination-wrapper.ts +6 -8
  142. package/utils/release-notes.ts +1 -1
  143. package/utils/sort.js +5 -0
  144. package/utils/unit-tests/pagination-utils.spec.ts +283 -0
  145. package/utils/validators/formRules/__tests__/index.test.ts +7 -0
  146. package/utils/validators/formRules/index.ts +2 -2
@@ -4,16 +4,15 @@ import CreateEditView from '@shell/mixins/create-edit-view';
4
4
  import CruResource from '@shell/components/CruResource';
5
5
  import { RadioGroup } from '@components/Form/Radio';
6
6
  import { LabeledInput } from '@components/Form/LabeledInput';
7
- import CopyToClipboard from '@shell/components/CopyToClipboard';
8
7
  import AllowedPrincipals from '@shell/components/auth/AllowedPrincipals';
9
8
  import { MANAGEMENT } from '@shell/config/types';
10
9
  import { findBy } from '@shell/utils/array';
11
10
  import AuthConfig from '@shell/mixins/auth-config';
12
11
  import AuthBanner from '@shell/components/auth/AuthBanner';
13
- import InfoBox from '@shell/components/InfoBox';
14
12
  import AuthProviderWarningBanners from '@shell/edit/auth/AuthProviderWarningBanners';
15
-
16
- const NAME = 'github';
13
+ import FileSelector from '@shell/components/form/FileSelector';
14
+ import GithubSteps from '@shell/edit/auth/github-steps.vue';
15
+ import GithubAppSteps from '@shell/edit/auth/github-app-steps.vue';
17
16
 
18
17
  export default {
19
18
  components: {
@@ -21,11 +20,12 @@ export default {
21
20
  CruResource,
22
21
  RadioGroup,
23
22
  LabeledInput,
24
- CopyToClipboard,
25
23
  AllowedPrincipals,
26
24
  AuthBanner,
27
- InfoBox,
28
- AuthProviderWarningBanners
25
+ AuthProviderWarningBanners,
26
+ FileSelector,
27
+ GithubSteps,
28
+ GithubAppSteps,
29
29
  },
30
30
 
31
31
  mixins: [CreateEditView, AuthConfig],
@@ -60,7 +60,7 @@ export default {
60
60
  },
61
61
 
62
62
  displayName() {
63
- return this.t(`model.authConfig.provider.${ NAME }`);
63
+ return this.t(`model.authConfig.provider.${ this.NAME }`);
64
64
  },
65
65
 
66
66
  tArgs() {
@@ -73,7 +73,7 @@ export default {
73
73
  },
74
74
 
75
75
  NAME() {
76
- return NAME;
76
+ return this.isGithubApp ? 'githubapp' : 'github';
77
77
  },
78
78
 
79
79
  AUTH_CONFIG() {
@@ -86,7 +86,27 @@ export default {
86
86
  githubConfig: this.model,
87
87
  description: 'Enable GitHub',
88
88
  };
89
- }
89
+ },
90
+
91
+ isGithubApp() {
92
+ return this.model?.id === 'githubapp';
93
+ },
94
+
95
+ steps() {
96
+ return this.isGithubApp ? GithubAppSteps : GithubSteps;
97
+ },
98
+
99
+ validationPassed() {
100
+ if (!this.model.clientId || !this.model.clientSecret) {
101
+ return false;
102
+ }
103
+
104
+ if (this.isGithubApp && (!this.model.appId || !this.model.privateKey)) {
105
+ return false;
106
+ }
107
+
108
+ return true;
109
+ },
90
110
 
91
111
  },
92
112
 
@@ -109,6 +129,10 @@ export default {
109
129
  this.model.hostname = match[4] || 'github.com';
110
130
  }
111
131
  },
132
+
133
+ updatePrivateKey(content) {
134
+ this.model.privateKey = content;
135
+ },
112
136
  },
113
137
  };
114
138
  </script>
@@ -122,7 +146,7 @@ export default {
122
146
  :mode="mode"
123
147
  :resource="model"
124
148
  :subtypes="[]"
125
- :validation-passed="true"
149
+ :validation-passed="validationPassed"
126
150
  :finish-button-mode="model.enabled ? 'edit' : 'enable'"
127
151
  :can-yaml="false"
128
152
  :errors="errors"
@@ -139,7 +163,7 @@ export default {
139
163
  >
140
164
  <template #rows>
141
165
  <tr><td>{{ t(`authConfig.${ NAME }.table.server`) }}: </td><td>{{ baseUrl }}</td></tr>
142
- <tr><td>{{ t(`authConfig.${ NAME }.table.clientId`) }}: </td><td>{{ value.clientId }}</td></tr>
166
+ <tr><td>{{ t(`authConfig.${ NAME }.table.clientId`) }}: </td><td>{{ model.clientId }}</td></tr>
143
167
  </template>
144
168
  </AuthBanner>
145
169
 
@@ -156,7 +180,17 @@ export default {
156
180
  <AuthProviderWarningBanners
157
181
  v-if="!model.enabled"
158
182
  :t-args="tArgs"
159
- />
183
+ >
184
+ <template
185
+ v-if="isGithubApp"
186
+ #additional-warning
187
+ >
188
+ <span
189
+ v-clean-html="t(`authConfig.${NAME}.warning`, {}, true)"
190
+ data-testid="github-app-banner"
191
+ />
192
+ </template>
193
+ </AuthProviderWarningBanners>
160
194
 
161
195
  <h3 v-t="`authConfig.${NAME}.target.label`" />
162
196
  <RadioGroup
@@ -182,60 +216,18 @@ export default {
182
216
  </div>
183
217
  </div>
184
218
 
185
- <InfoBox
186
- :step="1"
187
- class="step-box"
188
- >
189
- <ul class="step-list">
190
- <li v-clean-html="t(`authConfig.${NAME}.form.prefix.1`, tArgs, true)" />
191
- <li v-clean-html="t(`authConfig.${NAME}.form.prefix.2`, tArgs, true)" />
192
- <li v-clean-html="t(`authConfig.${NAME}.form.prefix.3`, tArgs, true)" />
193
- </ul>
194
- </InfoBox>
195
- <InfoBox
196
- :step="2"
197
- class="step-box"
198
- >
199
- <ul class="step-list">
200
- <li>
201
- {{ t(`authConfig.${NAME}.form.instruction`, tArgs, true) }}
202
- <ul class="mt-10">
203
- <li><b>{{ t(`authConfig.${NAME}.form.app.label`) }}</b>: <span v-clean-html="t(`authConfig.${NAME}.form.app.value`, tArgs, true)" /></li>
204
- <li>
205
- <b>{{ t(`authConfig.${NAME}.form.homepage.label`) }}</b>: {{ serverUrl }} <CopyToClipboard
206
- label-as="tooltip"
207
- :text="serverUrl"
208
- class="icon-btn"
209
- action-color="bg-transparent"
210
- />
211
- </li>
212
- <li><b>{{ t(`authConfig.${NAME}.form.description.label`) }}</b>: <span v-clean-html="t(`authConfig.${NAME}.form.description.value`, tArgs, true)" /></li>
213
- <li>
214
- <b>{{ t(`authConfig.${NAME}.form.callback.label`) }}</b>: {{ serverUrl }} <CopyToClipboard
215
- :text="serverUrl"
216
- label-as="tooltip"
217
- class="icon-btn"
218
- action-color="bg-transparent"
219
- />
220
- </li>
221
- </ul>
222
- </li>
223
- </ul>
224
- </InfoBox>
225
- <InfoBox
226
- :step="3"
227
- class="mb-20"
228
- >
229
- <ul class="step-list">
230
- <li v-clean-html="t(`authConfig.${NAME}.form.suffix.1`, tArgs, true)" />
231
- <li v-clean-html="t(`authConfig.${NAME}.form.suffix.2`, tArgs, true)" />
232
- </ul>
233
- </InfoBox>
219
+ <component
220
+ :is="steps"
221
+ :t-args="tArgs"
222
+ :name="NAME"
223
+ />
234
224
 
235
225
  <div class="row mb-20">
236
226
  <div class="col span-6">
237
227
  <LabeledInput
238
228
  v-model:value="model.clientId"
229
+ required
230
+ data-testid="client-id"
239
231
  :label="t(`authConfig.${NAME}.clientId.label`)"
240
232
  :mode="mode"
241
233
  />
@@ -243,21 +235,58 @@ export default {
243
235
  <div class="col span-6">
244
236
  <LabeledInput
245
237
  v-model:value="model.clientSecret"
238
+ required
239
+ data-testid="client-secret"
246
240
  type="password"
247
241
  :label="t(`authConfig.${NAME}.clientSecret.label`)"
248
242
  :mode="mode"
249
243
  />
250
244
  </div>
251
245
  </div>
246
+ <template v-if="isGithubApp">
247
+ <div class="row mb-20">
248
+ <div class="col span-6">
249
+ <LabeledInput
250
+ v-model:value="model.appId"
251
+ required
252
+ data-testid="app-id"
253
+ :label="t(`authConfig.${NAME}.githubAppId.label`)"
254
+ :mode="mode"
255
+ />
256
+ </div>
257
+ <div class="col span-6">
258
+ <LabeledInput
259
+ v-model:value="model.installationId"
260
+ data-testid="installation-id"
261
+ :label="t(`authConfig.${NAME}.installationId.label`)"
262
+ :mode="mode"
263
+ />
264
+ </div>
265
+ </div>
266
+ <div class="row mb-20">
267
+ <div class="col span-6">
268
+ <LabeledInput
269
+ v-model:value="model.privateKey"
270
+ required
271
+ data-testid="private-key"
272
+ type="multiline"
273
+ :label="t(`authConfig.${NAME}.privateKey.label`)"
274
+ :mode="mode"
275
+ />
276
+ <FileSelector
277
+ class="btn btn-sm role-secondary mt-10"
278
+ :label="t('generic.readFromFile')"
279
+ @selected="updatePrivateKey"
280
+ />
281
+ </div>
282
+ </div>
283
+ </template>
252
284
  </template>
253
285
  </CruResource>
254
286
  </div>
255
287
  </template>
256
288
 
257
289
  <style lang="scss" scoped>
258
- .step-list li:not(:last-child) {
259
- margin-bottom: 8px;
260
- }
261
290
  .banner {
262
291
  display: block;
263
292
 
@@ -59,11 +59,16 @@ export default {
59
59
  userInfoEndpoint: null,
60
60
  },
61
61
  // TODO #13457: this is duplicated due wrong format
62
- oidcScope: [],
63
- SLO_OPTION_VALUES
62
+ oidcScope: [],
63
+ SLO_OPTION_VALUES,
64
+ addCustomClaims: false,
64
65
  };
65
66
  },
66
67
 
68
+ created() {
69
+ this.registerBeforeHook(this.willSave, 'willSave');
70
+ },
71
+
67
72
  computed: {
68
73
  tArgs() {
69
74
  return {
@@ -140,6 +145,10 @@ export default {
140
145
  return this.model?.id === 'cognito';
141
146
  },
142
147
 
148
+ isGenericOidc() {
149
+ return this.model?.id === 'genericoidc';
150
+ },
151
+
143
152
  isLogoutAllSupported() {
144
153
  return this.model?.logoutAllSupported;
145
154
  },
@@ -220,6 +229,15 @@ export default {
220
229
  this.model.logoutAllForced = false;
221
230
  break;
222
231
  }
232
+ },
233
+
234
+ model: {
235
+ handler(newVal) {
236
+ if (newVal?.nameClaim || newVal?.groupsClaim || newVal?.emailClaim) {
237
+ this.addCustomClaims = true;
238
+ }
239
+ },
240
+ once: true
223
241
  }
224
242
  },
225
243
 
@@ -248,6 +266,14 @@ export default {
248
266
 
249
267
  updateScope() {
250
268
  this.model.scope = this.oidcScope.join(' ');
269
+ },
270
+
271
+ willSave() {
272
+ if (this.isGenericOidc && !this.addCustomClaims) {
273
+ this.model.nameClaim = undefined;
274
+ this.model.groupsClaim = undefined;
275
+ this.model.emailClaim = undefined;
276
+ }
251
277
  }
252
278
  }
253
279
  };
@@ -390,21 +416,60 @@ export default {
390
416
  </div>
391
417
  </div>
392
418
 
393
- <!-- Allow group search -->
394
- <div
395
- v-if="supportsGroupSearch"
396
- class="row mb-20"
397
- >
398
- <div class="col span-6">
399
- <Checkbox
400
- v-model:value="model.groupSearchEnabled"
401
- data-testid="input-group-search"
402
- :label="t('authConfig.oidc.groupSearch.label')"
403
- :tooltip="t('authConfig.oidc.groupSearch.tooltip')"
404
- :mode="mode"
405
- />
419
+ <template v-if="isGenericOidc || supportsGroupSearch">
420
+ <div
421
+ class="row mb-20"
422
+ >
423
+ <div class="col span-6 checkbox-flex">
424
+ <!-- Allow group search -->
425
+ <Checkbox
426
+ v-if="supportsGroupSearch"
427
+ v-model:value="model.groupSearchEnabled"
428
+ data-testid="input-group-search"
429
+ :label="t('authConfig.oidc.groupSearch.label')"
430
+ :tooltip="t('authConfig.oidc.groupSearch.tooltip')"
431
+ :mode="mode"
432
+ />
433
+ <Checkbox
434
+ v-if="isGenericOidc"
435
+ v-model:value="addCustomClaims"
436
+ data-testid="input-add-custom-claims"
437
+ :label="t('authConfig.oidc.customClaims.enable.label')"
438
+ :tooltip="t('authConfig.oidc.customClaims.enable.tooltip')"
439
+ :mode="mode"
440
+ />
441
+ </div>
406
442
  </div>
407
- </div>
443
+ </template>
444
+
445
+ <template v-if="addCustomClaims">
446
+ <h4>{{ t('authConfig.oidc.customClaims.label') }}</h4>
447
+ <div class="row mb-20">
448
+ <div class="col span-6">
449
+ <LabeledInput
450
+ v-model:value="model.nameClaim"
451
+ :label="t(`authConfig.oidc.customClaims.nameClaim.label`)"
452
+ :mode="mode"
453
+ />
454
+ </div>
455
+ <div class="col span-6">
456
+ <LabeledInput
457
+ v-model:value="model.groupsClaim"
458
+ :label="t(`authConfig.oidc.customClaims.groupsClaim.label`)"
459
+ :mode="mode"
460
+ />
461
+ </div>
462
+ </div>
463
+ <div class="row mb-20">
464
+ <div class="col span-6">
465
+ <LabeledInput
466
+ v-model:value="model.emailClaim"
467
+ :label="t(`authConfig.oidc.customClaims.emailClaim.label`)"
468
+ :mode="mode"
469
+ />
470
+ </div>
471
+ </div>
472
+ </template>
408
473
 
409
474
  <!-- Scopes -->
410
475
  <div class="row mb-20">
@@ -608,4 +673,9 @@ export default {
608
673
  margin: 0 3px;
609
674
  }
610
675
  }
676
+
677
+ .checkbox-flex {
678
+ display: flex;
679
+ flex-direction: column;
680
+ }
611
681
  </style>
@@ -29,6 +29,8 @@ import UnitInput from '@shell/components/form/UnitInput';
29
29
  import FleetClusterTargets from '@shell/components/fleet/FleetClusterTargets/index.vue';
30
30
  import { toSeconds } from '@shell/utils/duration';
31
31
  import FleetValuesFrom from '@shell/components/fleet/FleetValuesFrom.vue';
32
+ import FleetSecretSelector from '@shell/components/fleet/FleetSecretSelector.vue';
33
+ import FleetConfigMapSelector from '@shell/components/fleet/FleetConfigMapSelector.vue';
32
34
 
33
35
  const MINIMUM_POLLING_INTERVAL = 15;
34
36
 
@@ -50,6 +52,8 @@ export default {
50
52
  Checkbox,
51
53
  CruResource,
52
54
  FleetClusterTargets,
55
+ FleetConfigMapSelector,
56
+ FleetSecretSelector,
53
57
  FleetValuesFrom,
54
58
  YamlEditor,
55
59
  LabeledInput,
@@ -230,7 +234,15 @@ export default {
230
234
  }
231
235
 
232
236
  return null;
233
- }
237
+ },
238
+
239
+ downstreamSecretsList() {
240
+ return (this.value.spec.helm.downstreamResources || []).filter((r) => r.kind === 'Secret').map((r) => r.name);
241
+ },
242
+
243
+ downstreamConfigMapsList() {
244
+ return (this.value.spec.helm.downstreamResources || []).filter((r) => r.kind === 'ConfigMap').map((r) => r.name);
245
+ },
234
246
  },
235
247
 
236
248
  watch: {
@@ -429,7 +441,24 @@ export default {
429
441
  }];
430
442
  break;
431
443
  }
432
- }
444
+ },
445
+
446
+ updateDownstreamResources(kind, list) {
447
+ switch (kind) {
448
+ case 'Secret':
449
+ this.value.spec.helm.downstreamResources = [
450
+ ...(this.value.spec.helm.downstreamResources || []).filter((r) => r.kind !== 'Secret'),
451
+ ...(list || []).map((name) => ({ name, kind: 'Secret' })),
452
+ ];
453
+ break;
454
+ case 'ConfigMap':
455
+ this.value.spec.helm.downstreamResources = [
456
+ ...(this.value.spec.helm.downstreamResources || []).filter((r) => r.kind !== 'ConfigMap'),
457
+ ...(list || []).map((name) => ({ name, kind: 'ConfigMap' })),
458
+ ];
459
+ break;
460
+ }
461
+ },
433
462
  },
434
463
  };
435
464
  </script>
@@ -711,6 +740,26 @@ export default {
711
740
 
712
741
  <h2 v-t="'fleet.helmOp.resources.label'" />
713
742
 
743
+ <div class="row mt-20 mb-20">
744
+ <div class="col span-6">
745
+ <FleetSecretSelector
746
+ :value="downstreamSecretsList"
747
+ :namespace="value.metadata.namespace"
748
+ :mode="mode"
749
+ @update:value="updateDownstreamResources('Secret', $event)"
750
+ />
751
+ </div>
752
+ </div>
753
+ <div class="row mt-20 mb-20">
754
+ <div class="col span-6">
755
+ <FleetConfigMapSelector
756
+ :value="downstreamConfigMapsList"
757
+ :namespace="value.metadata.namespace"
758
+ :mode="mode"
759
+ @update:value="updateDownstreamResources('ConfigMap', $event)"
760
+ />
761
+ </div>
762
+ </div>
714
763
  <div class="resource-handling mb-30">
715
764
  <Checkbox
716
765
  v-model:value="correctDriftEnabled"
@@ -149,25 +149,35 @@ export default {
149
149
  },
150
150
  watch: {
151
151
  namespace: {
152
- handler: 'debouncedUpdateMatches',
152
+ handler() {
153
+ this.debouncedUpdateMatches();
154
+ },
153
155
  immediate: true
154
156
  },
155
157
  'value.podSelector': {
156
- handler: 'debouncedUpdateMatches',
158
+ handler() {
159
+ this.debouncedUpdateMatches();
160
+ },
157
161
  immediate: true
158
162
  },
159
163
  'value.namespaceSelector': {
160
- handler: 'debouncedUpdateMatches',
164
+ handler() {
165
+ this.debouncedUpdateMatches();
166
+ },
161
167
  immediate: true
162
168
  },
163
169
  'value.ipBlock.cidr': 'validateCIDR',
164
170
  'value.ipBlock.except': 'validateCIDR',
165
171
  podSelectorExpressions: {
166
- handler: 'debouncedUpdateMatches',
172
+ handler() {
173
+ this.debouncedUpdateMatches();
174
+ },
167
175
  immediate: true
168
176
  },
169
177
  namespaceSelectorExpressions: {
170
- handler: 'debouncedUpdateMatches',
178
+ handler() {
179
+ this.debouncedUpdateMatches();
180
+ },
171
181
  immediate: true
172
182
  }
173
183
  },
@@ -475,16 +475,17 @@ describe('component: rke2', () => {
475
475
  },
476
476
  provider: 'custom'
477
477
  },
478
- data: () => ({
479
- agentArgs: {
478
+ computed: {
479
+ ...rke2.computed,
480
+ agentArgs: () => ({
480
481
  'cloud-provider-name': {
481
482
  options: [
482
483
  'azure',
483
484
  'amazon'
484
485
  ]
485
486
  }
486
- }
487
- }),
487
+ })
488
+ },
488
489
  global: {
489
490
  mocks: {
490
491
  ...defaultMocks,
@@ -519,9 +520,10 @@ describe('component: rke2', () => {
519
520
  },
520
521
  provider: 'custom'
521
522
  },
522
- data: () => ({
523
- canAzureMigrateOnEdit: true,
524
- agentArgs: {
523
+ computed: {
524
+ ...rke2.computed,
525
+ canAzureMigrateOnEdit: () => true,
526
+ agentArgs: () => ({
525
527
  'cloud-provider-name': {
526
528
  options: [
527
529
  'azure',
@@ -529,8 +531,8 @@ describe('component: rke2', () => {
529
531
  'external'
530
532
  ]
531
533
  }
532
- }
533
- }),
534
+ })
535
+ },
534
536
  global: {
535
537
  mocks: {
536
538
  ...defaultMocks,
@@ -28,7 +28,7 @@ import {
28
28
  } from '@shell/utils/object';
29
29
  import { allHash } from '@shell/utils/promise';
30
30
  import {
31
- getAllOptionsAfterCurrentVersion, filterOutDeprecatedPatchVersions, isHarvesterSatisfiesVersion, labelForAddon, initSchedulingCustomization
31
+ getAllOptionsAfterCurrentVersion, filterOutDeprecatedPatchVersions, isHarvesterSatisfiesVersion, labelForAddon, initSchedulingCustomization, addonConfigPreserve
32
32
  } from '@shell/utils/cluster';
33
33
 
34
34
  import { BadgeState } from '@components/BadgeState';
@@ -162,6 +162,10 @@ export default {
162
162
  this.schedulingCustomizationOriginallyEnabled = sc.schedulingCustomizationOriginallyEnabled;
163
163
  this.errors = this.errors.concat(sc.errors);
164
164
 
165
+ if (this.isEdit) {
166
+ this.originalKubeVersion = this.versionOptions.find((v) => v.value === this.liveValue.spec.kubernetesVersion);
167
+ }
168
+
165
169
  Object.entries(this.chartValues).forEach(([name, value]) => {
166
170
  const key = this.chartVersionKey(name);
167
171
 
@@ -278,6 +282,9 @@ export default {
278
282
  REGISTRIES_TAB_NAME,
279
283
  labelForAddon,
280
284
  etcdConfigValid: true,
285
+ addonConfigDiffs: {},
286
+ originalKubeVersion: null,
287
+ isEmpty,
281
288
  };
282
289
  },
283
290
 
@@ -921,8 +928,22 @@ export default {
921
928
  }
922
929
  },
923
930
 
924
- selectedVersion() {
925
- this.versionInfo = {}; // Invalidate cache such that version info relevent to selected kube version is updated
931
+ async selectedVersion(neu) {
932
+ if (this.isEdit) {
933
+ const {
934
+ addonConfigDiffs, addonNames, userChartValues, $store
935
+ } = this;
936
+
937
+ await addonConfigPreserve(
938
+ {
939
+ addonConfigDiffs, addonNames, userChartValues, $store
940
+ },
941
+ this.originalKubeVersion?.charts,
942
+ neu?.charts
943
+ );
944
+ }
945
+
946
+ this.versionInfo = {}; // Invalidate cache such that version info relevant to selected kube version is updated
926
947
 
927
948
  // Allow time for addonNames to update... then fetch any missing addons
928
949
  this.$nextTick(() => this.initAddons());
@@ -1511,10 +1532,15 @@ export default {
1511
1532
  });
1512
1533
  },
1513
1534
 
1514
- showAddonConfirmation() {
1515
- return new Promise((resolve, reject) => {
1535
+ showAddonConfirmation(addonNames, previousKubeVersion, newKubeVersion) {
1536
+ return new Promise((resolve) => {
1516
1537
  this.$store.dispatch('cluster/promptModal', {
1517
- component: 'AddonConfigConfirmationDialog',
1538
+ component: 'AddonConfigConfirmationDialog',
1539
+ componentProps: {
1540
+ addonNames,
1541
+ previousKubeVersion,
1542
+ newKubeVersion
1543
+ },
1518
1544
  resources: [(value) => resolve(value)]
1519
1545
  });
1520
1546
  });
@@ -1555,10 +1581,28 @@ export default {
1555
1581
  const isEditVersion = this.isEdit && this.liveValue?.spec?.kubernetesVersion !== this.value?.spec?.kubernetesVersion;
1556
1582
 
1557
1583
  if (isEditVersion) {
1558
- const shouldContinue = await this.showAddonConfirmation();
1584
+ const hasDiffs = Object.values(this.addonConfigDiffs).some((d) => !isEmpty(d));
1585
+
1586
+ if (hasDiffs) {
1587
+ const addonNamesWithDiffs = [];
1588
+
1589
+ for (const name in this.addonConfigDiffs) {
1590
+ const diff = this.addonConfigDiffs[name];
1591
+
1592
+ if (!isEmpty(diff)) {
1593
+ addonNamesWithDiffs.push(name);
1594
+ }
1595
+ }
1559
1596
 
1560
- if (!shouldContinue) {
1561
- return btnCb('cancelled');
1597
+ const shouldContinue = await this.showAddonConfirmation(
1598
+ addonNamesWithDiffs,
1599
+ this.liveValue.spec.kubernetesVersion,
1600
+ this.value.spec.kubernetesVersion
1601
+ );
1602
+
1603
+ if (!shouldContinue) {
1604
+ return btnCb('cancelled');
1605
+ }
1562
1606
  }
1563
1607
  }
1564
1608
 
@@ -2521,6 +2565,9 @@ export default {
2521
2565
  :addons-rev="addonsRev"
2522
2566
  :user-chart-values-temp="userChartValuesTemp"
2523
2567
  :init-yaml-editor="initYamlEditor"
2568
+ :has-diff="!isEmpty(addonConfigDiffs[v.name])"
2569
+ :previous-kube-version="liveValue?.spec?.kubernetesVersion"
2570
+ :new-kube-version="value.spec.kubernetesVersion"
2524
2571
  @update:value="$emit('input', $event)"
2525
2572
  @update-questions="syncChartValues"
2526
2573
  @update-values="updateValues"