@rancher/shell 3.0.8-rc.8 → 3.0.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 (260) hide show
  1. package/apis/impl/apis.ts +61 -0
  2. package/apis/index.ts +40 -0
  3. package/apis/intf/modal.ts +90 -0
  4. package/apis/intf/shell.ts +36 -0
  5. package/apis/intf/slide-in.ts +98 -0
  6. package/apis/intf/system.ts +41 -0
  7. package/apis/shell/__tests__/modal.test.ts +80 -0
  8. package/apis/shell/__tests__/notifications.test.ts +71 -0
  9. package/apis/shell/__tests__/slide-in.test.ts +54 -0
  10. package/apis/shell/__tests__/system.test.ts +129 -0
  11. package/apis/shell/index.ts +38 -0
  12. package/apis/shell/modal.ts +41 -0
  13. package/apis/shell/notifications.ts +65 -0
  14. package/apis/shell/slide-in.ts +33 -0
  15. package/apis/shell/system.ts +65 -0
  16. package/apis/vue-shim.d.ts +11 -0
  17. package/assets/brand/suse/dark/rancher-logo.svg +1 -64
  18. package/assets/styles/global/_tooltip.scss +6 -1
  19. package/assets/translations/en-us.yaml +14 -1
  20. package/components/ActionMenuShell.vue +3 -1
  21. package/components/BackLink.vue +8 -0
  22. package/components/BannerGraphic.vue +1 -5
  23. package/components/BrandImage.vue +17 -6
  24. package/components/Cron/CronExpressionEditor.vue +1 -1
  25. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  26. package/components/CruResource.vue +8 -1
  27. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
  28. package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
  29. package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
  30. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
  31. package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
  32. package/components/LocaleSelector.vue +2 -2
  33. package/components/ModalManager.vue +11 -1
  34. package/components/Questions/__tests__/Yaml.test.ts +1 -1
  35. package/components/Questions/__tests__/index.test.ts +159 -0
  36. package/components/RelatedResources.vue +5 -0
  37. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  38. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  39. package/components/Resource/Detail/Metadata/index.vue +3 -3
  40. package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
  41. package/components/Resource/Detail/composables.ts +2 -2
  42. package/components/ResourceDetail/Masthead/latest.vue +23 -21
  43. package/components/ResourceDetail/index.vue +3 -0
  44. package/components/ResourceTable.vue +54 -21
  45. package/components/SlideInPanelManager.vue +16 -11
  46. package/components/SortableTable/THead.vue +2 -1
  47. package/components/SortableTable/index.vue +20 -2
  48. package/components/Tabbed/__tests__/index.test.ts +86 -0
  49. package/components/Tabbed/index.vue +37 -2
  50. package/components/__tests__/NamespaceFilter.test.ts +49 -0
  51. package/components/auth/SelectPrincipal.vue +28 -6
  52. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  53. package/components/auth/login/ldap.vue +3 -3
  54. package/components/fleet/FleetSecretSelector.vue +1 -1
  55. package/components/form/KeyValue.vue +1 -1
  56. package/components/form/NameNsDescription.vue +1 -1
  57. package/components/form/NodeScheduling.vue +2 -2
  58. package/components/form/ResourceTabs/composable.ts +2 -2
  59. package/components/form/ResourceTabs/index.vue +0 -2
  60. package/components/form/__tests__/NameNsDescription.test.ts +42 -0
  61. package/components/formatter/InternalExternalIP.vue +4 -1
  62. package/components/formatter/LinkName.vue +5 -0
  63. package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
  64. package/components/nav/Group.vue +25 -7
  65. package/components/nav/Header.vue +1 -1
  66. package/components/nav/NamespaceFilter.vue +1 -0
  67. package/components/nav/Type.vue +17 -6
  68. package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
  69. package/components/nav/__tests__/Type.test.ts +59 -0
  70. package/components/templates/standalone.vue +1 -1
  71. package/composables/cruResource.ts +27 -0
  72. package/composables/focusTrap.ts +3 -1
  73. package/composables/resourceDetail.ts +15 -0
  74. package/composables/useI18n.ts +10 -1
  75. package/composables/useLabeledFormElement.ts +3 -4
  76. package/config/__test__/uiplugins.test.ts +309 -0
  77. package/config/labels-annotations.js +1 -0
  78. package/config/product/explorer.js +3 -1
  79. package/config/product/fleet.js +1 -1
  80. package/config/router/navigation-guards/clusters.js +3 -3
  81. package/config/router/navigation-guards/products.js +1 -1
  82. package/config/router/routes.js +7 -7
  83. package/config/types.js +7 -0
  84. package/config/uiplugins.js +46 -2
  85. package/core/__tests__/extension-manager-impl.test.js +437 -0
  86. package/core/extension-manager-impl.js +21 -25
  87. package/core/plugin-helpers.ts +2 -2
  88. package/core/plugin.ts +9 -1
  89. package/core/plugins-loader.js +2 -2
  90. package/core/types-provisioning.ts +5 -1
  91. package/core/types.ts +35 -0
  92. package/detail/provisioning.cattle.io.cluster.vue +9 -6
  93. package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
  94. package/dialog/MoveNamespaceDialog.vue +20 -4
  95. package/dialog/RollbackWorkloadDialog.vue +2 -5
  96. package/dialog/SearchDialog.vue +1 -0
  97. package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
  98. package/directives/__tests__/clean-tooltip.test.ts +298 -0
  99. package/directives/clean-tooltip.ts +234 -0
  100. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
  101. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +100 -3
  102. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  103. package/edit/configmap.vue +1 -0
  104. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  105. package/edit/fleet.cattle.io.helmop.vue +11 -6
  106. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  107. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  108. package/edit/logging-flow/index.vue +1 -0
  109. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  110. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  111. package/edit/management.cattle.io.project.vue +1 -0
  112. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  113. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  114. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  115. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  116. package/edit/monitoring.coreos.com.route.vue +1 -1
  117. package/edit/namespace.vue +1 -0
  118. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  119. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  120. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  121. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  122. package/edit/node.vue +1 -0
  123. package/edit/persistentvolume/index.vue +27 -22
  124. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  125. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  126. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  127. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  128. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  129. package/edit/persistentvolume/plugins/csi.vue +18 -16
  130. package/edit/persistentvolume/plugins/fc.vue +13 -14
  131. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  132. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  133. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  134. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  135. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  136. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  137. package/edit/persistentvolume/plugins/local.vue +1 -3
  138. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  139. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  140. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  141. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  142. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  143. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  144. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  145. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  146. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  147. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
  148. package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
  149. package/edit/provisioning.cattle.io.cluster/rke2.vue +9 -8
  150. package/edit/resources.cattle.io.restore.vue +1 -1
  151. package/edit/secret/index.vue +1 -1
  152. package/edit/service.vue +1 -0
  153. package/edit/serviceaccount.vue +1 -0
  154. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  155. package/edit/workload/Job.vue +2 -2
  156. package/edit/workload/index.vue +2 -1
  157. package/edit/workload/mixins/workload.js +1 -1
  158. package/initialize/App.vue +4 -4
  159. package/initialize/install-plugins.js +19 -5
  160. package/machine-config/azure.vue +1 -1
  161. package/machine-config/components/GCEImage.vue +1 -1
  162. package/mixins/__tests__/brand.spec.ts +2 -2
  163. package/mixins/brand.js +1 -7
  164. package/mixins/create-edit-view/index.js +5 -0
  165. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
  166. package/models/chart.js +70 -74
  167. package/models/management.cattle.io.cluster.js +21 -3
  168. package/models/provisioning.cattle.io.cluster.js +31 -11
  169. package/package.json +11 -10
  170. package/pages/auth/login.vue +4 -6
  171. package/pages/auth/setup.vue +1 -1
  172. package/pages/auth/verify.vue +3 -3
  173. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  174. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  175. package/pages/c/_cluster/apps/charts/index.vue +122 -24
  176. package/pages/c/_cluster/apps/charts/install.vue +33 -0
  177. package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
  178. package/pages/c/_cluster/explorer/index.vue +8 -6
  179. package/pages/c/_cluster/fleet/index.vue +4 -7
  180. package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
  181. package/pages/c/_cluster/settings/brand.vue +1 -1
  182. package/pages/c/_cluster/settings/index.vue +5 -0
  183. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  184. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  185. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  186. package/pkg/auto-import.js +3 -3
  187. package/pkg/dynamic-importer.lib.js +1 -1
  188. package/pkg/import.js +1 -1
  189. package/plugins/__tests__/mutations.tests.ts +179 -0
  190. package/plugins/dashboard-client-init.js +3 -0
  191. package/plugins/dashboard-store/getters.js +19 -2
  192. package/plugins/dashboard-store/model-loader.js +1 -1
  193. package/plugins/dashboard-store/mutations.js +23 -2
  194. package/plugins/dashboard-store/resource-class.js +11 -5
  195. package/plugins/i18n.js +8 -0
  196. package/plugins/plugin.js +2 -2
  197. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
  198. package/plugins/steve/steve-class.js +1 -1
  199. package/plugins/steve/steve-pagination-utils.ts +131 -47
  200. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  201. package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
  202. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
  203. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  204. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  205. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  206. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  207. package/rancher-components/Pill/types.ts +0 -1
  208. package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
  209. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  210. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  211. package/rancher-components/RcIcon/index.ts +1 -0
  212. package/rancher-components/RcIcon/types.ts +160 -0
  213. package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
  214. package/rancher-components/utils/status.test.ts +67 -0
  215. package/rancher-components/utils/status.ts +77 -0
  216. package/scripts/publish-shell.sh +25 -0
  217. package/scripts/typegen.sh +1 -0
  218. package/store/__tests__/catalog.test.ts +1 -1
  219. package/store/__tests__/type-map.test.ts +164 -2
  220. package/store/action-menu.js +8 -0
  221. package/store/auth.js +25 -13
  222. package/store/catalog.js +6 -0
  223. package/store/i18n.js +3 -3
  224. package/store/index.js +8 -6
  225. package/store/notifications.ts +2 -0
  226. package/store/prefs.js +6 -7
  227. package/store/type-map.js +17 -7
  228. package/store/wm.ts +4 -4
  229. package/types/internal-api/shell/modal.d.ts +6 -6
  230. package/types/notifications/index.ts +126 -15
  231. package/types/rancher/index.d.ts +9 -0
  232. package/types/shell/index.d.ts +54 -3
  233. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  234. package/types/store/pagination.types.ts +157 -9
  235. package/types/vue-shim.d.ts +5 -4
  236. package/utils/__tests__/provider.test.ts +98 -0
  237. package/utils/__tests__/router.test.js +238 -0
  238. package/utils/__tests__/selector-typed.test.ts +263 -0
  239. package/utils/cluster.js +4 -1
  240. package/utils/color.js +1 -1
  241. package/utils/dynamic-content/__tests__/info.test.ts +6 -0
  242. package/utils/dynamic-content/info.ts +43 -0
  243. package/utils/favicon.js +4 -4
  244. package/utils/fleet.ts +8 -1
  245. package/utils/pagination-utils.ts +2 -2
  246. package/utils/pagination-wrapper.ts +1 -1
  247. package/utils/provider.ts +14 -0
  248. package/utils/router.js +50 -0
  249. package/utils/selector-typed.ts +6 -2
  250. package/utils/unit-tests/pagination-utils.spec.ts +8 -8
  251. package/vue.config.js +3 -3
  252. package/composables/useExtensionManager.ts +0 -17
  253. package/core/plugins.js +0 -38
  254. package/directives/clean-tooltip.js +0 -32
  255. package/plugins/internal-api/index.ts +0 -37
  256. package/plugins/internal-api/shared/base-api.ts +0 -13
  257. package/plugins/internal-api/shell/shell.api.ts +0 -108
  258. package/plugins/nuxt-client-init.js +0 -3
  259. package/types/internal-api/shell/growl.d.ts +0 -25
  260. package/types/internal-api/shell/slideIn.d.ts +0 -15
package/models/chart.js CHANGED
@@ -136,91 +136,87 @@ export default class Chart extends SteveModel {
136
136
  * @returns {Object} Card content object with `subHeaderItems`, `footerItems`, and `statuses` arrays.
137
137
  */
138
138
  get cardContent() {
139
- if (!this._cardContent) {
140
- const latestVersion = this.latestCompatibleVersion;
141
- const subHeaderItems = [];
142
-
143
- if (latestVersion) {
144
- const hasZeroTime = latestVersion.created === ZERO_TIME;
145
-
146
- subHeaderItems.push({
147
- icon: 'icon-version-alt',
148
- iconTooltip: { key: 'tableHeaders.version' },
149
- label: latestVersion.version
150
- });
151
-
152
- const lastUpdatedItem = {
153
- icon: 'icon-refresh-alt',
154
- iconTooltip: { key: 'tableHeaders.lastUpdated' },
155
- label: hasZeroTime ? this.t('generic.na') : day(latestVersion.created).format('MMM D, YYYY')
156
- };
157
-
158
- if (hasZeroTime) {
159
- lastUpdatedItem.labelTooltip = this.t('catalog.charts.appChartCard.subHeaderItem.missingVersionDate');
160
- }
161
-
162
- subHeaderItems.push(lastUpdatedItem);
163
- }
139
+ const latestVersion = this.latestCompatibleVersion;
140
+ const subHeaderItems = [];
141
+
142
+ if (latestVersion) {
143
+ const hasZeroTime = latestVersion.created === ZERO_TIME;
144
+
145
+ subHeaderItems.push({
146
+ icon: 'icon-version-alt',
147
+ iconTooltip: { key: 'tableHeaders.version' },
148
+ label: latestVersion.version
149
+ });
150
+
151
+ const lastUpdatedItem = {
152
+ icon: 'icon-refresh-alt',
153
+ iconTooltip: { key: 'tableHeaders.lastUpdated' },
154
+ label: hasZeroTime ? this.t('generic.na') : day(latestVersion.created).format('MMM D, YYYY')
155
+ };
164
156
 
165
- const footerItems = [
166
- {
167
- type: REPO,
168
- icon: 'icon-repository-alt',
169
- iconTooltip: { key: 'tableHeaders.repoName' },
170
- labels: [this.repoNameDisplay],
171
- labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.repo') }, true)
172
- }
173
- ];
174
-
175
- if (this.categories.length) {
176
- footerItems.push( {
177
- type: CATEGORY,
178
- icon: 'icon-category-alt',
179
- iconTooltip: { key: 'generic.category' },
180
- labels: this.categories,
181
- labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.category') }, true)
182
- });
157
+ if (hasZeroTime) {
158
+ lastUpdatedItem.labelTooltip = this.t('catalog.charts.appChartCard.subHeaderItem.missingVersionDate');
183
159
  }
184
160
 
185
- if (this.tags.length) {
186
- footerItems.push({
187
- type: TAG,
188
- icon: 'icon-tag-alt',
189
- iconTooltip: { key: 'generic.tags' },
190
- labels: this.tags,
191
- labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.tag') }, true)
192
- });
161
+ subHeaderItems.push(lastUpdatedItem);
162
+ }
163
+
164
+ const footerItems = [
165
+ {
166
+ type: REPO,
167
+ icon: 'icon-repository-alt',
168
+ iconTooltip: { key: 'tableHeaders.repoName' },
169
+ labels: [this.repoNameDisplay],
170
+ labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.repo') }, true)
193
171
  }
172
+ ];
173
+
174
+ if (this.categories.length) {
175
+ footerItems.push( {
176
+ type: CATEGORY,
177
+ icon: 'icon-category-alt',
178
+ iconTooltip: { key: 'generic.category' },
179
+ labels: this.categories,
180
+ labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.category') }, true)
181
+ });
182
+ }
194
183
 
195
- const statuses = [];
184
+ if (this.tags.length) {
185
+ footerItems.push({
186
+ type: TAG,
187
+ icon: 'icon-tag-alt',
188
+ iconTooltip: { key: 'generic.tags' },
189
+ labels: this.tags,
190
+ labelTooltip: this.t('catalog.charts.findSimilar.message', { type: this.t('catalog.charts.findSimilar.types.tag') }, true)
191
+ });
192
+ }
196
193
 
197
- if (this.deprecated) {
198
- statuses.push({
199
- icon: 'icon-alert-alt', color: 'error', tooltip: { key: 'generic.deprecated' }
200
- });
201
- }
194
+ const statuses = [];
202
195
 
203
- if (this.upgradeable) {
204
- statuses.push({
205
- icon: 'icon-upgrade-alt', color: 'info', tooltip: { key: 'generic.upgradeable' }
206
- });
207
- }
196
+ if (this.deprecated) {
197
+ statuses.push({
198
+ icon: 'icon-alert-alt', color: 'error', tooltip: { key: 'generic.deprecated' }
199
+ });
200
+ }
208
201
 
209
- if (this.isInstalled) {
210
- const installedVersion = this.matchingInstalledApps[0]?.spec?.chart?.metadata?.version;
202
+ if (this.upgradeable) {
203
+ statuses.push({
204
+ icon: 'icon-upgrade-alt', color: 'info', tooltip: { key: 'generic.upgradeable' }
205
+ });
206
+ }
211
207
 
212
- statuses.push({
213
- icon: 'icon-confirmation-alt', color: 'success', tooltip: { text: `${ this.t('generic.installed') } (${ installedVersion })` }
214
- });
215
- }
208
+ if (this.isInstalled) {
209
+ const installedVersion = this.matchingInstalledApps[0]?.spec?.chart?.metadata?.version;
216
210
 
217
- this._cardContent = {
218
- subHeaderItems,
219
- footerItems,
220
- statuses
221
- };
211
+ statuses.push({
212
+ icon: 'icon-confirmation-alt', color: 'success', tooltip: { text: `${ this.t('generic.installed') } (${ installedVersion })` }
213
+ });
222
214
  }
223
215
 
224
- return this._cardContent;
216
+ return {
217
+ subHeaderItems,
218
+ footerItems,
219
+ statuses
220
+ };
225
221
  }
226
222
  }
@@ -15,6 +15,7 @@ import { LINUX, WINDOWS } from '@shell/store/catalog';
15
15
  import { KONTAINER_TO_DRIVER } from './management.cattle.io.kontainerdriver';
16
16
  import { PINNED_CLUSTERS } from '@shell/store/prefs';
17
17
  import { copyTextToClipboard } from '@shell/utils/clipboard';
18
+ import { isHostedProvider } from '@shell/utils/provider';
18
19
 
19
20
  const DEFAULT_BADGE_COLOR = '#707070';
20
21
 
@@ -171,9 +172,20 @@ export default class MgmtCluster extends SteveModel {
171
172
  return this.isCondition('Ready');
172
173
  }
173
174
 
175
+ get config() {
176
+ if (!this.spec?.[`${ this.provisioner }Config`]) {
177
+ const allKeys = Object.keys(this.spec);
178
+ const configKey = allKeys.find( (k) => k.endsWith('Config'));
179
+
180
+ return this.spec[configKey];
181
+ }
182
+
183
+ return this.spec?.[`${ this.provisioner }Config`];
184
+ }
185
+
174
186
  get kubernetesVersionRaw() {
175
187
  const fromStatus = this.status?.version?.gitVersion;
176
- const fromSpec = this.spec?.[`${ this.provisioner }Config`]?.kubernetesVersion;
188
+ const fromSpec = this.config?.kubernetesVersion;
177
189
 
178
190
  return fromStatus || fromSpec;
179
191
  }
@@ -239,9 +251,15 @@ export default class MgmtCluster extends SteveModel {
239
251
  }
240
252
 
241
253
  get isHostedKubernetesProvider() {
242
- const providers = ['AKS', 'EKS', 'GKE'];
254
+ const context = {
255
+ dispatch: this.$dispatch,
256
+ getters: this.$getters,
257
+ axios: this.$axios,
258
+ $extension: this.$extension,
259
+ t: (...args) => this.t.apply(this, args),
260
+ };
243
261
 
244
- return providers.includes(this.provisioner);
262
+ return isHostedProvider(context, this.provisioner);
245
263
  }
246
264
 
247
265
  get providerLogo() {
@@ -16,6 +16,7 @@ import jsyaml from 'js-yaml';
16
16
  import { defineAsyncComponent, markRaw } from 'vue';
17
17
  import stevePaginationUtils from '@shell/plugins/steve/steve-pagination-utils';
18
18
  import { PaginationFilterField, PaginationParamFilter } from '@shell/types/store/pagination.types';
19
+ import { isHostedProvider } from '@shell/utils/provider';
19
20
 
20
21
  const RKE1_ALLOWED_ACTIONS = [
21
22
  'promptRemove',
@@ -272,9 +273,26 @@ export default class ProvCluster extends SteveModel {
272
273
  }
273
274
 
274
275
  get isHostedKubernetesProvider() {
275
- const providers = ['AKS', 'EKS', 'GKE'];
276
+ const context = {
277
+ dispatch: this.$dispatch,
278
+ getters: this.$getters,
279
+ axios: this.$axios,
280
+ $extension: this.$extension,
281
+ t: (...args) => this.t.apply(this, args),
282
+ };
276
283
 
277
- return providers.includes(this.provisioner);
284
+ return isHostedProvider(context, this.provisioner);
285
+ }
286
+
287
+ get providerConfig() {
288
+ if ( this.isRke2 ) {
289
+ return this.spec.rkeConfig;
290
+ }
291
+ if (this.mgmt && this.mgmt.config) {
292
+ return this.mgmt.config;
293
+ }
294
+
295
+ return null;
278
296
  }
279
297
 
280
298
  get isPrivateHostedProvider() {
@@ -308,19 +326,21 @@ export default class ProvCluster extends SteveModel {
308
326
 
309
327
  // imported rke2 and k3s have status.driver === rke2 and k3s respectively
310
328
  // Provisioned rke2 and k3s have status.driver === imported
311
- if (this.mgmt?.status?.provider === 'k3s' || this.mgmt?.status?.provider === 'rke2') {
312
- return this.mgmt?.status?.driver === this.mgmt?.status?.provider;
329
+ const provider = this.mgmt?.status?.provider;
330
+ const driver = this.mgmt?.status?.driver;
331
+
332
+ // The main case
333
+ if (provider === 'k3s' || provider === 'rke2') {
334
+ return driver === provider;
335
+ }
336
+ // The 'waiting' case
337
+ if (!provider && (driver === 'k3s' || driver === 'rke2')) {
338
+ return true;
313
339
  }
314
340
 
315
341
  // imported KEv2
316
342
  // we can't rely on this.provisioner to determine imported-ness for these clusters, as it will return 'aks' 'eks' 'gke' for both provisioned and imported clusters
317
- const kontainerConfigs = ['aksConfig', 'eksConfig', 'gkeConfig'];
318
-
319
- const isImportedKontainer = kontainerConfigs.filter((key) => {
320
- return this.mgmt?.spec?.[key]?.imported === true;
321
- }).length;
322
-
323
- if (isImportedKontainer) {
343
+ if (this.isHostedKubernetesProvider && !!this.providerConfig.imported) {
324
344
  return true;
325
345
  }
326
346
 
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.8-rc.8",
3
+ "version": "3.0.8",
4
4
  "description": "Rancher Dashboard Shell",
5
- "repository": "https://github.com/rancherlabs/dashboard",
5
+ "repository": "https://github.com/rancher/dashboard",
6
6
  "license": "Apache-2.0",
7
7
  "author": "SUSE",
8
8
  "private": false,
9
+ "types": "types/shell/index.d.ts",
9
10
  "engines": {
10
11
  "node": ">=20.0.0"
11
12
  },
@@ -38,7 +39,7 @@
38
39
  "@babel/preset-typescript": "7.16.7",
39
40
  "@novnc/novnc": "1.2.0",
40
41
  "@popperjs/core": "2.11.8",
41
- "@rancher/icons": "2.0.53",
42
+ "@rancher/icons": "2.0.54",
42
43
  "@types/is-url": "1.2.30",
43
44
  "@types/node": "20.10.8",
44
45
  "@types/semver": "^7.5.8",
@@ -52,16 +53,16 @@
52
53
  "add": "2.0.6",
53
54
  "ansi_up": "5.0.0",
54
55
  "axios-retry": "3.1.9",
55
- "axios": "1.12.2",
56
+ "axios": "1.13.2",
56
57
  "babel-eslint": "10.1.0",
57
- "babel-plugin-module-resolver": "4.0.0",
58
+ "babel-plugin-module-resolver": "5.0.2",
58
59
  "babel-preset-vue": "2.0.2",
59
60
  "cache-loader": "4.1.0",
60
- "chart.js": "4.4.8",
61
+ "chart.js": "4.5.1",
61
62
  "clipboard-polyfill": "4.0.1",
62
63
  "codemirror-editor-vue3": "2.8.0",
63
64
  "codemirror": ">=5.64.0 <6",
64
- "color": "4.2.3",
65
+ "color": "5.0.3",
65
66
  "cookie-universal": "2.2.2",
66
67
  "cookie": "0.7.0",
67
68
  "core-js": "3.45.0",
@@ -105,7 +106,7 @@
105
106
  "jquery": "3.5.1",
106
107
  "js-cookie": "3.0.5",
107
108
  "js-yaml-loader": "1.2.2",
108
- "js-yaml": "4.1.0",
109
+ "js-yaml": "4.1.1",
109
110
  "jsdiff": "1.1.1",
110
111
  "jsonpath-plus": "10.3.0",
111
112
  "jsrsasign": "11.0.0",
@@ -114,7 +115,7 @@
114
115
  "marked": "4.0.17",
115
116
  "node-polyfill-webpack-plugin": "3.0.0",
116
117
  "nodemon": "2.0.22",
117
- "nyc": "15.1.0",
118
+ "nyc": "17.1.0",
118
119
  "papaparse": "5.3.0",
119
120
  "portal-vue": "~3.0.0",
120
121
  "sass-loader": "12.6.0",
@@ -139,7 +140,7 @@
139
140
  "vuedraggable": "4.1.0",
140
141
  "vuex": "4.1.0",
141
142
  "webpack-bundle-analyzer": "4.10.2",
142
- "webpack-virtual-modules": "0.4.3",
143
+ "webpack-virtual-modules": "0.6.2",
143
144
  "worker-loader": "3.0.8",
144
145
  "xterm-addon-canvas": "0.5.0",
145
146
  "xterm-addon-fit": "0.8.0",
@@ -137,9 +137,7 @@ export default {
137
137
  },
138
138
 
139
139
  customizations() {
140
- const globalSettings = this.$store.getters['management/all'](MANAGEMENT.SETTING);
141
- const setting = globalSettings?.find((gs) => gs.id === SETTING.BRAND);
142
- const brandMeta = getBrandMeta(setting?.value);
140
+ const brandMeta = getBrandMeta(this.$store.getters['management/brand']);
143
141
  const login = brandMeta?.login || {};
144
142
 
145
143
  return {
@@ -317,9 +315,9 @@ export default {
317
315
  // so we manually load them here - other SSO auth providers bounce out and back to the Dashboard, so on the bounce-back
318
316
  // the plugins will load via the boot-time plugin
319
317
  await loadPlugins({
320
- app: this.$store.app,
321
- store: this.$store,
322
- $plugin: this.$store.$plugin
318
+ app: this.$store.app,
319
+ store: this.$store,
320
+ $extension: this.$store.$extension,
323
321
  });
324
322
 
325
323
  if (this.firstLogin || user[0]?.mustChangePassword) {
@@ -209,7 +209,7 @@ export default {
209
209
  const promises = [];
210
210
 
211
211
  try {
212
- await applyProducts(this.$store, this.$plugin);
212
+ await applyProducts(this.$store, this.$extension);
213
213
  await this.$store.dispatch('loadManagement');
214
214
 
215
215
  if ( this.mustChangePassword ) {
@@ -119,9 +119,9 @@ export default {
119
119
 
120
120
  // Load plugins
121
121
  await loadPlugins({
122
- app: this.$store.app,
123
- store: this.$store,
124
- $plugin: this.$store.$plugin
122
+ app: this.$store.app,
123
+ store: this.$store,
124
+ $extension: this.$store.$extension,
125
125
  });
126
126
 
127
127
  this.$router.replace(backTo);
@@ -0,0 +1,135 @@
1
+ import Chart from '@shell/pages/c/_cluster/apps/charts/chart.vue';
2
+
3
+ jest.mock('clipboard-polyfill', () => ({ writeText: () => {} }));
4
+
5
+ describe('page: Chart Detail', () => {
6
+ describe('computed: maintainers', () => {
7
+ it('should return an empty array if no maintainers are provided', () => {
8
+ const thisContext = {
9
+ version: {},
10
+ versionInfo: null,
11
+ };
12
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
13
+
14
+ expect(result).toStrictEqual([]);
15
+ });
16
+
17
+ it('should return an empty array for empty maintainers arrays', () => {
18
+ const thisContext = {
19
+ version: { maintainers: [] },
20
+ versionInfo: { chart: { maintainers: [] } },
21
+ };
22
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
23
+
24
+ expect(result).toStrictEqual([]);
25
+ });
26
+
27
+ it('should prioritize maintainers from "version"', () => {
28
+ const thisContext = {
29
+ version: {
30
+ maintainers: [
31
+ { name: 'Version Maintainer', email: 'version@test.com' }
32
+ ]
33
+ },
34
+ versionInfo: {
35
+ chart: {
36
+ maintainers: [
37
+ { name: 'VersionInfo Maintainer', email: 'versioninfo@test.com' }
38
+ ]
39
+ }
40
+ },
41
+ };
42
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
43
+
44
+ expect(result).toHaveLength(1);
45
+ expect(result[0].name).toBe('Version Maintainer');
46
+ });
47
+
48
+ it('should fall back to maintainers from "versionInfo"', () => {
49
+ const thisContext = {
50
+ version: {},
51
+ versionInfo: {
52
+ chart: {
53
+ maintainers: [
54
+ { name: 'VersionInfo Maintainer', email: 'versioninfo@test.com' }
55
+ ]
56
+ }
57
+ },
58
+ };
59
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
60
+
61
+ expect(result).toHaveLength(1);
62
+ expect(result[0].name).toBe('VersionInfo Maintainer');
63
+ });
64
+
65
+ it('should correctly map all maintainer fields', () => {
66
+ const thisContext = {
67
+ version: {
68
+ maintainers: [
69
+ {
70
+ name: 'Full Maintainer', email: 'full@test.com', url: 'http://full.com'
71
+ }
72
+ ]
73
+ },
74
+ versionInfo: null,
75
+ };
76
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
77
+ const expected = {
78
+ id: 'Full Maintainer-0',
79
+ name: 'Full Maintainer',
80
+ href: 'http://full.com',
81
+ label: 'Full Maintainer'
82
+ };
83
+
84
+ expect(result[0]).toStrictEqual(expected);
85
+ });
86
+
87
+ it('should handle maintainers with missing optional fields', () => {
88
+ const thisContext = {
89
+ version: {
90
+ maintainers: [
91
+ { name: 'No Email Maintainer', url: 'http://noemail.com' },
92
+ { name: 'No URL Maintainer', email: 'nourl@test.com' },
93
+ { name: 'Name Only Maintainer' },
94
+ { url: 'http://noname.com' },
95
+ { email: 'noname@test.com' }
96
+ ]
97
+ },
98
+ versionInfo: null,
99
+ };
100
+ const result = (Chart.computed!.maintainers as () => any[]).call(thisContext);
101
+
102
+ expect(result).toHaveLength(5);
103
+ expect(result[0]).toStrictEqual({
104
+ id: 'No Email Maintainer-0',
105
+ name: 'No Email Maintainer',
106
+ href: 'http://noemail.com',
107
+ label: 'No Email Maintainer'
108
+ });
109
+ expect(result[1]).toStrictEqual({
110
+ id: 'No URL Maintainer-1',
111
+ name: 'No URL Maintainer',
112
+ href: 'mailto:nourl@test.com',
113
+ label: 'No URL Maintainer'
114
+ });
115
+ expect(result[2]).toStrictEqual({
116
+ id: 'Name Only Maintainer-2',
117
+ name: 'Name Only Maintainer',
118
+ href: null,
119
+ label: 'Name Only Maintainer'
120
+ });
121
+ expect(result[3]).toStrictEqual({
122
+ id: 'undefined-3',
123
+ name: undefined,
124
+ href: 'http://noname.com',
125
+ label: 'http://noname.com'
126
+ });
127
+ expect(result[4]).toStrictEqual({
128
+ id: 'undefined-4',
129
+ name: undefined,
130
+ href: 'mailto:noname@test.com',
131
+ label: 'noname@test.com'
132
+ });
133
+ });
134
+ });
135
+ });
@@ -84,11 +84,21 @@ export default {
84
84
  maintainers() {
85
85
  const maintainers = this.version.maintainers || this.versionInfo?.chart?.maintainers || [];
86
86
 
87
- return maintainers.map((m) => {
87
+ return maintainers.map((m, i) => {
88
+ const label = m.name || m.url || m.email || this.t('generic.unknown');
89
+ let href = null;
90
+
91
+ if (m.url) {
92
+ href = m.url;
93
+ } else if (m.email) {
94
+ href = `mailto:${ m.email }`;
95
+ }
96
+
88
97
  return {
89
- id: m.name,
90
- text: m.name,
91
- url: m.email ? `mailto:${ m.email }` : m.url
98
+ id: `${ m.name }-${ i }`,
99
+ name: m.name,
100
+ label,
101
+ href
92
102
  };
93
103
  });
94
104
  },
@@ -456,18 +466,26 @@ export default {
456
466
  data-testid="chart-home-link"
457
467
  >{{ home }}<i class="icon icon-external-link" /><span class="sr-only">{{ t('generic.opensInNewTab') }}</span></a>
458
468
  </div>
459
- <div
460
- v-if="maintainers.length"
461
- class="chart-body__info-section"
462
- >
469
+ <div class="chart-body__info-section">
463
470
  <h4>{{ t('catalog.chart.info.maintainers') }}</h4>
464
- <a
465
- v-for="m of maintainers"
466
- :key="m.id"
467
- :href="m.url"
468
- rel="nofollow noopener noreferrer"
469
- target="_blank"
470
- >{{ m.text }}<span class="sr-only">{{ t('generic.opensInNewTab') }}</span></a>
471
+ <template v-if="maintainers.length">
472
+ <div
473
+ v-for="m of maintainers"
474
+ :key="m.id"
475
+ >
476
+ <a
477
+ v-if="m.href"
478
+ v-clean-tooltip="m.name ? t('catalog.chart.info.maintainerContactTooltip', { maintainer: m.name }) : undefined"
479
+ :href="m.href"
480
+ rel="nofollow noopener noreferrer"
481
+ target="_blank"
482
+ >
483
+ {{ m.label }}
484
+ </a>
485
+ <span v-else>{{ m.label }}</span>
486
+ </div>
487
+ </template>
488
+ <span v-else>{{ t('generic.unknown') }}</span>
471
489
  </div>
472
490
  <div
473
491
  v-if="version.sources"