@rancher/shell 3.0.5-rc.8 → 3.0.5-rc.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 (171) hide show
  1. package/assets/styles/base/_color.scss +4 -1
  2. package/assets/styles/global/_tooltip.scss +7 -4
  3. package/assets/styles/themes/_dark.scss +11 -0
  4. package/assets/styles/themes/_light.scss +13 -1
  5. package/assets/styles/themes/_modern.scss +22 -0
  6. package/assets/translations/en-us.yaml +136 -14
  7. package/assets/translations/zh-hans.yaml +0 -1
  8. package/chart/monitoring/grafana/index.vue +8 -2
  9. package/components/ActionMenuShell.vue +3 -1
  10. package/components/Cron/CronExpressionEditor.vue +299 -0
  11. package/components/Cron/CronExpressionEditorModal.vue +247 -0
  12. package/components/Cron/CronTooltip.vue +87 -0
  13. package/components/Cron/types.ts +13 -0
  14. package/components/ForceDirectedTreeChart/composable.ts +11 -0
  15. package/components/PromptModal.vue +1 -1
  16. package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +1 -0
  17. package/components/Resource/Detail/CopyToClipboard.vue +78 -0
  18. package/components/Resource/Detail/FetchLoader/__tests__/composables.test.ts +69 -0
  19. package/components/Resource/Detail/FetchLoader/composables.ts +27 -0
  20. package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +1 -1
  21. package/components/Resource/Detail/Metadata/Annotations/index.vue +1 -1
  22. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +13 -61
  23. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +33 -6
  24. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +24 -38
  25. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +25 -5
  26. package/components/Resource/Detail/Metadata/KeyValue.vue +12 -23
  27. package/components/Resource/Detail/Metadata/KeyValueRow.vue +144 -0
  28. package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +1 -0
  29. package/components/Resource/Detail/Metadata/Labels/index.vue +1 -0
  30. package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +30 -32
  31. package/components/Resource/Detail/Metadata/__tests__/KeyValueRow.test.ts +108 -0
  32. package/components/Resource/Detail/Metadata/__tests__/composables.test.ts +0 -3
  33. package/components/Resource/Detail/Metadata/__tests__/index.test.ts +12 -5
  34. package/components/Resource/Detail/Metadata/composables.ts +1 -4
  35. package/components/Resource/Detail/Metadata/index.vue +1 -0
  36. package/components/Resource/Detail/Preview/Content.vue +63 -0
  37. package/components/Resource/Detail/Preview/Preview.vue +128 -0
  38. package/components/Resource/Detail/Preview/__tests__/Content.spec.ts +71 -0
  39. package/components/Resource/Detail/Preview/__tests__/Preview.spec.ts +121 -0
  40. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +141 -0
  41. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +136 -0
  42. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +245 -0
  43. package/components/Resource/Detail/ResourcePopover/index.vue +226 -0
  44. package/components/Resource/Detail/SpacedRow.vue +1 -0
  45. package/components/Resource/Detail/TitleBar/__tests__/composables.test.ts +0 -5
  46. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +1 -1
  47. package/components/Resource/Detail/TitleBar/composables.ts +1 -3
  48. package/components/Resource/Detail/TitleBar/index.vue +2 -29
  49. package/components/Resource/Detail/ViewOptions/composable.ts +9 -0
  50. package/components/Resource/Detail/ViewOptions/index.vue +41 -0
  51. package/components/Resource/Detail/__tests__/CopyToClipboard.spec.ts +82 -0
  52. package/components/ResourceDetail/Masthead/legacy.vue +0 -19
  53. package/components/ResourceDetail/index.vue +1 -26
  54. package/components/ResourceTable.vue +24 -0
  55. package/components/SortableTable/index.vue +7 -1
  56. package/components/SortableTable/paging.js +3 -0
  57. package/components/Tabbed/Tab.vue +43 -1
  58. package/components/Tabbed/index.vue +3 -1
  59. package/components/__tests__/Cron/CronExpressionEditor.test.ts +151 -0
  60. package/components/__tests__/Cron/CronExpressionEditorModal.test.ts +81 -0
  61. package/components/auth/login/saml.vue +86 -0
  62. package/components/form/LabeledSelect.vue +8 -8
  63. package/components/form/ResourceTabs/composable.ts +54 -0
  64. package/components/form/ResourceTabs/index.vue +10 -7
  65. package/components/form/Select.vue +13 -10
  66. package/components/form/__tests__/LabeledSelect.test.ts +133 -0
  67. package/components/form/__tests__/Select.test.ts +134 -0
  68. package/composables/useExtensionManager.ts +17 -0
  69. package/config/home-links.js +12 -0
  70. package/config/labels-annotations.js +0 -1
  71. package/config/page-actions.js +0 -1
  72. package/config/product/explorer.js +3 -1
  73. package/config/product/fleet.js +2 -7
  74. package/config/product/manager.js +0 -5
  75. package/config/query-params.js +1 -0
  76. package/config/router/navigation-guards/clusters.js +2 -1
  77. package/config/router/navigation-guards/products.js +1 -1
  78. package/core/extension-manager-impl.js +518 -0
  79. package/core/plugins.js +35 -468
  80. package/core/types.ts +8 -2
  81. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +1 -0
  82. package/detail/catalog.cattle.io.app.vue +7 -4
  83. package/detail/fleet.cattle.io.bundle.vue +1 -5
  84. package/detail/fleet.cattle.io.cluster.vue +3 -2
  85. package/detail/fleet.cattle.io.gitrepo.vue +76 -49
  86. package/detail/fleet.cattle.io.helmop.vue +78 -49
  87. package/dialog/AddonConfigConfirmationDialog.vue +1 -1
  88. package/dialog/GenericPrompt.vue +1 -1
  89. package/dialog/ImportDialog.vue +9 -2
  90. package/dialog/InstallExtensionDialog.vue +18 -10
  91. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -1
  92. package/edit/__tests__/resources.cattle.io.restore.test.ts +106 -0
  93. package/edit/cloudcredential.vue +31 -17
  94. package/edit/constraints.gatekeeper.sh.constraint/index.vue +10 -2
  95. package/edit/fleet.cattle.io.cluster.vue +19 -0
  96. package/edit/fleet.cattle.io.gitrepo.vue +23 -16
  97. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +12 -11
  98. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +11 -1
  99. package/edit/provisioning.cattle.io.cluster/index.vue +14 -19
  100. package/edit/provisioning.cattle.io.cluster/rke2.vue +11 -3
  101. package/edit/resources.cattle.io.restore.vue +5 -8
  102. package/list/__tests__/workload.test.ts +1 -0
  103. package/list/workload.vue +8 -1
  104. package/machine-config/components/GCEImage.vue +6 -5
  105. package/machine-config/google.vue +11 -6
  106. package/mixins/__tests__/chart.test.ts +139 -1
  107. package/mixins/chart.js +58 -18
  108. package/models/__tests__/namespace.test.ts +69 -0
  109. package/models/apps.statefulset.js +8 -10
  110. package/models/chart.js +5 -1
  111. package/models/fleet-application.js +16 -46
  112. package/models/fleet.cattle.io.bundle.js +1 -38
  113. package/models/fleet.cattle.io.gitrepo.js +4 -0
  114. package/models/fleet.cattle.io.helmop.js +4 -0
  115. package/models/management.cattle.io.project.js +12 -0
  116. package/models/namespace.js +30 -0
  117. package/models/workload.js +3 -0
  118. package/package.json +10 -10
  119. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +26 -11
  120. package/pages/c/_cluster/apps/charts/chart.vue +29 -20
  121. package/pages/c/_cluster/apps/charts/index.vue +1 -0
  122. package/pages/c/_cluster/apps/charts/install.vue +6 -5
  123. package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +102 -12
  124. package/pages/c/_cluster/explorer/tools/index.vue +145 -254
  125. package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -1
  126. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +12 -2
  127. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -1
  128. package/pages/c/_cluster/uiplugins/__tests__/index.spec.ts +318 -0
  129. package/pages/c/_cluster/uiplugins/index.vue +221 -363
  130. package/pages/home.vue +1 -9
  131. package/plugins/dashboard-store/resource-class.js +49 -0
  132. package/public/index.html +2 -1
  133. package/rancher-components/Card/Card.vue +1 -1
  134. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  135. package/rancher-components/Form/Radio/RadioButton.vue +1 -1
  136. package/rancher-components/Form/Radio/RadioGroup.vue +1 -1
  137. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +1 -11
  138. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.test.ts +53 -0
  139. package/rancher-components/Pill/RcCounterBadge/RcCounterBadge.vue +65 -0
  140. package/rancher-components/Pill/RcCounterBadge/index.ts +1 -0
  141. package/rancher-components/Pill/RcCounterBadge/types.ts +7 -0
  142. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +1 -1
  143. package/rancher-components/Pill/RcStatusBadge/index.ts +1 -1
  144. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +3 -3
  145. package/rancher-components/Pill/RcStatusIndicator/types.ts +1 -1
  146. package/rancher-components/Pill/RcTag/RcTag.test.ts +64 -0
  147. package/rancher-components/Pill/RcTag/RcTag.vue +94 -0
  148. package/rancher-components/Pill/RcTag/index.ts +1 -0
  149. package/rancher-components/Pill/RcTag/types.ts +9 -0
  150. package/rancher-components/Pill/types.ts +1 -0
  151. package/rancher-components/RcItemCard/RcItemCard.vue +1 -0
  152. package/rancher-components/RcItemCard/RcItemCardAction.vue +12 -0
  153. package/store/__tests__/catalog.test.ts +63 -0
  154. package/store/catalog.js +2 -2
  155. package/store/type-map.js +3 -15
  156. package/types/extension-manager.ts +26 -0
  157. package/types/shell/index.d.ts +121 -16
  158. package/utils/__tests__/product.test.ts +129 -0
  159. package/utils/__tests__/resource.test.ts +87 -0
  160. package/utils/alertmanagerconfig.js +2 -2
  161. package/utils/auth.js +3 -76
  162. package/utils/product.ts +39 -0
  163. package/utils/resource.ts +35 -0
  164. package/utils/select.js +0 -24
  165. package/utils/validators/formRules/__tests__/index.test.ts +3 -0
  166. package/utils/validators/formRules/index.ts +2 -1
  167. package/vue.config.js +1 -1
  168. package/components/Resource/Detail/Metadata/Rectangle.vue +0 -34
  169. package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +0 -24
  170. package/components/ResourceDetail/Masthead/__tests__/legacy.test.ts +0 -65
  171. /package/components/{ForceDirectedTreeChart.vue → ForceDirectedTreeChart/index.vue} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.5-rc.8",
3
+ "version": "3.0.5-rc.9",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@aws-sdk/client-ec2": "3.863.0",
31
- "@aws-sdk/client-eks": "3.863.0",
31
+ "@aws-sdk/client-eks": "3.879.0",
32
32
  "@aws-sdk/client-iam": "3.863.0",
33
33
  "@aws-sdk/client-kms": "3.863.0",
34
34
  "@smithy/fetch-http-handler": "5.1.1",
@@ -52,7 +52,7 @@
52
52
  "add": "2.0.6",
53
53
  "ansi_up": "5.0.0",
54
54
  "axios-retry": "3.1.9",
55
- "axios": "1.8.4",
55
+ "axios": "1.12.2",
56
56
  "babel-eslint": "10.1.0",
57
57
  "babel-plugin-module-resolver": "4.0.0",
58
58
  "babel-preset-vue": "2.0.2",
@@ -64,7 +64,7 @@
64
64
  "color": "4.2.3",
65
65
  "cookie-universal": "2.2.2",
66
66
  "cookie": "0.7.0",
67
- "core-js": "3.40.0",
67
+ "core-js": "3.45.0",
68
68
  "cron-validator": "1.4.0",
69
69
  "cronstrue": "2.53.0",
70
70
  "cross-env": "7.0.3",
@@ -74,7 +74,7 @@
74
74
  "cypress": "11.1.0",
75
75
  "d3-selection": "3.0.0",
76
76
  "d3": "7.3.0",
77
- "dayjs": "1.8.29",
77
+ "dayjs": "1.11.18",
78
78
  "defu": "5.0.1",
79
79
  "diff2html": "3.4.24",
80
80
  "dompurify": "3.2.5",
@@ -84,7 +84,7 @@
84
84
  "eslint-import-resolver-node": "0.3.9",
85
85
  "eslint-module-utils": "2.6.1",
86
86
  "eslint-plugin-cypress": "2.12.1",
87
- "eslint-plugin-import": "2.31.0",
87
+ "eslint-plugin-import": "2.32.0",
88
88
  "eslint-plugin-jest": "24.4.0",
89
89
  "eslint-plugin-n": "15.2.0",
90
90
  "eslint-plugin-vue": "9.32.0",
@@ -130,15 +130,15 @@
130
130
  "ufo": "0.7.11",
131
131
  "unfetch": "4.2.0",
132
132
  "url-parse": "1.5.10",
133
- "vue-router": "4.5.0",
133
+ "vue-router": "4.5.1",
134
134
  "vue-select": "4.0.0-beta.6",
135
135
  "vue-server-renderer": "2.7.16",
136
- "vue": "^3.2.13",
136
+ "vue": "3.5.18",
137
137
  "vue3-resize": "0.2.0",
138
138
  "vue3-virtual-scroll-list": "0.2.1",
139
139
  "vuedraggable": "4.1.0",
140
140
  "vuex": "4.1.0",
141
- "webpack-bundle-analyzer": "4.5.0",
141
+ "webpack-bundle-analyzer": "4.10.2",
142
142
  "webpack-virtual-modules": "0.4.3",
143
143
  "worker-loader": "3.0.8",
144
144
  "xterm-addon-canvas": "0.5.0",
@@ -172,4 +172,4 @@
172
172
  ".vue"
173
173
  ]
174
174
  }
175
- }
175
+ }
@@ -5,12 +5,15 @@ interface FooterItem {
5
5
  icon?: string;
6
6
  iconTooltip?: Record<{key?: string, text?: string}>;
7
7
  labels: string[];
8
+ labelTooltip?: string;
9
+ type?: string;
8
10
  }
9
11
 
10
12
  const emit = defineEmits<{(e: 'click:item', type: string, label: string): void; }>();
11
13
 
12
14
  defineProps<{
13
15
  items: FooterItem[];
16
+ clickable?: boolean;
14
17
  }>();
15
18
 
16
19
  function onClickItem(type: string, label: string) {
@@ -32,20 +35,32 @@ function onClickItem(type: string, label: string) {
32
35
  v-clean-tooltip="t(footerItem.iconTooltip?.key)"
33
36
  :class="['icon', 'app-chart-card-footer-item-icon', footerItem.icon]"
34
37
  />
35
- <rc-item-card-action
38
+ <template
36
39
  v-for="(label, j) in footerItem.labels"
37
40
  :key="j"
38
- v-clean-tooltip="footerItem.labelTooltip"
39
- class="app-chart-card-footer-item-text secondary-text-link"
40
- data-testid="app-chart-card-footer-item-text"
41
- tabindex="0"
42
- :aria-label="t('catalog.charts.appChartCard.footerItem.ariaLabel')"
43
- @click="onClickItem(footerItem.type, label)"
44
- @keydown.enter="onClickItem(footerItem.type, label)"
45
- @keydown.space.prevent="onClickItem(footerItem.type, label)"
46
41
  >
47
- {{ label }}<span v-if="footerItem.labels.length > 1 && j !== footerItem.labels.length - 1">, </span>
48
- </rc-item-card-action>
42
+ <rc-item-card-action
43
+ v-if="clickable && footerItem.type"
44
+ v-clean-tooltip="footerItem.labelTooltip"
45
+ class="app-chart-card-footer-item-text secondary-text-link"
46
+ data-testid="app-chart-card-footer-item-text"
47
+ tabindex="0"
48
+ :aria-label="t('catalog.charts.appChartCard.footerItem.ariaLabel')"
49
+ @click="onClickItem(footerItem.type, label)"
50
+ >
51
+ {{ label }}
52
+ <span v-if="footerItem.labels.length > 1 && j !== footerItem.labels.length - 1">, </span>
53
+ </rc-item-card-action>
54
+ <span
55
+ v-else
56
+ v-clean-tooltip="footerItem.labelTooltip"
57
+ class="app-chart-card-footer-item-text"
58
+ data-testid="app-chart-card-footer-item-text"
59
+ >
60
+ {{ label }}
61
+ <span v-if="footerItem.labels.length > 1 && j !== footerItem.labels.length - 1">, </span>
62
+ </span>
63
+ </template>
49
64
  </div>
50
65
  </div>
51
66
  </template>
@@ -6,7 +6,7 @@ import ChartReadme from '@shell/components/ChartReadme';
6
6
  import LazyImage from '@shell/components/LazyImage';
7
7
  import isEqual from 'lodash/isEqual';
8
8
  import {
9
- CHART, REPO, REPO_TYPE, VERSION, SEARCH_QUERY, CATEGORY, TAG
9
+ CHART, REPO, REPO_TYPE, VERSION, SEARCH_QUERY, CATEGORY, TAG, DEPRECATED
10
10
  } from '@shell/config/query-params';
11
11
  import { DATE_FORMAT } from '@shell/store/prefs';
12
12
  import { ZERO_TIME } from '@shell/config/types';
@@ -50,7 +50,14 @@ export default {
50
50
  ...mapGetters(['currentCluster']),
51
51
 
52
52
  headerContent() {
53
- return this.chart.cardContent;
53
+ return {
54
+ ...this.chart.cardContent,
55
+ subHeaderItems: this.chart.cardContent.subHeaderItems.map((item, i) => i === 0 ? ({
56
+ icon: 'icon-version-alt',
57
+ iconTooltip: { key: 'tableHeaders.version' },
58
+ label: this.query.versionName
59
+ }) : item)
60
+ };
54
61
  },
55
62
 
56
63
  versions() {
@@ -144,10 +151,11 @@ export default {
144
151
  product: this.$store.getters['productId'],
145
152
  },
146
153
  query: {
147
- [REPO_TYPE]: this.query.repoType,
148
- [REPO]: this.query.repoName,
149
- [CHART]: this.query.chartName,
150
- [VERSION]: this.query.versionName,
154
+ [REPO_TYPE]: this.query.repoType,
155
+ [REPO]: this.query.repoName,
156
+ [CHART]: this.query.chartName,
157
+ [VERSION]: this.query.versionName,
158
+ [DEPRECATED]: this.query.deprecated,
151
159
  }
152
160
  });
153
161
  },
@@ -210,17 +218,6 @@ export default {
210
218
  <template>
211
219
  <Loading v-if="$fetchState.pending" />
212
220
  <main v-else>
213
- <Banner
214
- v-if="versionInfoError"
215
- color="error"
216
- :label="versionInfoError"
217
- />
218
- <Banner
219
- v-if="warningMessage"
220
- color="warning"
221
- :label="warningMessage"
222
- data-testid="deprecation-and-experimental-banner"
223
- />
224
221
  <div
225
222
  v-if="chart"
226
223
  class="chart-header"
@@ -284,6 +281,7 @@ export default {
284
281
  </div>
285
282
  <div class="header-bottom">
286
283
  <AppChartCardFooter
284
+ :clickable="true"
287
285
  :items="headerContent.footerItems"
288
286
  @click:item="handleHeaderItemClick"
289
287
  />
@@ -296,15 +294,26 @@ export default {
296
294
  @click.prevent="install"
297
295
  >
298
296
  <i
299
- v-if="action === 'upgrade'"
300
- class="icon icon-upgrade-alt mmr-2"
297
+ :class="['icon', action.icon, 'mmr-2']"
301
298
  />
302
- {{ t(`asyncButton.${action}.action` ) }}
299
+ {{ t(`catalog.chart.chartButton.action.${action.tKey}` ) }}
303
300
  </RcButton>
304
301
  </div>
305
302
 
306
303
  <div class="dashed-spacer" />
307
304
 
305
+ <Banner
306
+ v-if="versionInfoError"
307
+ color="error"
308
+ :label="versionInfoError"
309
+ />
310
+ <Banner
311
+ v-if="warningMessage"
312
+ color="warning"
313
+ :label="warningMessage"
314
+ data-testid="deprecation-and-experimental-banner"
315
+ />
316
+
308
317
  <div
309
318
  v-if="requires.length || warnings.length || targetedAppWarning || osWarning"
310
319
  class="chart-banners"
@@ -624,6 +624,7 @@ export default {
624
624
  >
625
625
  <AppChartCardFooter
626
626
  :items="card.footerItems"
627
+ :clickable="true"
627
628
  @click:item="handleFooterItemClick"
628
629
  />
629
630
  </template>
@@ -629,19 +629,19 @@ export default {
629
629
  step1Description() {
630
630
  const descriptionKey = this.steps.find((s) => s.name === 'basics').descriptionKey;
631
631
 
632
- return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
632
+ return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
633
633
  },
634
634
 
635
635
  step2Description() {
636
636
  const descriptionKey = this.steps.find((s) => s.name === 'helmValues').descriptionKey;
637
637
 
638
- return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
638
+ return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
639
639
  },
640
640
 
641
641
  step3Description() {
642
642
  const descriptionKey = this.steps.find((s) => s.name === 'helmCli').descriptionKey;
643
643
 
644
- return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action, existing: !!this.existing }, '');
644
+ return this.$store.getters['i18n/withFallback'](descriptionKey, { action: this.action.name, existing: !!this.existing }, '');
645
645
  },
646
646
 
647
647
  steps() {
@@ -1299,7 +1299,8 @@ export default {
1299
1299
  :edit-first-step="true"
1300
1300
  :banner-title="stepperName"
1301
1301
  :banner-title-subtext="stepperSubtext"
1302
- :finish-mode="action"
1302
+ :finish-mode="action.name"
1303
+ :header-mode="action.tKey"
1303
1304
  class="wizard"
1304
1305
  :class="{'windowsIncompatible': windowsIncompatible}"
1305
1306
  @cancel="cancel"
@@ -1427,7 +1428,7 @@ export default {
1427
1428
  <Checkbox
1428
1429
  v-model:value="showCommandStep"
1429
1430
  class="mb-20"
1430
- :label="t('catalog.install.steps.helmCli.checkbox', { action, existing: !!existing })"
1431
+ :label="t('catalog.install.steps.helmCli.checkbox', { action: action.name, existing: !!existing })"
1431
1432
  />
1432
1433
 
1433
1434
  <Checkbox
@@ -2,23 +2,29 @@ import { clone } from '@shell/utils/object';
2
2
  import ClusterTools from '@shell/pages/c/_cluster/explorer/tools/index.vue';
3
3
  import { shallowMount } from '@vue/test-utils';
4
4
  import { MANAGEMENT } from '@shell/config/types';
5
+ import { RcItemCard } from '@components/RcItemCard';
6
+ import { APP_UPGRADE_STATUS } from '@shell/store/catalog';
5
7
 
6
8
  describe('page: cluster tools', () => {
7
9
  const mountOptions = {
8
10
  computed: {
9
- options: () => [
11
+ appChartCards: () => [
10
12
  {
11
- chart: {
12
- id: 'cluster/rancher-charts/rancher-alerting-drivers',
13
- iconName: 'icon',
14
- },
15
- app: {}
13
+ id: 'cluster/rancher-charts/rancher-alerting-drivers',
14
+ header: { title: { text: 'Rancher Alerting Drivers' } },
15
+ content: { text: 'Some description' },
16
+ image: { src: '' },
17
+ subHeaderItems: [],
18
+ installedApp: { spec: { chart: { metadata: { version: '1.0.0' } } } },
19
+ rawChart: { versions: [{ version: '1.0.0' }], blocked: false }
16
20
  }
17
21
  ]
18
22
  },
19
- global: {
23
+ methods: { getCardActions: (ClusterTools as any).methods.getCardActions },
24
+ global: {
20
25
  mocks: {
21
26
  $route: { query: {} },
27
+ t: (key: string) => key,
22
28
  $fetchState: {
23
29
  pending: false, error: true, timestamp: Date.now()
24
30
  },
@@ -36,7 +42,7 @@ describe('page: cluster tools', () => {
36
42
  }
37
43
  },
38
44
  currentCluster: { id: 'cluster', status: { provider: 'provider' } },
39
- 'i18n/t': jest.fn(),
45
+ 'i18n/t': (key: string) => key,
40
46
  }
41
47
  }
42
48
  },
@@ -44,10 +50,10 @@ describe('page: cluster tools', () => {
44
50
  };
45
51
 
46
52
  it('should show apps catalog', async() => {
47
- const wrapper = shallowMount(ClusterTools, mountOptions);
53
+ const wrapper = shallowMount(ClusterTools, { ...mountOptions, methods: { getCardActions: () => [] } });
48
54
 
49
55
  await (ClusterTools as any).fetch.call(wrapper.vm);
50
- const cards = wrapper.find('[data-testid^="cluster-tools-app"]');
56
+ const cards = wrapper.findComponent(RcItemCard);
51
57
 
52
58
  expect(cards.exists()).toBe(true);
53
59
  });
@@ -61,11 +67,95 @@ describe('page: cluster tools', () => {
61
67
  }
62
68
  };
63
69
 
64
- const wrapper = shallowMount(ClusterTools, options);
70
+ const wrapper = shallowMount(ClusterTools, { ...options, methods: { getCardActions: () => [] } });
65
71
 
66
72
  await (ClusterTools as any).fetch.call(wrapper.vm);
67
- const cards = wrapper.find('[data-testid^="cluster-tools-app"]');
73
+ const cards = wrapper.findComponent(RcItemCard);
68
74
 
69
75
  expect(cards.exists()).toBe(true);
70
76
  });
77
+
78
+ describe('getCardActions', () => {
79
+ it('should return "install" action for an uninstalled chart', () => {
80
+ const wrapper = shallowMount(ClusterTools, mountOptions);
81
+ const card = {
82
+ installedApp: null,
83
+ rawChart: { blocked: false }
84
+ };
85
+ const actions = wrapper.vm.getCardActions(card);
86
+
87
+ expect(actions).toHaveLength(1);
88
+ expect(actions[0]).toStrictEqual({
89
+ label: 'catalog.tools.action.install',
90
+ action: 'install',
91
+ icon: 'icon-plus',
92
+ enabled: true
93
+ });
94
+ });
95
+
96
+ it('should return all actions for an installed chart', () => {
97
+ const wrapper = shallowMount(ClusterTools, mountOptions);
98
+ const card = {
99
+ installedApp: {
100
+ spec: { chart: { metadata: { version: '1.0.1' } } },
101
+ upgradeAvailable: APP_UPGRADE_STATUS.SINGLE_UPGRADE
102
+ },
103
+ rawChart: { versions: [{ version: '1.0.2' }, { version: '1.0.1' }, { version: '1.0.0' }] }
104
+ };
105
+ const actions = wrapper.vm.getCardActions(card);
106
+
107
+ expect(actions).toHaveLength(5); // Upgrade, Edit, Downgrade, separator, Remove
108
+ expect(actions[0]).toStrictEqual({
109
+ label: 'catalog.tools.action.upgrade',
110
+ icon: 'icon-upgrade-alt',
111
+ action: 'upgrade'
112
+ });
113
+ expect(actions[1]).toStrictEqual({
114
+ label: 'catalog.tools.action.edit',
115
+ icon: 'icon-edit',
116
+ action: 'edit'
117
+ });
118
+ expect(actions[2]).toStrictEqual({
119
+ label: 'catalog.tools.action.downgrade',
120
+ icon: 'icon-history',
121
+ action: 'downgrade'
122
+ });
123
+ expect(actions[3]).toStrictEqual({ divider: true });
124
+ expect(actions[4]).toStrictEqual({
125
+ label: 'catalog.tools.action.remove',
126
+ icon: 'icon-delete',
127
+ action: 'remove'
128
+ });
129
+ });
130
+
131
+ it('should not show upgrade if not available', () => {
132
+ const wrapper = shallowMount(ClusterTools, mountOptions);
133
+ const card = {
134
+ installedApp: {
135
+ spec: { chart: { metadata: { version: '1.0.2' } } },
136
+ upgradeAvailable: APP_UPGRADE_STATUS.NO_UPGRADE
137
+ },
138
+ rawChart: { versions: [{ version: '1.0.2' }, { version: '1.0.1' }, { version: '1.0.0' }] }
139
+ };
140
+ const actions = wrapper.vm.getCardActions(card);
141
+
142
+ expect(actions.find((a) => a.action === 'upgrade')).toBeUndefined();
143
+ expect(actions).toHaveLength(4); // Edit, Downgrade, separator, Remove
144
+ });
145
+
146
+ it('should not show downgrade if not available', () => {
147
+ const wrapper = shallowMount(ClusterTools, mountOptions);
148
+ const card = {
149
+ installedApp: {
150
+ spec: { chart: { metadata: { version: '1.0.0' } } },
151
+ upgradeAvailable: APP_UPGRADE_STATUS.SINGLE_UPGRADE
152
+ },
153
+ rawChart: { versions: [{ version: '1.0.1' }, { version: '1.0.0' }] }
154
+ };
155
+ const actions = wrapper.vm.getCardActions(card);
156
+
157
+ expect(actions.find((a) => a.action === 'downgrade')).toBeUndefined();
158
+ expect(actions).toHaveLength(4); // Upgrade, Edit, separator, Remove
159
+ });
160
+ });
71
161
  });