@rancher/shell 3.0.2-rc.5 → 3.0.2

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 (219) hide show
  1. package/assets/images/providers/nutanix.svg +12 -1
  2. package/assets/styles/base/_basic.scss +2 -1
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +2 -0
  5. package/assets/styles/global/_labeled-input.scss +5 -13
  6. package/assets/styles/global/_layout.scss +4 -1
  7. package/assets/styles/global/_select.scss +5 -0
  8. package/assets/styles/themes/_dark.scss +1 -3
  9. package/assets/styles/themes/_light.scss +5 -1
  10. package/assets/translations/en-us.yaml +130 -23
  11. package/assets/translations/zh-hans.yaml +0 -3
  12. package/cloud-credential/azure.vue +1 -1
  13. package/components/ActionMenuShell.vue +105 -0
  14. package/components/AppModal.vue +2 -2
  15. package/components/AsyncButton.vue +2 -0
  16. package/components/ButtonGroup.vue +9 -2
  17. package/components/ClusterBadge.vue +1 -0
  18. package/components/ClusterIconMenu.vue +3 -0
  19. package/components/ClusterProviderIcon.vue +14 -1
  20. package/components/CodeMirror.vue +96 -5
  21. package/components/Collapse.vue +16 -3
  22. package/components/CruResource.vue +9 -0
  23. package/components/CruResourceFooter.vue +1 -1
  24. package/components/ExplorerMembers.vue +2 -1
  25. package/components/FixedBanner.vue +19 -12
  26. package/components/Import.vue +14 -1
  27. package/components/LandingPagePreference.vue +4 -2
  28. package/components/PodSecurityAdmission.vue +8 -6
  29. package/components/PromptChangePassword.vue +1 -0
  30. package/components/PromptRemove.vue +23 -21
  31. package/components/ResourceDetail/Masthead.vue +30 -11
  32. package/components/ResourceDetail/__tests__/Masthead.test.ts +61 -0
  33. package/components/ResourceDetail/index.vue +6 -0
  34. package/components/ResourceTable.vue +6 -1
  35. package/components/ResourceYaml.vue +1 -0
  36. package/components/Setting.vue +115 -0
  37. package/components/SortableTable/THead.vue +2 -0
  38. package/components/SortableTable/index.vue +7 -12
  39. package/components/StatusBadge.vue +71 -0
  40. package/components/Tabbed/index.vue +16 -15
  41. package/components/Wizard.vue +108 -104
  42. package/components/YamlEditor.vue +12 -2
  43. package/components/__tests__/Collapse.test.ts +2 -2
  44. package/components/__tests__/FixedBanner.test.ts +3 -3
  45. package/components/auth/Principal.vue +29 -17
  46. package/components/auth/__tests__/Principal.test.ts +40 -0
  47. package/components/auth/login/ldap.vue +7 -0
  48. package/components/fleet/FleetBundles.vue +1 -1
  49. package/components/fleet/FleetRepos.vue +1 -1
  50. package/components/fleet/FleetResources.vue +0 -2
  51. package/components/fleet/FleetSummary.vue +60 -65
  52. package/components/fleet/ForceDirectedTreeChart/index.vue +5 -1
  53. package/components/fleet/__tests__/FleetSummary.test.ts +49 -9
  54. package/components/form/ArrayList.vue +6 -2
  55. package/components/form/ColorInput.vue +1 -0
  56. package/components/form/KeyValue.vue +11 -12
  57. package/components/form/LabeledSelect.vue +15 -3
  58. package/components/form/Labels.vue +8 -1
  59. package/components/form/Members/MembershipEditor.vue +230 -222
  60. package/components/form/Members/__tests__/MembershipEditor.test.ts +62 -0
  61. package/components/form/Password.vue +3 -0
  62. package/components/form/ProjectMemberEditor.vue +6 -3
  63. package/components/form/ResourceTabs/index.vue +15 -13
  64. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +5 -4
  65. package/components/form/SchedulingCustomization.vue +85 -0
  66. package/components/form/Select.vue +3 -2
  67. package/components/form/SelectOrCreateAuthSecret.vue +2 -1
  68. package/components/form/UnitInput.vue +3 -4
  69. package/components/form/__tests__/ArrayList.test.ts +9 -6
  70. package/components/form/__tests__/LabeledSelect.test.ts +37 -0
  71. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +34 -0
  72. package/components/form/__tests__/UnitInput.test.ts +4 -5
  73. package/components/formatter/LiveDate.vue +3 -1
  74. package/components/formatter/ServiceType.vue +12 -4
  75. package/components/formatter/WorkloadHealthScale.vue +2 -1
  76. package/components/nav/Header.vue +35 -2
  77. package/components/nav/HeaderPageActionMenu.vue +11 -40
  78. package/components/nav/Jump.vue +8 -2
  79. package/components/nav/NamespaceFilter.vue +5 -4
  80. package/components/nav/Pinned.vue +1 -1
  81. package/components/nav/TopLevelMenu.helper.ts +5 -5
  82. package/components/nav/TopLevelMenu.vue +1 -12
  83. package/components/nav/WindowManager/ContainerLogs.vue +96 -58
  84. package/components/nav/WindowManager/ContainerShell.vue +99 -18
  85. package/components/nav/WindowManager/index.vue +74 -6
  86. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  87. package/components/templates/default.vue +2 -47
  88. package/config/features.js +1 -0
  89. package/config/labels-annotations.js +11 -1
  90. package/config/router/navigation-guards/index.js +2 -1
  91. package/config/router/navigation-guards/record-last-route.js +24 -0
  92. package/config/settings.ts +66 -98
  93. package/config/version.js +1 -1
  94. package/core/types-provisioning.ts +7 -0
  95. package/detail/fleet.cattle.io.bundle.vue +7 -0
  96. package/detail/fleet.cattle.io.cluster.vue +0 -3
  97. package/detail/fleet.cattle.io.gitrepo.vue +8 -15
  98. package/detail/provisioning.cattle.io.cluster.vue +8 -2
  99. package/dialog/DeactivateDriverDialog.vue +5 -5
  100. package/dialog/GitRepoForceUpdateDialog.vue +132 -0
  101. package/directives/strip-html-aria-label.js +19 -0
  102. package/edit/__tests__/cis.cattle.io.clusterscan.test.ts +87 -0
  103. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +217 -37
  104. package/edit/auth/__tests__/oidc.test.ts +60 -12
  105. package/edit/auth/ldap/__tests__/config.test.ts +40 -0
  106. package/edit/auth/ldap/config.vue +67 -89
  107. package/edit/auth/oidc.vue +16 -2
  108. package/edit/catalog.cattle.io.clusterrepo.vue +12 -8
  109. package/edit/cis.cattle.io.clusterscan.vue +13 -1
  110. package/edit/fleet.cattle.io.gitrepo.vue +198 -72
  111. package/edit/logging-flow/Match.vue +0 -21
  112. package/edit/management.cattle.io.project.vue +1 -1
  113. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +10 -3
  114. package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +5 -1
  115. package/edit/monitoring.coreos.com.prometheusrule/index.vue +5 -2
  116. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +8 -1
  117. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +2 -0
  118. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +0 -2
  119. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +55 -15
  120. package/edit/provisioning.cattle.io.cluster/index.vue +28 -30
  121. package/edit/provisioning.cattle.io.cluster/rke2.vue +64 -13
  122. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +37 -2
  123. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -2
  124. package/edit/resources.cattle.io.backup.vue +150 -15
  125. package/edit/secret/__tests__/ssh.test.ts +79 -0
  126. package/edit/secret/ssh.vue +7 -1
  127. package/edit/service.vue +0 -3
  128. package/edit/workload/Job.vue +8 -8
  129. package/edit/workload/__tests__/Job.test.ts +0 -1
  130. package/edit/workload/index.vue +3 -1
  131. package/initialize/install-directives.js +2 -0
  132. package/initialize/install-plugins.js +6 -1
  133. package/list/catalog.cattle.io.app.vue +21 -4
  134. package/list/fleet.cattle.io.bundle.vue +1 -1
  135. package/list/management.cattle.io.setting.vue +34 -132
  136. package/list/provisioning.cattle.io.cluster.vue +11 -3
  137. package/machine-config/vmwarevsphere.vue +15 -8
  138. package/mixins/__tests__/auth-config.test.ts +74 -0
  139. package/mixins/__tests__/chart.test.ts +5 -4
  140. package/mixins/__tests__/create-edit-view.test.ts +38 -0
  141. package/mixins/auth-config.js +8 -0
  142. package/mixins/chart.js +2 -2
  143. package/mixins/create-edit-view/impl.js +4 -1
  144. package/mixins/vue-select-overrides.js +10 -0
  145. package/models/__tests__/catalog.cattle.io.app.test.ts +148 -0
  146. package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +157 -0
  147. package/models/__tests__/secret.test.ts +56 -13
  148. package/models/catalog.cattle.io.app.js +112 -37
  149. package/models/cluster.js +11 -0
  150. package/models/fleet.cattle.io.bundle.js +40 -2
  151. package/models/fleet.cattle.io.gitrepo.js +169 -109
  152. package/models/management.cattle.io.fleetworkspace.js +4 -0
  153. package/models/management.cattle.io.kontainerdriver.js +7 -0
  154. package/models/nodedriver.js +4 -1
  155. package/models/provisioning.cattle.io.cluster.js +24 -0
  156. package/models/secret.js +1 -1
  157. package/package.json +5 -5
  158. package/pages/auth/login.vue +5 -11
  159. package/pages/auth/verify.vue +11 -1
  160. package/pages/c/_cluster/apps/charts/index.vue +6 -4
  161. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  162. package/pages/c/_cluster/explorer/ConfigBadge.vue +3 -5
  163. package/pages/c/_cluster/explorer/EventsTable.vue +3 -2
  164. package/pages/c/_cluster/explorer/__tests__/index.test.ts +9 -9
  165. package/pages/c/_cluster/explorer/index.vue +33 -35
  166. package/pages/c/_cluster/explorer/tools/index.vue +3 -3
  167. package/pages/c/_cluster/fleet/index.vue +0 -5
  168. package/pages/c/_cluster/legacy/project/index.vue +1 -1
  169. package/pages/c/_cluster/settings/performance.vue +52 -53
  170. package/pages/c/_cluster/uiplugins/index.vue +19 -22
  171. package/pages/home.vue +17 -12
  172. package/pages/prefs.vue +5 -1
  173. package/plugins/shortkey.js +10 -1
  174. package/plugins/steve/steve-pagination-utils.ts +58 -8
  175. package/promptRemove/management.cattle.io.fleetworkspace.vue +98 -0
  176. package/promptRemove/management.cattle.io.globalrole.vue +1 -1
  177. package/promptRemove/management.cattle.io.project.vue +2 -8
  178. package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
  179. package/promptRemove/mixin/roleDeletionCheck.js +1 -7
  180. package/promptRemove/pod.vue +7 -28
  181. package/rancher-components/Card/Card.vue +9 -1
  182. package/rancher-components/Form/Checkbox/Checkbox.vue +42 -6
  183. package/rancher-components/Form/LabeledInput/LabeledInput.vue +30 -3
  184. package/rancher-components/Form/Radio/RadioButton.vue +18 -3
  185. package/rancher-components/Form/Radio/RadioGroup.vue +39 -5
  186. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +13 -1
  187. package/rancher-components/RcButton/RcButton.test.ts +97 -0
  188. package/rancher-components/RcButton/RcButton.vue +14 -9
  189. package/rancher-components/RcDropdown/RcDropdown.vue +3 -1
  190. package/rancher-components/RcDropdown/RcDropdownItem.vue +8 -2
  191. package/rancher-components/RcDropdown/RcDropdownMenu.vue +66 -0
  192. package/rancher-components/RcDropdown/index.ts +1 -0
  193. package/rancher-components/RcDropdown/types.ts +27 -0
  194. package/rancher-components/RcDropdown/useDropdownContext.ts +5 -2
  195. package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
  196. package/scripts/typegen.sh +1 -0
  197. package/store/__tests__/auth.test.ts +120 -0
  198. package/store/action-menu.js +13 -3
  199. package/store/auth.js +14 -9
  200. package/store/aws.js +9 -2
  201. package/store/catalog.js +14 -7
  202. package/store/features.js +1 -0
  203. package/store/prefs.js +9 -28
  204. package/store/type-map.utils.ts +4 -0
  205. package/types/resources/settings.d.ts +27 -20
  206. package/types/shell/index.d.ts +18 -12
  207. package/utils/__tests__/array.test.ts +13 -1
  208. package/utils/__tests__/string.test.ts +80 -1
  209. package/utils/array.ts +13 -0
  210. package/utils/auth.js +4 -0
  211. package/utils/banners.js +0 -45
  212. package/utils/cluster.js +1 -1
  213. package/{edit/monitoring.coreos.com.prometheusrule → utils}/duration.js +5 -3
  214. package/utils/object.js +0 -3
  215. package/utils/pagination-utils.ts +15 -2
  216. package/utils/string.js +31 -7
  217. package/utils/validators/formRules/__tests__/index.test.ts +27 -0
  218. package/utils/validators/formRules/index.ts +16 -0
  219. package/edit/provisioning.cattle.io.cluster/import.vue +0 -198
@@ -11,7 +11,7 @@ import NameNsDescription from '@shell/components/form/NameNsDescription';
11
11
  import Loading from '@shell/components/Loading';
12
12
  import S3 from '@shell/chart/rancher-backup/S3';
13
13
  import { mapGetters } from 'vuex';
14
- import { SECRET, BACKUP_RESTORE, CATALOG } from '@shell/config/types';
14
+ import { SECRET, BACKUP_RESTORE, CATALOG, COUNT } from '@shell/config/types';
15
15
  import { allHash } from '@shell/utils/promise';
16
16
  import { NAMESPACE, _VIEW, _CREATE } from '@shell/config/query-params';
17
17
  import { sortBy } from '@shell/utils/sort';
@@ -20,6 +20,10 @@ import { formatEncryptionSecretNames } from '@shell/utils/formatter';
20
20
  import { FilterArgs, PaginationParamFilter } from '@shell/types/store/pagination.types';
21
21
  import { SECRET_TYPES } from '@shell/config/secret';
22
22
 
23
+ const DEFAULT_RANCHER_BACKUP_RESOURCE_SET_ID = 'rancher-resource-set-basic';
24
+ const FULL_RANCHER_BACKUP_RESOURCE_SET_ID = 'rancher-resource-set-full';
25
+ const CUSTOM_RESOURCE_SET_ID = 'custom';
26
+
23
27
  export default {
24
28
 
25
29
  components: {
@@ -50,18 +54,38 @@ export default {
50
54
 
51
55
  async fetch() {
52
56
  const hash = await allHash({
53
- catalog: this.$store.dispatch('catalog/load'),
54
- resourceSet: this.$store.dispatch('cluster/find', { type: BACKUP_RESTORE.RESOURCE_SET, id: this.value?.spec?.resourceSetName || 'rancher-resource-set' }),
55
- apps: this.$store.dispatch('cluster/findAll', { type: CATALOG.APP })
57
+ catalog: this.$store.dispatch('catalog/load'),
58
+ allResourceSets: this.$store.dispatch('cluster/findAll', { type: BACKUP_RESTORE.RESOURCE_SET }),
59
+ apps: this.$store.dispatch('cluster/findAll', { type: CATALOG.APP })
56
60
  });
57
61
 
58
62
  this.apps = hash.apps;
59
- this.resourceSet = hash.resourceSet;
63
+ this.allResourceSets = hash.allResourceSets;
60
64
 
61
65
  const BRORelease = this.apps.filter((release) => get(release, 'spec.name') === 'rancher-backup')[0];
62
66
 
63
67
  this.chartNamespace = BRORelease?.spec.namespace || '';
64
68
 
69
+ if (!this.value.spec.resourceSetName) {
70
+ this.value.spec.resourceSetName = this.defaultExistingResourceSetOptionIds[0] || this.allResourceSets[0].id;
71
+ }
72
+
73
+ const computeResourceSetSelection = () => {
74
+ if (!this.value?.spec?.resourceSetName) {
75
+ const defaults = this.defaultExistingResourceSetOptionIds;
76
+
77
+ if (defaults.length > 0) {
78
+ return defaults[0];
79
+ }
80
+
81
+ return this.allResourceSets[0].id;
82
+ }
83
+
84
+ return this.defaultResourceSetOptionIds.includes(this.value?.spec?.resourceSetName) ? this.value?.spec?.resourceSetName : CUSTOM_RESOURCE_SET_ID;
85
+ };
86
+
87
+ this.resourceSetSelection = computeResourceSetSelection();
88
+
65
89
  if (this.$store.getters[`cluster/paginationEnabled`](SECRET)) {
66
90
  const findPageArgs = { // Of type ActionFindPageArgs
67
91
  namespaced: this.chartNamespace,
@@ -105,17 +129,25 @@ export default {
105
129
  s3 = this.value.spec.storageLocation.s3;
106
130
  }
107
131
 
132
+ const counts = this.$store.getters[`cluster/all`](COUNT);
133
+ const defaultResourceSetOptionIds = [DEFAULT_RANCHER_BACKUP_RESOURCE_SET_ID, FULL_RANCHER_BACKUP_RESOURCE_SET_ID];
134
+
108
135
  return {
109
- secrets: [],
110
- resourceSet: null,
136
+ secrets: [],
137
+ resourceSetCounts: counts?.[0]?.counts?.[BACKUP_RESTORE.RESOURCE_SET]?.summary?.count,
138
+ defaultResourceSetOptionIds,
139
+ allResourceSets: [],
140
+ resourceSetSelection: null,
111
141
  s3,
112
142
  storageSource,
113
143
  useEncryption,
114
- apps: [],
144
+ apps: [],
115
145
  setSchedule,
116
- name: this.value?.metadata?.name,
117
- fvFormRuleSets: [{
118
- path: 'metadata.name', rules: ['dnsLabel', 'noUpperCase'], translationKey: 'nameNsDescription.name.label'
146
+ name: this.value?.metadata?.name,
147
+ fvFormRuleSets: [{
148
+ path: 'metadata.name',
149
+ rules: ['dnsLabel', 'noUpperCase'],
150
+ translationKey: 'nameNsDescription.name.label'
119
151
  }],
120
152
  chartNamespace: null,
121
153
  };
@@ -144,6 +176,48 @@ export default {
144
176
  return { options, labels };
145
177
  },
146
178
 
179
+ defaultExistingResourceSetOptionIds() {
180
+ return this.defaultResourceSetOptionIds.filter((id) => {
181
+ return this.allResourceSetIds.includes(id);
182
+ });
183
+ },
184
+
185
+ resourceSetOptions() {
186
+ const optionIds = [...this.defaultExistingResourceSetOptionIds];
187
+ const addCustom = !optionIds.includes(this.value.spec?.resourceSetName) || this.allResourceSetIds.length > optionIds.length;
188
+
189
+ if (addCustom) {
190
+ optionIds.push(CUSTOM_RESOURCE_SET_ID);
191
+ }
192
+
193
+ return optionIds.map((id) => {
194
+ return {
195
+ label: this.t(`backupRestoreOperator.backup.resourceSetOptions.${ id }`),
196
+ value: id
197
+ };
198
+ });
199
+ },
200
+
201
+ allResourceSetIds() {
202
+ return this.allResourceSets.map((rs) => rs.id);
203
+ },
204
+
205
+ customResourceSetOptions() {
206
+ return this.allResourceSetIds.filter((id) => !this.defaultResourceSetOptionIds.includes(id));
207
+ },
208
+
209
+ showCustomResourceSetOptions() {
210
+ return this.resourceSetSelection === CUSTOM_RESOURCE_SET_ID;
211
+ },
212
+
213
+ showEncryptionWarningBanner() {
214
+ return this.resourceSetSelection === 'rancher-resource-set-full';
215
+ },
216
+
217
+ showMissingResourceSetWarningBanner() {
218
+ return !this.allResourceSetIds.includes(this.value.spec.resourceSetName);
219
+ },
220
+
147
221
  namespaces() {
148
222
  const choices = this.$store.getters['cluster/all'](NAMESPACE);
149
223
  const out = sortBy(choices.map((obj) => {
@@ -172,9 +246,16 @@ export default {
172
246
  }
173
247
  },
174
248
 
175
- resourceSet(neu) {
176
- if (neu?.metadata?.name) {
177
- this.value.spec['resourceSetName'] = neu?.metadata?.name;
249
+ resourceSetSelection(neu, old) {
250
+ // We don't want to handle this when this gets triggered in fetch
251
+ if (!old) {
252
+ return;
253
+ }
254
+
255
+ if (neu === CUSTOM_RESOURCE_SET_ID) {
256
+ this.value.spec.resourceSetName = this.customResourceSetOptions[0];
257
+ } else {
258
+ this.value.spec.resourceSetName = neu;
178
259
  }
179
260
  },
180
261
 
@@ -212,7 +293,7 @@ export default {
212
293
  :rules="{name: fvGetAndReportPathRules('metadata.name')}"
213
294
  @change="name=value.metadata.name"
214
295
  />
215
- <template v-if="!!resourceSet">
296
+ <template v-if="resourceSetCounts > 0">
216
297
  <div class="bordered-section">
217
298
  <RadioGroup
218
299
  v-model:value="setSchedule"
@@ -245,6 +326,60 @@ export default {
245
326
  </div>
246
327
  </div>
247
328
  </div>
329
+ <div class="bordered-section">
330
+ <div class="row mb-10">
331
+ <div class="col span-12">
332
+ <h3>{{ t('backupRestoreOperator.backup.label') }}</h3>
333
+ <div>{{ t('backupRestoreOperator.backup.description') }}</div>
334
+ </div>
335
+ </div>
336
+ <div class="row">
337
+ <div class="col span-12">
338
+ <RadioGroup
339
+ v-model:value="resourceSetSelection"
340
+ name="resourceSet"
341
+ :options="resourceSetOptions"
342
+ :mode="mode"
343
+ />
344
+ </div>
345
+ </div>
346
+ <div
347
+ v-if="showCustomResourceSetOptions"
348
+ class="row mt-10"
349
+ >
350
+ <div class="col span-6">
351
+ <LabeledSelect
352
+ v-model:value="value.spec.resourceSetName"
353
+ :mode="mode"
354
+ :options="customResourceSetOptions"
355
+ :label="t('backupRestoreOperator.backup.resourceSetOptions.customResourceSetLabel')"
356
+ />
357
+ </div>
358
+ </div>
359
+ <div
360
+ v-if="showEncryptionWarningBanner"
361
+ class="row mt-10"
362
+ >
363
+ <div class="col span-12">
364
+ <Banner
365
+ color="warning"
366
+ role="alert"
367
+ >
368
+ <span v-clean-html="t('backupRestoreOperator.backup.enableEncryptionWarning')" />
369
+ </Banner>
370
+ </div>
371
+ </div>
372
+ <div
373
+ v-if="showMissingResourceSetWarningBanner"
374
+ class="row mt-10"
375
+ >
376
+ <div class="col span-12">
377
+ <Banner color="warning">
378
+ <span v-clean-html="t('backupRestoreOperator.backup.missingResourceSetWarning', {resourceSet: value.spec.resourceSetName})" />
379
+ </Banner>
380
+ </div>
381
+ </div>
382
+ </div>
248
383
 
249
384
  <div class="bordered-section">
250
385
  <div class="row">
@@ -0,0 +1,79 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { _VIEW, _EDIT, _CREATE } from '@shell/config/query-params';
3
+ import Ssh from '@shell/edit/secret/ssh.vue';
4
+
5
+ const mockedStore = () => {
6
+ return { getters: { 'i18n/t': jest.fn() } };
7
+ };
8
+
9
+ const mockedRoute = { query: {} };
10
+
11
+ const requiredSetup = () => {
12
+ return {
13
+ global: {
14
+ mocks: {
15
+ $store: mockedStore(),
16
+ $route: mockedRoute,
17
+ $fetchState: {},
18
+ }
19
+ }
20
+ };
21
+ };
22
+
23
+ const decodedData = {
24
+ known_hosts: 'S05PV05fSE9TVFM=',
25
+ 'ssh-privatekey': 'dGVzdDE=',
26
+ 'ssh-publickey': 'dGVzdDE='
27
+ };
28
+
29
+ describe.each([
30
+ _CREATE,
31
+ _EDIT,
32
+ _VIEW
33
+ ])('component: Ssh.vue', (mode) => {
34
+ it(`mode: ${ mode }, should show input fields`, () => {
35
+ const wrapper = mount(Ssh, {
36
+ ...requiredSetup(),
37
+ props: {
38
+ value: {
39
+ name: 'foo',
40
+ decodedData,
41
+ supportsSshKnownHosts: true
42
+ },
43
+ mode,
44
+ },
45
+ });
46
+
47
+ const publicKey = wrapper.find('[data-testid="ssh-public-key"]').element as HTMLInputElement;
48
+ const privateKey = wrapper.find('[data-testid="ssh-private-key"]').element as HTMLInputElement;
49
+ const knownHosts = wrapper.find('[data-testid="ssh-known-hosts"]').element as HTMLInputElement;
50
+
51
+ expect(publicKey.value).toBe('dGVzdDE=');
52
+ expect(privateKey.value).toBe('dGVzdDE=');
53
+ expect(knownHosts.value).toBe('S05PV05fSE9TVFM=');
54
+ });
55
+
56
+ it.each([
57
+ ['show', true],
58
+ ['hide', false],
59
+ ])(`mode: ${ mode }, should %p known_hosts`, (
60
+ _,
61
+ supportsSshKnownHosts,
62
+ ) => {
63
+ const wrapper = mount(Ssh, {
64
+ ...requiredSetup(),
65
+ props: {
66
+ value: {
67
+ name: 'foo',
68
+ decodedData,
69
+ supportsSshKnownHosts
70
+ },
71
+ mode: _EDIT,
72
+ },
73
+ });
74
+
75
+ const knownHosts = wrapper.find('[data-testid="ssh-known-hosts"]');
76
+
77
+ expect(knownHosts.exists()).toBe(supportsSshKnownHosts);
78
+ });
79
+ });
@@ -44,7 +44,10 @@ export default {
44
44
  update() {
45
45
  this.value.setData('ssh-publickey', this.username);
46
46
  this.value.setData('ssh-privatekey', this.password);
47
- this.value.setData('known_hosts', this.knownHosts);
47
+
48
+ if (this.showKnownHosts) {
49
+ this.value.setData('known_hosts', this.knownHosts);
50
+ }
48
51
  }
49
52
  }
50
53
  };
@@ -57,6 +60,7 @@ export default {
57
60
  <LabeledInput
58
61
  v-model:value="username"
59
62
  type="multiline"
63
+ data-testid="ssh-public-key"
60
64
  :label="t('secret.ssh.public')"
61
65
  :mode="mode"
62
66
  required
@@ -72,6 +76,7 @@ export default {
72
76
  <LabeledInput
73
77
  v-model:value="password"
74
78
  type="multiline"
79
+ data-testid="ssh-private-key"
75
80
  :label="t('secret.ssh.private')"
76
81
  :mode="mode"
77
82
  required
@@ -90,6 +95,7 @@ export default {
90
95
  v-if="showKnownHosts"
91
96
  v-model:value="knownHosts"
92
97
  type="multiline"
98
+ data-testid="ssh-known-hosts"
93
99
  :label="t('secret.ssh.knownHosts')"
94
100
  :mode="mode"
95
101
  :placeholder="t('secret.ssh.knownHostsPlaceholder')"
package/edit/service.vue CHANGED
@@ -521,9 +521,6 @@ export default {
521
521
  "
522
522
  :label="t('servicesPage.affinity.timeout.label')"
523
523
  :placeholder="t('servicesPage.affinity.timeout.placeholder')"
524
- @input="
525
- (e) => value.spec.sessionAffinityConfig.clientIP.timeoutSeconds = e
526
- "
527
524
  />
528
525
  </div>
529
526
  </div>
@@ -161,7 +161,7 @@ export default {
161
161
  :suffix="t('suffix.times', {count: completions})"
162
162
  label-key="workload.job.completions.label"
163
163
  tooltip-key="workload.job.completions.tip"
164
- @input="update"
164
+ @update:value="update"
165
165
  />
166
166
  </div>
167
167
  <div
@@ -174,7 +174,7 @@ export default {
174
174
  :suffix="t('suffix.times', {count: parallelism})"
175
175
  label-key="workload.job.parallelism.label"
176
176
  tooltip-key="workload.job.parallelism.tip"
177
- @input="update"
177
+ @update:value="update"
178
178
  />
179
179
  </div>
180
180
  </div>
@@ -189,7 +189,7 @@ export default {
189
189
  :suffix="t('suffix.times', {count: backoffLimit})"
190
190
  label-key="workload.job.backoffLimit.label"
191
191
  tooltip-key="workload.job.backoffLimit.tip"
192
- @input="update"
192
+ @update:value="update"
193
193
  />
194
194
  </div>
195
195
  <div
@@ -202,7 +202,7 @@ export default {
202
202
  :suffix="t('suffix.seconds', {count: activeDeadlineSeconds})"
203
203
  label-key="workload.job.activeDeadlineSeconds.label"
204
204
  tooltip-key="workload.job.activeDeadlineSeconds.tip"
205
- @input="update"
205
+ @update:value="update"
206
206
  />
207
207
  </div>
208
208
  </div>
@@ -245,7 +245,7 @@ export default {
245
245
  :suffix="t('suffix.seconds', {count: startingDeadlineSeconds})"
246
246
  label-key="workload.job.startingDeadlineSeconds.label"
247
247
  tooltip-key="workload.job.startingDeadlineSeconds.tip"
248
- @input="update"
248
+ @update:value="update"
249
249
  />
250
250
  </div>
251
251
  <div
@@ -254,10 +254,10 @@ export default {
254
254
  >
255
255
  <UnitInput
256
256
  v-model:value="terminationGracePeriodSeconds"
257
- :suffix="terminationGracePeriodSeconds == 1 ? 'Second' : 'Seconds'"
257
+ :suffix="t('suffix.seconds', { count: terminationGracePeriodSeconds })"
258
258
  :label="t('workload.upgrading.activeDeadlineSeconds.label')"
259
259
  :mode="mode"
260
- @input="update"
260
+ @update:value="update"
261
261
  >
262
262
  <template #label>
263
263
  <label
@@ -316,7 +316,7 @@ export default {
316
316
  >
317
317
  <UnitInput
318
318
  v-model:value="terminationGracePeriodSeconds"
319
- :suffix="terminationGracePeriodSeconds == 1 ? 'Second' : 'Seconds'"
319
+ :suffix="t('suffix.seconds', { count: terminationGracePeriodSeconds })"
320
320
  :label="t('workload.upgrading.activeDeadlineSeconds.label')"
321
321
  :mode="mode"
322
322
  >
@@ -64,7 +64,6 @@ describe('component: Job', () => {
64
64
  const newValue = 123;
65
65
 
66
66
  input.setValue(newValue);
67
- input.trigger('blur');
68
67
 
69
68
  expect(wrapper.emitted('update:value')).toHaveLength(1);
70
69
  });
@@ -262,8 +262,10 @@ export default {
262
262
  <h3>
263
263
  {{ t('workload.container.ports.expose') }}
264
264
  <i
265
- v-clean-tooltip="t('workload.container.ports.toolTip')"
265
+ v-clean-tooltip="{content: t('workload.container.ports.toolTip'), triggers: ['hover', 'touch', 'focus'] }"
266
+ v-stripped-aria-label="t('workload.container.ports.toolTip')"
266
267
  class="icon icon-info"
268
+ tabindex="0"
267
269
  />
268
270
  </h3>
269
271
  <p class="padded">
@@ -10,6 +10,7 @@ import cleanTooltipDirective from '@shell/directives/clean-tooltip';
10
10
  import positiveIntNumberDirective from '@shell/directives/positive-int-number.js';
11
11
  import trimWhitespaceDirective from '@shell/directives/trim-whitespace';
12
12
  import intNumberDirective from '@shell/directives/int-number';
13
+ import htmlStrippedAriaLabelDirective from '@shell/directives/strip-html-aria-label';
13
14
 
14
15
  /**
15
16
  * Prevent extensions from overriding existing directives
@@ -47,6 +48,7 @@ function addDirectives(vueApp) {
47
48
  vueApp.directive('focus', focusDirective);
48
49
  vueApp.directive('intNumber', intNumberDirective);
49
50
  vueApp.directive('positiveIntNumber', positiveIntNumberDirective);
51
+ vueApp.directive('stripped-aria-label', htmlStrippedAriaLabelDirective);
50
52
  }
51
53
 
52
54
  /**
@@ -35,7 +35,12 @@ export async function installPlugins(vueApp) {
35
35
  vueApp.use(PortalVue);
36
36
  vueApp.use(Vue3Resize);
37
37
  vueApp.use(FloatingVue, floatingVueOptions);
38
- vueApp.use(ShortKey, { prevent: ['input', 'textarea', 'select'] });
38
+ vueApp.use(
39
+ ShortKey,
40
+ {
41
+ prevent: ['input', 'textarea', 'select'],
42
+ preventContainer: ['#modal-container-element']
43
+ });
39
44
  vueApp.use(InstallCodeMirror);
40
45
  vueApp.component('v-select', vSelect);
41
46
  }
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import PaginatedResourceTable from '@shell/components/PaginatedResourceTable';
3
+ import { APP_UPGRADE_STATUS } from '@shell/store/catalog';
3
4
 
4
5
  export default {
5
6
  name: 'ListApps',
@@ -21,6 +22,10 @@ export default {
21
22
  }
22
23
  },
23
24
 
25
+ data() {
26
+ return { APP_UPGRADE_STATUS };
27
+ },
28
+
24
29
  async fetch() {
25
30
  await this.$store.dispatch('catalog/load');
26
31
  },
@@ -36,18 +41,30 @@ export default {
36
41
  >
37
42
  <template #cell:upgrade="{row}">
38
43
  <span
39
- v-if="row.upgradeAvailable"
44
+ v-if="row.upgradeAvailable === APP_UPGRADE_STATUS.SINGLE_UPGRADE"
40
45
  class="badge-state bg-warning hand"
41
- @click="row.goToUpgrade(row.upgradeAvailable)"
46
+ @click="row.goToUpgrade(row.upgradeAvailableVersion)"
42
47
  >
43
- {{ row.upgradeAvailable }}
48
+ {{ row.upgradeAvailableVersion }}
44
49
  <i class="icon icon-upload" />
45
50
  </span>
46
51
  <span
47
- v-else-if="row.upgradeAvailable === false"
52
+ v-else-if="row.upgradeAvailable === APP_UPGRADE_STATUS.NOT_APPLICABLE"
48
53
  v-t="'catalog.app.managed'"
49
54
  class="text-muted"
50
55
  />
56
+ <span
57
+ v-else-if="row.upgradeAvailable === APP_UPGRADE_STATUS.NO_UPGRADE"
58
+ class="text-muted"
59
+ />
60
+ <span
61
+ v-else-if="row.upgradeAvailable === APP_UPGRADE_STATUS.MULTIPLE_UPGRADES"
62
+ >
63
+ <i
64
+ v-clean-tooltip="t('catalog.app.upgrade.uncertainUpgradeWarningTooltip')"
65
+ class="icon icon-info"
66
+ />
67
+ </span>
51
68
  </template>
52
69
  </PaginatedResourceTable>
53
70
  </template>
@@ -118,7 +118,7 @@ export default {
118
118
  v-if="row.status && row.status.summary && (row.status.summary.desiredReady !== row.status.summary.ready)"
119
119
  class="text-warning"
120
120
  >
121
- {{ row.status.summary.ready }}/{{ row.status.summary.desiredReady }}</span>
121
+ {{ row.status.summary.ready || 0 }}/{{ row.status.summary.desiredReady }}</span>
122
122
  <span v-else-if="row.status && row.status.summary">{{ row.status.summary.desiredReady }}</span>
123
123
  <span v-else>-</span>
124
124
  </template>