@rancher/shell 3.0.8-rc.1 → 3.0.8-rc.10

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 (323) hide show
  1. package/assets/brand/suse/banner.svg +1 -0
  2. package/assets/brand/suse/dark/banner.svg +1 -0
  3. package/assets/brand/suse/dark/login-landscape.svg +1 -0
  4. package/assets/brand/suse/dark/rancher-logo.svg +1 -1
  5. package/assets/brand/suse/favicon.png +0 -0
  6. package/assets/brand/suse/login-landscape.svg +1 -0
  7. package/assets/brand/suse/metadata.json +11 -1
  8. package/assets/brand/suse/rancher-logo.svg +1 -1
  9. package/assets/fonts/suse/suse-v2-latin-300.woff +0 -0
  10. package/assets/fonts/suse/suse-v2-latin-300.woff2 +0 -0
  11. package/assets/fonts/suse/suse-v2-latin-600.woff +0 -0
  12. package/assets/fonts/suse/suse-v2-latin-600.woff2 +0 -0
  13. package/assets/fonts/suse/suse-v2-latin-700.woff +0 -0
  14. package/assets/fonts/suse/suse-v2-latin-700.woff2 +0 -0
  15. package/assets/fonts/suse/suse-v2-latin-800.woff +0 -0
  16. package/assets/fonts/suse/suse-v2-latin-800.woff2 +0 -0
  17. package/assets/fonts/suse/suse-v2-latin-regular.woff +0 -0
  18. package/assets/fonts/suse/suse-v2-latin-regular.woff2 +0 -0
  19. package/assets/images/content/README.md +5 -0
  20. package/assets/images/content/cloud-native.svg +84 -0
  21. package/assets/images/content/dark/cloud-native.svg +21 -0
  22. package/assets/images/content/dark/shield.svg +59 -0
  23. package/assets/images/content/dark/suse.svg +10 -0
  24. package/assets/images/content/shield.svg +59 -0
  25. package/assets/images/content/suse.svg +10 -0
  26. package/assets/styles/base/_typography.scss +1 -0
  27. package/assets/styles/fonts/_fontstack.scss +53 -1
  28. package/assets/styles/global/_cards.scss +0 -3
  29. package/assets/styles/global/_layout.scss +21 -35
  30. package/assets/styles/themes/_dark.scss +1 -1
  31. package/assets/styles/themes/_light.scss +1 -1
  32. package/assets/styles/themes/_modern.scss +11 -3
  33. package/assets/styles/themes/_suse.scss +116 -24
  34. package/assets/translations/en-us.yaml +94 -10
  35. package/components/AutoscalerCard.vue +113 -0
  36. package/components/AutoscalerTab.vue +94 -0
  37. package/components/BackLink.vue +8 -0
  38. package/components/BannerGraphic.vue +36 -21
  39. package/components/BrandImage.vue +17 -6
  40. package/components/ClusterIconMenu.vue +1 -1
  41. package/components/ClusterProviderIcon.vue +1 -1
  42. package/components/Cron/CronExpressionEditor.vue +1 -1
  43. package/components/Cron/CronExpressionEditorModal.vue +1 -1
  44. package/components/Drawer/Chrome.vue +2 -6
  45. package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +4 -9
  46. package/components/Drawer/ResourceDetailDrawer/YamlTab.vue +3 -8
  47. package/components/Drawer/ResourceDetailDrawer/composables.ts +3 -4
  48. package/components/Drawer/ResourceDetailDrawer/index.vue +4 -9
  49. package/components/Drawer/ResourceDetailDrawer/types.ts +17 -0
  50. package/components/Drawer/types.ts +3 -0
  51. package/components/DynamicContent/DynamicContentBanner.vue +102 -0
  52. package/components/DynamicContent/DynamicContentCloseButton.vue +42 -0
  53. package/components/DynamicContent/DynamicContentIcon.vue +132 -0
  54. package/components/DynamicContent/DynamicContentPanel.vue +112 -0
  55. package/components/DynamicContent/content.ts +78 -0
  56. package/components/EmberPage.vue +1 -1
  57. package/components/IconOrSvg.vue +2 -2
  58. package/components/PaginatedResourceTable.vue +2 -6
  59. package/components/PopoverCard.vue +192 -0
  60. package/components/Questions/__tests__/index.test.ts +159 -0
  61. package/components/Resource/Detail/CopyToClipboard.vue +4 -1
  62. package/components/Resource/Detail/FetchLoader/composables.ts +18 -4
  63. package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
  64. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +1 -1
  65. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +4 -0
  66. package/components/Resource/Detail/Metadata/KeyValueRow.vue +1 -1
  67. package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
  68. package/components/Resource/Detail/Metadata/composables.ts +9 -9
  69. package/components/Resource/Detail/Metadata/index.vue +3 -3
  70. package/components/Resource/Detail/ResourcePopover/ResourcePopoverCard.vue +2 -19
  71. package/components/Resource/Detail/ResourcePopover/__tests__/ResourcePopoverCard.test.ts +0 -29
  72. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +132 -150
  73. package/components/Resource/Detail/ResourcePopover/index.vue +54 -159
  74. package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +0 -2
  75. package/components/Resource/Detail/TitleBar/composables.ts +2 -1
  76. package/components/Resource/Detail/TitleBar/index.vue +10 -6
  77. package/components/Resource/Detail/composables.ts +12 -0
  78. package/components/ResourceDetail/Masthead/latest.vue +29 -0
  79. package/components/ResourceDetail/index.vue +4 -1
  80. package/components/ResourceList/Masthead.vue +1 -1
  81. package/components/SortableTable/index.vue +1 -0
  82. package/components/Tabbed/__tests__/index.test.ts +86 -0
  83. package/components/{nav/WindowManager → Window}/ContainerLogs.vue +1 -1
  84. package/components/{nav/WindowManager → Window}/ContainerLogsActions.vue +1 -0
  85. package/components/{nav/WindowManager → Window}/__tests__/ContainerLogs.test.ts +1 -1
  86. package/components/{nav/WindowManager → Window}/__tests__/ContainerShell.test.ts +2 -2
  87. package/components/__tests__/AutoscalerCard.test.ts +154 -0
  88. package/components/__tests__/AutoscalerTab.test.ts +125 -0
  89. package/components/__tests__/PopoverCard.test.ts +204 -0
  90. package/components/auth/SelectPrincipal.vue +24 -6
  91. package/components/auth/__tests__/SelectPrincipal.test.ts +119 -0
  92. package/components/formatter/Autoscaler.vue +97 -0
  93. package/components/formatter/InternalExternalIP.vue +198 -24
  94. package/components/formatter/__tests__/Autoscaler.test.ts +156 -0
  95. package/components/formatter/__tests__/InternalExternalIP.test.ts +133 -0
  96. package/components/google/util/__tests__/formatter.test.ts +47 -0
  97. package/components/google/util/formatter.ts +5 -2
  98. package/components/nav/Group.vue +12 -3
  99. package/components/nav/Header.vue +36 -16
  100. package/components/nav/NamespaceFilter.vue +13 -1
  101. package/components/nav/NotificationCenter/index.vue +2 -1
  102. package/components/nav/TopLevelMenu.helper.ts +16 -6
  103. package/components/nav/TopLevelMenu.vue +4 -2
  104. package/components/{DraggableZone.vue → nav/WindowManager/PinArea.vue} +47 -80
  105. package/components/nav/WindowManager/composables/useComponentsMount.ts +70 -0
  106. package/components/nav/WindowManager/composables/useDimensionsHandler.ts +105 -0
  107. package/components/nav/WindowManager/composables/useDragHandler.ts +99 -0
  108. package/components/nav/WindowManager/composables/usePanelHandler.ts +72 -0
  109. package/components/nav/WindowManager/composables/usePanelsHandler.ts +14 -0
  110. package/components/nav/WindowManager/composables/useResizeHandler.ts +167 -0
  111. package/components/nav/WindowManager/composables/useTabsHandler.ts +51 -0
  112. package/components/nav/WindowManager/constants.ts +23 -0
  113. package/components/nav/WindowManager/index.vue +61 -575
  114. package/components/nav/WindowManager/panels/HorizontalPanel.vue +265 -0
  115. package/components/nav/WindowManager/panels/TabBodyContainer.vue +39 -0
  116. package/components/nav/WindowManager/panels/VerticalPanel.vue +308 -0
  117. package/components/templates/default.vue +4 -40
  118. package/components/templates/home.vue +31 -5
  119. package/components/templates/plain.vue +30 -4
  120. package/components/templates/standalone.vue +1 -1
  121. package/composables/useI18n.ts +10 -1
  122. package/composables/useInterval.ts +15 -0
  123. package/config/__test__/uiplugins.test.ts +309 -0
  124. package/config/labels-annotations.js +9 -1
  125. package/config/product/explorer.js +3 -1
  126. package/config/product/manager.js +20 -9
  127. package/config/router/routes.js +10 -2
  128. package/config/settings.ts +2 -1
  129. package/config/store.js +4 -2
  130. package/config/table-headers.js +8 -0
  131. package/config/types.js +9 -0
  132. package/config/uiplugins.js +46 -2
  133. package/config/version.js +1 -1
  134. package/core/__test__/extension-manager-impl.test.js +236 -0
  135. package/core/extension-manager-impl.js +23 -6
  136. package/core/plugin-helpers.ts +2 -0
  137. package/core/types-provisioning.ts +4 -1
  138. package/detail/pod.vue +1 -0
  139. package/detail/provisioning.cattle.io.cluster.vue +13 -1
  140. package/dialog/DeveloperLoadExtensionDialog.vue +12 -3
  141. package/dialog/RollbackWorkloadDialog.vue +2 -5
  142. package/directives/ui-context.ts +103 -0
  143. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +2 -2
  144. package/edit/auth/__tests__/oidc.test.ts +26 -0
  145. package/edit/auth/github.vue +5 -0
  146. package/edit/auth/oidc.vue +5 -1
  147. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
  148. package/edit/cloudcredential.vue +1 -1
  149. package/edit/configmap.vue +1 -0
  150. package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
  151. package/edit/fleet.cattle.io.gitrepo.vue +0 -10
  152. package/edit/fleet.cattle.io.helmop.vue +6 -6
  153. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  154. package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
  155. package/edit/logging-flow/index.vue +1 -0
  156. package/edit/logging.banzaicloud.io.output/index.vue +1 -0
  157. package/edit/management.cattle.io.fleetworkspace.vue +1 -1
  158. package/edit/management.cattle.io.project.vue +1 -0
  159. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
  160. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
  161. package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
  162. package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
  163. package/edit/monitoring.coreos.com.route.vue +1 -1
  164. package/edit/namespace.vue +1 -0
  165. package/edit/networking.istio.io.destinationrule/index.vue +1 -0
  166. package/edit/networking.k8s.io.ingress/index.vue +1 -0
  167. package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
  168. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
  169. package/edit/node.vue +1 -0
  170. package/edit/persistentvolume/index.vue +27 -22
  171. package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
  172. package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
  173. package/edit/persistentvolume/plugins/azureFile.vue +15 -14
  174. package/edit/persistentvolume/plugins/cephfs.vue +15 -14
  175. package/edit/persistentvolume/plugins/cinder.vue +15 -14
  176. package/edit/persistentvolume/plugins/csi.vue +18 -16
  177. package/edit/persistentvolume/plugins/fc.vue +13 -14
  178. package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
  179. package/edit/persistentvolume/plugins/flocker.vue +1 -3
  180. package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
  181. package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
  182. package/edit/persistentvolume/plugins/hostPath.vue +40 -39
  183. package/edit/persistentvolume/plugins/iscsi.vue +13 -14
  184. package/edit/persistentvolume/plugins/local.vue +1 -3
  185. package/edit/persistentvolume/plugins/longhorn.vue +23 -22
  186. package/edit/persistentvolume/plugins/nfs.vue +15 -14
  187. package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
  188. package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
  189. package/edit/persistentvolume/plugins/quobyte.vue +15 -14
  190. package/edit/persistentvolume/plugins/rbd.vue +15 -14
  191. package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
  192. package/edit/persistentvolume/plugins/storageos.vue +15 -14
  193. package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
  194. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +32 -5
  195. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +35 -0
  196. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +155 -0
  197. package/edit/provisioning.cattle.io.cluster/index.vue +25 -15
  198. package/edit/provisioning.cattle.io.cluster/rke2.vue +42 -8
  199. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +107 -5
  200. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +92 -4
  201. package/edit/secret/index.vue +1 -1
  202. package/edit/service.vue +9 -4
  203. package/edit/serviceaccount.vue +1 -0
  204. package/edit/storage.k8s.io.storageclass/index.vue +1 -0
  205. package/edit/workload/index.vue +2 -1
  206. package/edit/workload/mixins/workload.js +1 -1
  207. package/initialize/App.vue +4 -4
  208. package/initialize/install-directives.js +2 -0
  209. package/initialize/install-plugins.js +19 -2
  210. package/list/provisioning.cattle.io.cluster.vue +15 -2
  211. package/machine-config/amazonec2.vue +42 -135
  212. package/machine-config/components/EC2Networking.vue +490 -0
  213. package/machine-config/components/__tests__/EC2Networking.test.ts +148 -0
  214. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +294 -0
  215. package/machine-config/digitalocean.vue +11 -0
  216. package/machine-config/google.vue +1 -1
  217. package/mixins/__tests__/brand.spec.ts +2 -2
  218. package/mixins/__tests__/chart.test.ts +21 -0
  219. package/mixins/brand.js +1 -7
  220. package/mixins/chart.js +7 -1
  221. package/mixins/create-edit-view/index.js +5 -0
  222. package/models/__tests__/chart.test.ts +33 -4
  223. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +112 -5
  224. package/models/chart.js +25 -13
  225. package/models/cluster/node.js +13 -6
  226. package/models/cluster.x-k8s.io.machine.js +10 -20
  227. package/models/cluster.x-k8s.io.machinedeployment.js +5 -1
  228. package/models/management.cattle.io.cluster.js +21 -3
  229. package/models/management.cattle.io.kontainerdriver.js +1 -0
  230. package/models/provisioning.cattle.io.cluster.js +249 -33
  231. package/package.json +6 -5
  232. package/pages/auth/login.vue +38 -2
  233. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
  234. package/pages/c/_cluster/apps/charts/chart.vue +33 -15
  235. package/pages/c/_cluster/apps/charts/index.vue +11 -13
  236. package/pages/c/_cluster/apps/charts/install.vue +1 -1
  237. package/pages/c/_cluster/explorer/index.vue +8 -6
  238. package/pages/c/_cluster/manager/hostedprovider/index.vue +220 -0
  239. package/pages/c/_cluster/settings/brand.vue +1 -1
  240. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
  241. package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
  242. package/pages/c/_cluster/uiplugins/index.vue +126 -184
  243. package/pages/home.vue +14 -4
  244. package/pkg/dynamic-importer.lib.js +4 -0
  245. package/plugins/dashboard-client-init.js +3 -0
  246. package/plugins/dashboard-store/getters.js +18 -1
  247. package/plugins/dashboard-store/resource-class.js +4 -4
  248. package/plugins/dynamic-content.js +13 -0
  249. package/plugins/i18n.js +8 -0
  250. package/plugins/steve/__tests__/steve-pagination-utils.test.ts +333 -0
  251. package/plugins/steve/steve-pagination-utils.ts +39 -20
  252. package/plugins/steve/subscribe.js +17 -9
  253. package/plugins/subscribe-events.ts +4 -2
  254. package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
  255. package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -34
  256. package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
  257. package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
  258. package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
  259. package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
  260. package/rancher-components/Pill/types.ts +0 -1
  261. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -0
  262. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +5 -1
  263. package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
  264. package/rancher-components/RcIcon/RcIcon.vue +46 -0
  265. package/rancher-components/RcIcon/index.ts +1 -0
  266. package/rancher-components/RcIcon/types.ts +160 -0
  267. package/rancher-components/utils/status.test.ts +67 -0
  268. package/rancher-components/utils/status.ts +77 -0
  269. package/scripts/typegen.sh +1 -0
  270. package/store/action-menu.js +8 -0
  271. package/store/auth.js +3 -3
  272. package/store/catalog.js +6 -0
  273. package/store/features.js +1 -0
  274. package/store/index.js +36 -17
  275. package/store/notifications.ts +51 -4
  276. package/store/plugins.js +7 -3
  277. package/store/prefs.js +6 -6
  278. package/store/type-map.js +3 -3
  279. package/store/ui-context.ts +86 -0
  280. package/store/wm.ts +244 -0
  281. package/types/notifications/index.ts +27 -3
  282. package/types/shell/index.d.ts +79 -4
  283. package/types/store/__tests__/pagination.types.spec.ts +137 -0
  284. package/types/store/pagination.types.ts +157 -9
  285. package/types/store/subscribe-events.types.ts +8 -1
  286. package/types/store/subscribe.types.ts +1 -0
  287. package/types/window-manager.ts +24 -0
  288. package/utils/__tests__/object.test.ts +19 -0
  289. package/utils/__tests__/provider.test.ts +98 -0
  290. package/utils/__tests__/selector-typed.test.ts +263 -0
  291. package/utils/__tests__/version.test.ts +19 -1
  292. package/utils/autoscaler-utils.ts +7 -0
  293. package/utils/back-off.ts +3 -3
  294. package/utils/brand.ts +29 -0
  295. package/utils/chart.js +18 -0
  296. package/utils/color.js +1 -1
  297. package/utils/dynamic-content/__tests__/announcement.test.ts +498 -0
  298. package/utils/dynamic-content/__tests__/info.test.ts +21 -9
  299. package/utils/dynamic-content/announcement.ts +142 -0
  300. package/utils/dynamic-content/example.json +40 -0
  301. package/utils/dynamic-content/index.ts +6 -2
  302. package/utils/dynamic-content/info.ts +44 -2
  303. package/utils/dynamic-content/new-release.ts +1 -1
  304. package/utils/dynamic-content/notification-handler.ts +48 -0
  305. package/utils/dynamic-content/types.d.ts +53 -1
  306. package/utils/dynamic-importer.js +2 -2
  307. package/utils/favicon.js +4 -4
  308. package/utils/object.js +20 -2
  309. package/utils/pagination-wrapper.ts +12 -8
  310. package/utils/provider.ts +14 -0
  311. package/utils/scroll.js +7 -0
  312. package/utils/selector-typed.ts +6 -2
  313. package/utils/settings.ts +15 -0
  314. package/utils/validators/machine-pool.ts +13 -3
  315. package/utils/version.js +15 -0
  316. package/assets/images/icons/document.svg +0 -3
  317. package/plugins/nuxt-client-init.js +0 -3
  318. package/store/wm.js +0 -95
  319. /package/components/{nav/WindowManager → Window}/ChartReadme.vue +0 -0
  320. /package/components/{nav/WindowManager → Window}/ContainerShell.vue +0 -0
  321. /package/components/{nav/WindowManager → Window}/KubectlShell.vue +0 -0
  322. /package/components/{nav/WindowManager → Window}/MachineSsh.vue +0 -0
  323. /package/components/{nav/WindowManager → Window}/Window.vue +0 -0
@@ -32,6 +32,7 @@ import loadPlugins from '@shell/plugins/plugin';
32
32
  import Loading from '@shell/components/Loading';
33
33
  import { HARVESTER_NAME as HARVESTER } from '@shell/config/features';
34
34
  import TabTitle from '@shell/components/TabTitle.vue';
35
+ import { getBrandMeta } from '@shell/utils/brand';
35
36
 
36
37
  export default {
37
38
  name: 'Login',
@@ -134,6 +135,25 @@ export default {
134
135
  hasLoginMessage() {
135
136
  return this.errorToDisplay || this.loggedOut || this.timedOut;
136
137
  },
138
+
139
+ customizations() {
140
+ const brandMeta = getBrandMeta(this.$store.getters['management/brand']);
141
+ const login = brandMeta?.login || {};
142
+
143
+ return {
144
+ welcomeLabelKey: 'login.welcome',
145
+ logoClass: 'login-logo',
146
+ ...login,
147
+ };
148
+ },
149
+
150
+ bannerClass() {
151
+ return this.customizations.bannerClass;
152
+ },
153
+
154
+ brandLogo() {
155
+ return this.customizations.logo;
156
+ }
137
157
  },
138
158
 
139
159
  async fetch() {
@@ -335,11 +355,20 @@ export default {
335
355
  </TabTitle>
336
356
  <div class="row gutless mb-20">
337
357
  <div class="col span-6 p-20">
338
- <p class="text-center">
358
+ <p
359
+ v-if="!brandLogo"
360
+ class="text-center"
361
+ >
339
362
  {{ t('login.howdy') }}
340
363
  </p>
364
+ <BrandImage
365
+ v-else
366
+ :class="{[customizations.logoClass]: !!customizations.logoClass}"
367
+ :file-name="brandLogo"
368
+ :alt="t('login.landscapeAlt')"
369
+ />
341
370
  <h1 class="text-center login-welcome">
342
- {{ t('login.welcome', {vendor}) }}
371
+ {{ t(customizations.welcomeLabelKey, {vendor}) }}
343
372
  </h1>
344
373
  <div
345
374
  class="login-messages"
@@ -524,6 +553,7 @@ export default {
524
553
  </div>
525
554
  </div>
526
555
  <BrandImage
556
+ :class="bannerClass"
527
557
  class="col span-6 landscape"
528
558
  data-testid="login-landscape__img"
529
559
  file-name="login-landscape.svg"
@@ -552,6 +582,12 @@ export default {
552
582
  margin: 0
553
583
  }
554
584
 
585
+ .login-logo {
586
+ align-self: center;
587
+ max-width: 260px;
588
+ margin-bottom: 20px;
589
+ }
590
+
555
591
  .login-messages {
556
592
  display: flex;
557
593
  justify-content: center;
@@ -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"
@@ -7,7 +7,7 @@ import {
7
7
  REPO_TYPE, REPO, CHART, VERSION, SEARCH_QUERY, SORT_BY, _FLAGGED, CATEGORY, DEPRECATED, HIDDEN, TAG, STATUS
8
8
  } from '@shell/config/query-params';
9
9
  import { DOCS_BASE } from '@shell/config/private-label';
10
- import { APP_STATUS, compatibleVersionsFor, filterAndArrangeCharts, normalizeFilterQuery } from '@shell/store/catalog';
10
+ import { APP_STATUS, filterAndArrangeCharts, normalizeFilterQuery } from '@shell/store/catalog';
11
11
  import { lcFirst } from '@shell/utils/string';
12
12
  import { sortBy } from '@shell/utils/sort';
13
13
  import debounce from 'lodash/debounce';
@@ -24,6 +24,7 @@ import AppChartCardFooter from '@shell/pages/c/_cluster/apps/charts/AppChartCard
24
24
  import AddRepoLink from '@shell/pages/c/_cluster/apps/charts/AddRepoLink';
25
25
  import StatusLabel from '@shell/pages/c/_cluster/apps/charts/StatusLabel';
26
26
  import RichTranslation from '@shell/components/RichTranslation.vue';
27
+ import { getLatestCompatibleVersion } from '@shell/utils/chart';
27
28
  import Select from '@shell/components/form/Select';
28
29
 
29
30
  const createInitialFilters = () => ({
@@ -190,6 +191,13 @@ export default {
190
191
  sort: this.selectedSortOption
191
192
  });
192
193
 
194
+ const OSs = this.currentCluster.workerOSs;
195
+ const showPrerelease = this.$store.getters['prefs/get'](SHOW_PRE_RELEASE);
196
+
197
+ res.forEach((chart) => {
198
+ chart._latestCompatibleVersion = getLatestCompatibleVersion(chart, OSs, showPrerelease);
199
+ });
200
+
193
201
  // status filtering is separated from other filters because "isInstalled" and "upgradeable" statuses are already calculated in models/chart.js
194
202
  // by doing this we won't need to re-calculate it in filterAndArrangeCharts
195
203
  if (!statuses.length) {
@@ -265,7 +273,7 @@ export default {
265
273
  statuses: chart.cardContent.statuses
266
274
  },
267
275
  subHeaderItems: chart.cardContent.subHeaderItems,
268
- image: { src: chart.versions[0].icon, alt: { text: this.t('catalog.charts.iconAlt', { app: get(chart, 'chartNameDisplay') }) } },
276
+ image: { src: chart.latestCompatibleVersion.icon, alt: { text: this.t('catalog.charts.iconAlt', { app: get(chart, 'chartNameDisplay') }) } },
269
277
  content: { text: chart.chartDescription },
270
278
  footerItems: chart.cardContent.footerItems,
271
279
  rawChart: chart
@@ -343,17 +351,7 @@ export default {
343
351
  }, 100),
344
352
 
345
353
  selectChart(chart) {
346
- let version;
347
- const OSs = this.currentCluster.workerOSs;
348
- const showPrerelease = this.$store.getters['prefs/get'](SHOW_PRE_RELEASE);
349
- const compatibleVersions = compatibleVersionsFor(chart, OSs, showPrerelease);
350
- const versions = chart.versions;
351
-
352
- if (compatibleVersions.length > 0) {
353
- version = compatibleVersions[0].version;
354
- } else {
355
- version = versions[0].version;
356
- }
354
+ const version = chart.latestCompatibleVersion.version;
357
355
 
358
356
  const query = {
359
357
  [REPO_TYPE]: chart.repoType,
@@ -1203,7 +1203,7 @@ export default {
1203
1203
  const { allValues, values: crdValues } = versionInfo;
1204
1204
 
1205
1205
  // only save crd values that differ from the defaults defined in chart values.yaml
1206
- const customizedCrdValues = diff(crdValues, allValues);
1206
+ const customizedCrdValues = diff(crdValues, allValues, true);
1207
1207
 
1208
1208
  // CRD globals should be overwritten by main chart globals
1209
1209
  // we want to avoid including globals present on crd values and not main chart values
@@ -222,7 +222,7 @@ export default {
222
222
  displayProvider() {
223
223
  const other = 'other';
224
224
 
225
- let provider = this.currentCluster?.status?.provider || other;
225
+ let provider = this.currentCluster?.status?.provider || this.currentCluster?.status?.driver.toLowerCase() || other;
226
226
 
227
227
  if (provider === 'rke.windows') {
228
228
  provider = 'rkeWindows';
@@ -484,6 +484,12 @@ export default {
484
484
  hasNodes() {
485
485
  return this.nodes?.length > 0;
486
486
  },
487
+ kubernetesVersion() {
488
+ const base = this.currentCluster?.kubernetesVersionBase || '';
489
+ const extension = this.currentCluster?.kubernetesVersionExtension || '';
490
+
491
+ return `${ base }${ extension }`;
492
+ }
487
493
  },
488
494
 
489
495
  methods: {
@@ -661,11 +667,7 @@ export default {
661
667
  </div>
662
668
  <div data-testid="kubernetesVersion__label">
663
669
  <label>{{ t('glance.version') }}: </label>
664
- <span>{{ currentCluster.kubernetesVersionBase }}</span>
665
- <span
666
- v-if="currentCluster.kubernetesVersionExtension"
667
- style="font-size: 0.75em"
668
- >{{ currentCluster.kubernetesVersionExtension }}</span>
670
+ <span>{{ kubernetesVersion }}</span>
669
671
  </div>
670
672
  <div
671
673
  v-if="hasNodes"
@@ -0,0 +1,220 @@
1
+ <script>
2
+ import { MANAGEMENT, HOSTED_PROVIDER } from '@shell/config/types';
3
+ import { SETTING } from '@shell/config/settings';
4
+ import { STATE, NAME } from '@shell/config/table-headers';
5
+ import ResourceTable from '@shell/components/ResourceTable';
6
+ import Masthead from '@shell/components/ResourceList/Masthead';
7
+ import Banner from '@components/Banner/Banner.vue';
8
+ import RcStatusBadge from '@components/Pill/RcStatusBadge/RcStatusBadge.vue';
9
+ import { exceptionToErrorsArray } from '@shell/utils/error';
10
+ import { isRancherPrime } from '@shell/config/version';
11
+ import { stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
12
+ import { getHostedProviders } from '@shell/utils/provider';
13
+
14
+ export default {
15
+ name: 'HostedProviders',
16
+ components: {
17
+ ResourceTable, Masthead, RcStatusBadge, Banner
18
+ },
19
+ data() {
20
+ return {
21
+ errors: [],
22
+ rows: [],
23
+ allProviders: null,
24
+ resource: HOSTED_PROVIDER,
25
+ schema: this.$store.getters['rancher/schemaFor'](HOSTED_PROVIDER),
26
+ prime: isRancherPrime(),
27
+ settingResource: null
28
+ };
29
+ },
30
+ fetch() {
31
+ this.allProviders = this.getProviders();
32
+ this.getSettings();
33
+ this.generateRows();
34
+ },
35
+ watch: {
36
+ settings() {
37
+ this.generateRows();
38
+ },
39
+ allProviders() {
40
+ this.generateRows();
41
+ }
42
+ },
43
+ computed: {
44
+ headers() {
45
+ return [
46
+ STATE,
47
+ NAME,
48
+ ];
49
+ },
50
+ settings() {
51
+ const providerTypesJSON = this.settingResource?.value;
52
+ const providerTypes = providerTypesJSON ? JSON.parse(providerTypesJSON) : [];
53
+ const settingsDict = {};
54
+
55
+ providerTypes.forEach((p) => {
56
+ settingsDict[p.name] = p.active;
57
+ });
58
+
59
+ return settingsDict;
60
+ },
61
+
62
+ },
63
+ methods: {
64
+ getProviders() {
65
+ const context = {
66
+ dispatch: this.$store.dispatch,
67
+ getters: this.$store.getters,
68
+ axios: this.$store.$axios,
69
+ $extension: this.$store.app.$extension,
70
+ t: (...args) => this.t.apply(this, args),
71
+ };
72
+
73
+ return getHostedProviders(context);
74
+ },
75
+ getSettings() {
76
+ this.settingResource = this.$store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.KEV2_OPERATORS );
77
+ },
78
+ stateDisplay(row) {
79
+ if (!row.active) {
80
+ return stateDisplay(STATES_ENUM.INACTIVE);
81
+ }
82
+
83
+ return stateDisplay(STATES_ENUM.ACTIVE);
84
+ },
85
+ async setSetting(resources, active) {
86
+ try {
87
+ const providerTypes = this.settingResource.value ? JSON.parse(this.settingResource.value) : [];
88
+ const providerMap = new Map(providerTypes.map((prov) => [prov.name, prov]));
89
+
90
+ resources.forEach((resource) => {
91
+ const provider = providerMap.get(resource.id);
92
+
93
+ if (provider) {
94
+ provider.active = active;
95
+ } else {
96
+ providerMap.set(resource.id, { name: resource.id, active });
97
+ }
98
+ });
99
+
100
+ this.settingResource.value = JSON.stringify(Array.from(providerMap.values()));
101
+ await this.settingResource.save();
102
+ this.getSettings();
103
+ } catch (e) {
104
+ this.errors = exceptionToErrorsArray(e);
105
+ }
106
+ },
107
+ async generateRows() {
108
+ this.rows = this.allProviders.map((p) => {
109
+ const active = p.id in this.settings ? this.settings[p.id] : true;
110
+ const canNotPrime = p.prime && !this.prime;
111
+ const canNotChangeSettings = !this.settingResource?.canUpdate;
112
+ const enableAction = {
113
+ action: 'activate',
114
+ label: this.t('action.activate'),
115
+ icon: 'icon icon-play',
116
+ bulkable: true,
117
+ enabled: !active && !canNotPrime && !canNotChangeSettings,
118
+ invoke: async(opts, resources) => {
119
+ await this.setSetting(resources, true);
120
+ }
121
+ };
122
+ const disableAction = {
123
+ action: 'deactivate',
124
+ label: this.t('action.deactivate'),
125
+ icon: 'icon icon-pause',
126
+ bulkable: true,
127
+ enabled: active && !canNotChangeSettings,
128
+ weight: -1,
129
+ invoke: async(opts, resources) => {
130
+ await this.setSetting(resources, false);
131
+ }
132
+ };
133
+ const availableActions = [enableAction, disableAction];
134
+
135
+ return {
136
+ id: p.id,
137
+ name: p.label,
138
+ nameDisplay: p.label,
139
+ description: p.description || '',
140
+ prime: p.prime,
141
+ active,
142
+ availableActions
143
+ };
144
+ }) || [];
145
+ },
146
+ closeError(index) {
147
+ this.errors.splice(index, 1);
148
+ },
149
+ },
150
+ };
151
+ </script>
152
+
153
+ <template>
154
+ <div>
155
+ <Masthead
156
+ :schema="schema"
157
+ :resource="resource"
158
+ :type-display="t('providers.hosted.title')"
159
+ :is-creatable="false"
160
+ />
161
+ <Banner
162
+ color="warning"
163
+ :label="t('providers.hosted.warning')"
164
+ :closable="false"
165
+ />
166
+ <Banner
167
+ v-for="(err, i) in errors"
168
+ :key="i"
169
+ color="error"
170
+ :label="err"
171
+ :closable="true"
172
+ @close="closeError(i)"
173
+ />
174
+ <ResourceTable
175
+ :schema="schema"
176
+ :resource="resource"
177
+ :rows="rows"
178
+ :headers="headers"
179
+ :row-actions="true"
180
+ :table-actions="true"
181
+ :data-testid="'hosted-provider-list'"
182
+ key-field="id"
183
+ >
184
+ <template #cell:state="{row}">
185
+ <RcStatusBadge
186
+ :status="!row.active ? 'error' : 'success'"
187
+ >
188
+ {{ stateDisplay(row) }}
189
+ </RcStatusBadge>
190
+ </template>
191
+ <template #cell:name="{row}">
192
+ <div class="col">
193
+ <div class="row">
194
+ <span class="mr-10">{{ row.name }}</span>
195
+ <RcStatusBadge
196
+ v-if="row.prime"
197
+ class="prime-badge"
198
+ status="success"
199
+ >
200
+ {{ t('providers.hosted.prime') }}
201
+ </RcStatusBadge>
202
+ </div>
203
+ <div
204
+ v-if="row.description"
205
+ class="description text-muted text-small"
206
+ >
207
+ {{ row.description }}
208
+ </div>
209
+ </div>
210
+ </template>
211
+ </ResourceTable>
212
+ </div>
213
+ </template>
214
+
215
+ <style lang="scss" scoped>
216
+ .prime-badge {
217
+ font-size: 10px;
218
+ line-height: 15px;
219
+ }
220
+ </style>
@@ -18,7 +18,7 @@ import { _EDIT, _VIEW } from '@shell/config/query-params';
18
18
  import { setFavIcon } from '@shell/utils/favicon';
19
19
  import TabTitle from '@shell/components/TabTitle';
20
20
 
21
- const Color = require('color');
21
+ import Color from 'color';
22
22
 
23
23
  export default {
24
24
  components: {
@@ -164,6 +164,13 @@ describe('page: UI plugins/Extensions', () => {
164
164
  });
165
165
 
166
166
  describe('getFooterItems', () => {
167
+ it('should return "developer" label for isDeveloper plugins', () => {
168
+ const plugin = { isDeveloper: true };
169
+ const items = wrapper.vm.getFooterItems(plugin);
170
+
171
+ expect(items[0].labels).toContain('plugins.labels.isDeveloper');
172
+ });
173
+
167
174
  it('should return "builtin" label for builtin plugins', () => {
168
175
  const plugin = { builtin: true };
169
176
  const items = wrapper.vm.getFooterItems(plugin);