@rancher/shell 3.0.12-rc.2 → 3.0.12-rc.3

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 (272) hide show
  1. package/apis/impl/apis.ts +6 -0
  2. package/apis/index.ts +26 -0
  3. package/apis/intf/resources-api/cluster-api.ts +18 -0
  4. package/apis/intf/resources-api/mgmt-api.ts +15 -0
  5. package/apis/intf/resources-api/resource-base.ts +107 -0
  6. package/apis/intf/resources-api/resource-constants.ts +147 -0
  7. package/apis/intf/resources-api/resources-api.ts +143 -0
  8. package/apis/intf/resources.ts +49 -0
  9. package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
  10. package/apis/intf/shell-api/proxy.ts +216 -0
  11. package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
  12. package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
  13. package/apis/intf/shell.ts +12 -6
  14. package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
  15. package/apis/resources/index.ts +22 -0
  16. package/apis/resources/resources-api-class.ts +187 -0
  17. package/apis/shell/__tests__/proxy.test.ts +369 -0
  18. package/apis/shell/index.ts +8 -1
  19. package/apis/shell/modal.ts +4 -1
  20. package/apis/shell/notifications.ts +9 -6
  21. package/apis/shell/proxy.ts +256 -0
  22. package/apis/shell/slide-in.ts +4 -1
  23. package/apis/vue-shim.d.ts +2 -1
  24. package/assets/data/aws-regions.json +4 -0
  25. package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
  26. package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
  27. package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
  28. package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
  29. package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
  30. package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
  31. package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
  32. package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
  33. package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
  34. package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
  35. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
  36. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
  37. package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
  38. package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
  39. package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
  40. package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
  41. package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
  42. package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
  43. package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
  44. package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
  45. package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
  46. package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
  47. package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
  48. package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
  49. package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
  50. package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
  51. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
  52. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
  53. package/assets/styles/base/_variables.scss +2 -0
  54. package/assets/styles/fonts/_fontstack.scss +132 -8
  55. package/assets/translations/en-us.yaml +22 -5
  56. package/chart/monitoring/index.vue +10 -1
  57. package/components/ActionDropdownShell.vue +2 -1
  58. package/components/CruResourceFooter.vue +9 -5
  59. package/components/ExplorerProjectsNamespaces.vue +1 -1
  60. package/components/InstallHelmCharts.vue +2 -2
  61. package/components/LandingPagePreference.vue +14 -5
  62. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
  63. package/components/Resource/Detail/Metadata/index.vue +6 -0
  64. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  65. package/components/Resource/Detail/SpacedRow.vue +3 -1
  66. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  67. package/components/ResourceList/Masthead.vue +12 -8
  68. package/components/SelectIconGrid.vue +0 -10
  69. package/components/SingleClusterInfo.vue +1 -0
  70. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  71. package/components/SortableTable/index.vue +6 -9
  72. package/components/SortableTable/selection.js +23 -5
  73. package/components/SortableTable/sorting.js +6 -3
  74. package/components/Wizard.vue +14 -13
  75. package/components/fleet/FleetBundles.vue +100 -12
  76. package/components/fleet/FleetClusterTargets/index.vue +37 -15
  77. package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
  78. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  79. package/components/form/LabeledSelect.vue +20 -3
  80. package/components/form/NameNsDescription.vue +11 -0
  81. package/components/form/Security.vue +6 -2
  82. package/components/form/WorkloadPorts.vue +2 -7
  83. package/components/form/__tests__/Security.test.ts +76 -0
  84. package/components/formatter/Autoscaler.vue +4 -4
  85. package/components/formatter/ClusterKubeVersion.vue +27 -0
  86. package/components/formatter/ClusterLink.vue +1 -7
  87. package/components/formatter/ClusterProvider.vue +6 -10
  88. package/components/formatter/FleetSummaryGraph.vue +0 -3
  89. package/components/formatter/MachineSummaryGraph.vue +1 -1
  90. package/components/formatter/PodsUsage.vue +2 -2
  91. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  92. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  93. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  94. package/components/nav/NamespaceFilter.vue +2 -2
  95. package/components/nav/TopLevelMenu.helper.ts +15 -3
  96. package/components/nav/TopLevelMenu.vue +16 -5
  97. package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
  98. package/components/templates/home.vue +18 -0
  99. package/components/templates/plain.vue +18 -0
  100. package/components/templates/standalone.vue +17 -0
  101. package/composables/useFormValidation.ts +93 -0
  102. package/composables/useVeeValidateField.test.ts +159 -0
  103. package/composables/useVeeValidateField.ts +67 -0
  104. package/config/pagination-table-headers.js +18 -1
  105. package/config/product/manager.js +82 -21
  106. package/config/router/routes.js +6 -0
  107. package/config/table-headers.js +20 -1
  108. package/config/types.js +2 -1
  109. package/core/__tests__/plugin-products.test.ts +904 -20
  110. package/core/plugin-products-base.ts +107 -7
  111. package/core/plugin-products.ts +4 -0
  112. package/core/plugin-types.ts +111 -1
  113. package/core/plugin.ts +15 -7
  114. package/core/productDebugger.js +9 -4
  115. package/core/types-provisioning.ts +43 -30
  116. package/core/types.ts +57 -20
  117. package/detail/__tests__/pod.test.ts +41 -0
  118. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  119. package/detail/pod.vue +1 -1
  120. package/detail/provisioning.cattle.io.cluster.vue +4 -10
  121. package/edit/auth/__tests__/azuread.test.ts +217 -34
  122. package/edit/auth/azuread.vue +122 -14
  123. package/edit/auth/oidc.vue +2 -2
  124. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  125. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  126. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  127. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  128. package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
  129. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
  130. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  131. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  132. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  133. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  134. package/edit/secret/__tests__/ssh.test.ts +5 -6
  135. package/edit/secret/basic.vue +31 -0
  136. package/edit/secret/index.vue +68 -17
  137. package/edit/secret/registry.vue +38 -0
  138. package/edit/secret/ssh.vue +29 -0
  139. package/edit/secret/tls.vue +30 -0
  140. package/edit/service.vue +4 -4
  141. package/edit/workload/Upgrading.vue +3 -3
  142. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  143. package/edit/workload/mixins/workload.js +2 -1
  144. package/list/fleet.cattle.io.bundle.vue +7 -104
  145. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  146. package/list/provisioning.cattle.io.cluster.vue +262 -180
  147. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  148. package/mixins/__tests__/chart.test.ts +112 -0
  149. package/mixins/brand.js +2 -1
  150. package/mixins/chart.js +12 -8
  151. package/mixins/resource-fetch-api-pagination.js +41 -5
  152. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  153. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  154. package/models/__tests__/management.cattle.io.node.ts +6 -5
  155. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  156. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
  157. package/models/base-cluster.x-k8s.io.js +26 -0
  158. package/models/cluster.js +1 -1
  159. package/models/cluster.x-k8s.io.machine.js +4 -22
  160. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  161. package/models/cluster.x-k8s.io.machineset.js +2 -20
  162. package/models/compliance.cattle.io.clusterscan.js +130 -2
  163. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  164. package/models/fleet-application.js +3 -1
  165. package/models/management.cattle.io.cluster.js +417 -40
  166. package/models/management.cattle.io.node.js +6 -4
  167. package/models/management.cattle.io.nodepool.js +1 -1
  168. package/models/networking.k8s.io.ingress.js +12 -4
  169. package/models/provisioning.cattle.io.cluster.js +47 -330
  170. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  171. package/package.json +11 -29
  172. package/pages/__tests__/readme.test.ts +49 -0
  173. package/pages/auth/setup.vue +2 -3
  174. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
  175. package/pages/c/_cluster/apps/charts/chart.vue +60 -8
  176. package/pages/c/_cluster/apps/charts/install.vue +10 -7
  177. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  178. package/pages/c/_cluster/explorer/index.vue +5 -49
  179. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  180. package/pages/c/_cluster/istio/index.vue +21 -6
  181. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -0
  182. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +719 -2
  183. package/pages/c/_cluster/uiplugins/index.vue +203 -197
  184. package/pages/diagnostic.vue +13 -17
  185. package/pages/fail-whale.vue +18 -0
  186. package/pages/home.vue +77 -260
  187. package/pages/readme.vue +88 -0
  188. package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
  189. package/plugins/dashboard-store/actions.js +40 -18
  190. package/plugins/dashboard-store/resource-class.js +5 -2
  191. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  192. package/plugins/steve/steve-pagination-utils.ts +11 -3
  193. package/plugins/steve/subscribe.js +35 -5
  194. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
  195. package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
  196. package/rancher-components/RcButton/RcButton.test.ts +37 -1
  197. package/rancher-components/RcButton/RcButton.vue +38 -8
  198. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  199. package/store/__tests__/catalog.test.ts +115 -1
  200. package/store/__tests__/type-map.test.ts +556 -1
  201. package/store/action-menu.js +8 -3
  202. package/store/auth.js +1 -1
  203. package/store/aws.js +27 -16
  204. package/store/catalog.js +27 -3
  205. package/store/digitalocean.js +20 -38
  206. package/store/index.js +2 -0
  207. package/store/linode.js +25 -40
  208. package/store/pnap.js +1 -0
  209. package/store/type-map.js +111 -29
  210. package/tsconfig.paths.json +8 -8
  211. package/types/kube/kube-api.ts +14 -1
  212. package/types/rancher/steve.api.ts +12 -12
  213. package/types/resources/settings.d.ts +2 -1
  214. package/types/shell/index.d.ts +102 -2
  215. package/types/store/dashboard-store.types.ts +108 -11
  216. package/types/store/pagination.types.ts +6 -3
  217. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  218. package/utils/__tests__/async.test.ts +87 -0
  219. package/utils/__tests__/aws.test.ts +140 -0
  220. package/utils/__tests__/banners.test.ts +176 -0
  221. package/utils/__tests__/chart.test.ts +64 -1
  222. package/utils/__tests__/color.test.ts +226 -0
  223. package/utils/__tests__/duration.test.ts +140 -0
  224. package/utils/__tests__/fleet.test.ts +340 -0
  225. package/utils/__tests__/ingress.test.ts +553 -0
  226. package/utils/__tests__/kube.test.ts +68 -0
  227. package/utils/__tests__/namespace-filter.test.ts +109 -0
  228. package/utils/__tests__/pagination-utils.test.ts +361 -0
  229. package/utils/__tests__/parse-externalid.test.ts +137 -0
  230. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  231. package/utils/__tests__/poller-sequential.test.ts +177 -0
  232. package/utils/__tests__/poller.test.ts +170 -0
  233. package/utils/__tests__/promise.test.ts +346 -0
  234. package/utils/__tests__/settings.test.ts +140 -0
  235. package/utils/__tests__/sort-utils.test.ts +301 -0
  236. package/utils/__tests__/string-utils.test.ts +798 -0
  237. package/utils/__tests__/string.test.ts +23 -1
  238. package/utils/__tests__/style.test.ts +154 -0
  239. package/utils/__tests__/svg-filter.test.ts +184 -0
  240. package/utils/__tests__/units.test.ts +417 -0
  241. package/utils/__tests__/versions.test.ts +128 -0
  242. package/utils/__tests__/xccdf.test.ts +391 -0
  243. package/utils/chart.js +36 -0
  244. package/utils/fleet.ts +13 -3
  245. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  246. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  247. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  248. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  249. package/utils/gc/__tests__/gc.test.ts +487 -0
  250. package/utils/ingress.ts +9 -1
  251. package/utils/pagination-utils.ts +2 -1
  252. package/utils/string.js +25 -2
  253. package/utils/uiplugins.ts +5 -5
  254. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  255. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  256. package/utils/validators/__tests__/index.test.ts +481 -0
  257. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  258. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  259. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  260. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  261. package/utils/validators/__tests__/role-template.test.ts +149 -0
  262. package/utils/validators/__tests__/service.test.ts +283 -0
  263. package/utils/validators/__tests__/setting.test.js +32 -0
  264. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  265. package/utils/validators/formRules/index.ts +5 -5
  266. package/utils/validators/machine-pool.ts +1 -1
  267. package/utils/validators/setting.js +18 -3
  268. package/utils/xccdf.ts +418 -0
  269. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  270. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  271. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  272. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
@@ -256,224 +256,51 @@ export default {
256
256
  },
257
257
 
258
258
  available() {
259
- let all = this.charts.filter((c) => isUIPlugin(c));
259
+ let all = this.charts
260
+ .filter((c) => isUIPlugin(c))
261
+ .filter((c) => !uiPluginHasAnnotation(c, CATALOG_ANNOTATIONS.HIDDEN, 'true'))
262
+ .map((chart) => this.mapChartToPluginItem(chart))
263
+ .filter((c) => c.versions.length > 0);
260
264
 
261
- // Filter out hidden charts
262
- all = all.filter((c) => !uiPluginHasAnnotation(c, CATALOG_ANNOTATIONS.HIDDEN, 'true'));
263
-
264
- all = all.map((chart) => {
265
- // Label can be overridden by chart annotation
266
- const label = uiPluginAnnotation(chart, UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME) || chart.chartNameDisplay;
267
- const item = {
268
- name: chart.chartName,
269
- label,
270
- description: chart.chartDescription,
271
- id: chart.id,
272
- versions: [],
273
- installed: false,
274
- builtin: false,
275
- };
276
-
277
- item.versions = [...chart.versions];
278
- item.chart = chart;
279
- item.incompatibilityMessage = '';
280
-
281
- // Filter the versions available to install (plugins-api version and current dashboard version)
282
- item.installableVersions = item.versions.filter((version) => isSupportedChartVersion({
283
- version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
284
- }));
285
-
286
- // add prop to version object if version is compatible with the current dashboard version
287
- item.versions = item.versions.map((version) => isSupportedChartVersion({
288
- version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
289
- }, true));
290
-
291
- const latestCompatible = item.installableVersions?.[0];
292
- const latestNotCompatible = item.versions.find((version) => !version.isVersionCompatible);
293
-
294
- if (latestCompatible) {
295
- item.primeOnly = latestCompatible?.annotations?.[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true';
296
- item.experimental = latestCompatible?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true';
297
- item.certified = latestCompatible?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER;
298
-
299
- item.displayVersion = latestCompatible.version;
300
- item.displayVersionLabel = getPluginChartVersionLabel(latestCompatible);
301
- item.icon = latestCompatible.icon;
302
- item.created = latestCompatible.created;
303
- } else {
304
- item.primeOnly = uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.PRIME_ONLY, 'true');
305
- item.experimental = uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.EXPERIMENTAL, 'true');
306
- item.certified = uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.CERTIFIED, CATALOG_ANNOTATIONS._RANCHER);
307
-
308
- item.displayVersion = item.versions?.[0]?.version;
309
- item.displayVersionLabel = getPluginChartVersionLabel(item.versions?.[0]);
310
- item.icon = chart.icon || latestCompatible?.annotations?.['catalog.cattle.io/ui-icon'];
311
- item.created = item.versions?.[0]?.created;
312
- }
313
-
314
- // add message of extension card if there's a newer version of the extension, but it's not available to be installed
315
- if (latestNotCompatible && item.installableVersions.length && isChartVersionHigher(latestNotCompatible.version, item.installableVersions?.[0].version)) {
316
- switch (latestNotCompatible.versionIncompatibilityData?.type) {
317
- case EXTENSIONS_INCOMPATIBILITY_TYPES.HOST:
318
- item.incompatibilityMessage = this.t(latestNotCompatible.versionIncompatibilityData?.cardMessageKey, {
319
- version: latestNotCompatible.version, required: latestNotCompatible.versionIncompatibilityData?.required, mainHost: latestNotCompatible.versionIncompatibilityData?.mainHost
320
- }, true);
321
- break;
322
- default:
323
- item.incompatibilityMessage = this.t(latestNotCompatible.versionIncompatibilityData?.cardMessageKey, {
324
- version: latestNotCompatible.version,
325
- required: latestNotCompatible.versionIncompatibilityData?.required
326
- }, true);
327
- break;
328
- }
329
- }
330
-
331
- if (this.installing[item.id]) {
332
- item.installing = this.installing[item.id];
333
- }
334
-
335
- return item;
336
- });
337
-
338
- // Remove charts with no installable versions
339
- all = all.filter((c) => c.versions.length > 0);
340
-
341
- // Check that all of the loaded plugins are represented
342
265
  this.uiplugins.forEach((p) => {
343
- const chart = all.find((c) => c.name === p.name);
344
-
345
- if (!chart) {
346
- // A plugin is loaded, but there is no chart, so add an item so that it shows up
347
- const rancher = typeof p.metadata?.rancher === 'object' ? p.metadata.rancher : {};
348
-
349
- const label = rancher.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || p.name;
350
- const item = {
351
- name: p.name,
352
- label,
353
- description: p.metadata?.description,
354
- icon: p.metadata?.icon,
355
- id: p.id,
356
- versions: [],
357
- displayVersion: p.metadata?.version,
358
- displayVersionLabel: p.metadata?.version || '-',
359
- installed: true,
360
- installedVersion: p.metadata?.version,
361
- builtin: !!p.builtin,
362
- primeOnly: rancher?.annotations?.[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true',
363
- experimental: rancher?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true',
364
- certified: rancher?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER
365
- };
366
-
367
- // Built-in plugins can chose to be hidden - used where we implement as extensions
368
- // but don't want to shows them individually on the extensions page
369
- if (!(item.builtin && rancher[UI_PLUGIN_CHART_ANNOTATIONS.HIDDEN_BUILTIN])) {
266
+ if (!all.find((c) => c.name === p.name)) {
267
+ const item = this.buildLoadedPluginItem(p);
268
+
269
+ if (item) {
370
270
  all.push(item);
371
271
  }
372
272
  }
373
273
  });
374
274
 
375
- // Go through the CRs for the plugins and wire them into the catalog
376
- this.plugins.forEach((p) => {
377
- let chart;
378
- const app = this.apps.find((a) => a.metadata.name === p.name && a.metadata.namespace === UI_PLUGIN_NAMESPACE);
379
- const originalRepoName = app?.spec?.chart?.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME] || app?.metadata?.labels?.[CATALOG_ANNOTATIONS.CLUSTER_REPO_NAME];
380
-
381
- // Find the chart from the original repo to avoid picking a wrong chart with the same name
382
- if (originalRepoName) {
383
- chart = all.find((c) => c.name === p.name && c.chart?.repoName === originalRepoName);
384
- }
385
-
386
- // If original repo was removed, don't fall back to another repo's chart (would break Available tab)
387
- if (chart) {
388
- chart.installed = true;
389
- chart.uiplugin = p;
390
- chart.installedVersion = p.version;
391
-
392
- // Can't do this here
393
- chart.installing = this.installing[chart.id];
394
-
395
- // Check for upgrade
396
- const latestInstallableVersion = chart.installableVersions?.[0];
397
-
398
- if (latestInstallableVersion && p.version !== (latestInstallableVersion.appVersion ?? latestInstallableVersion.version)) {
399
- // Use the currently installed version's metadata to show/hide the experimental and certified labels
400
- const installedVersion = (chart.installableVersions || []).find((v) => (v.appVersion ?? v.version) === p.version);
275
+ this.plugins.forEach((p) => this.wirePluginCRToChart(p, all));
401
276
 
402
- if (installedVersion) {
403
- chart.primeOnly = installedVersion?.annotations?.[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true';
404
- chart.experimental = installedVersion?.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true';
405
- chart.certified = installedVersion?.annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER;
406
- }
277
+ this.mergePluginErrors(all);
407
278
 
408
- chart.upgrade = getPluginChartVersionLabel(latestInstallableVersion);
409
- }
410
- } else {
411
- // No chart available - original repo was removed or developer-loaded plugin
412
- const appChartMeta = app?.spec?.chart?.metadata;
413
- const appAnnotations = appChartMeta?.annotations || {};
414
- let originalRepoDisplayName = null;
415
-
416
- if (originalRepoName) {
417
- originalRepoDisplayName = this.$store.getters['i18n/withFallback'](`catalog.repo.name."${ originalRepoName }"`, null, originalRepoName);
418
- }
279
+ // Remove duplicate installed plugins - keep only ones with uiplugin (correct CR data)
280
+ const installedByName = {};
419
281
 
420
- const item = {
421
- name: p.name,
422
- label: appAnnotations[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || appChartMeta?.name || p.name,
423
- description: appChartMeta?.description || p.description || '-',
424
- icon: appChartMeta?.icon || appAnnotations['catalog.cattle.io/ui-icon'],
425
- id: `${ p.name }-${ p.version }`,
426
- versions: [],
427
- displayVersion: p.version,
428
- displayVersionLabel: p.version || '-',
429
- isDeveloper: p.isDeveloper,
430
- installed: true,
431
- installedVersion: p.version,
432
- installing: false,
433
- builtin: false,
434
- uiplugin: p,
435
- primeOnly: appAnnotations[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true',
436
- experimental: appAnnotations[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true',
437
- certified: appAnnotations[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER,
438
- originalRepoNameDisplay: originalRepoDisplayName,
439
- };
440
-
441
- all.push(item);
282
+ all.forEach((plugin) => {
283
+ if (plugin.description && plugin.description.length > MAX_DESCRIPTION_LENGTH) {
284
+ plugin.description = `${ plugin.description.substr(0, MAX_DESCRIPTION_LENGTH) } ...`;
442
285
  }
443
- });
444
-
445
- // Merge in the plugin load errors
446
- Object.keys(this.uiErrors).forEach((e) => {
447
- const chart = all.find((c) => c.name === e);
448
286
 
449
- if (chart) {
450
- const error = this.uiErrors[e];
287
+ if (plugin.installed) {
288
+ const existing = installedByName[plugin.name];
451
289
 
452
- if (error && typeof error === 'string') {
453
- chart.installedError = this.t(this.uiErrors[e]);
454
- } else {
455
- chart.installedError = '';
290
+ if (!existing || plugin.uiplugin) {
291
+ installedByName[plugin.name] = plugin;
456
292
  }
457
293
  }
458
294
  });
459
295
 
460
- // Merge in the plugin load errors from help ops
461
- Object.keys(this.errors).forEach((e) => {
462
- const chart = all.find((c) => c.id === e);
463
-
464
- if (chart) {
465
- chart.helmError = !!this.errors[e];
296
+ all = all.filter((plugin) => {
297
+ if (!plugin.installed) {
298
+ return true;
466
299
  }
467
- });
468
300
 
469
- all.forEach((plugin) => {
470
- // Clamp the lengths of the descriptions
471
- if (plugin.description && plugin.description.length > MAX_DESCRIPTION_LENGTH) {
472
- plugin.description = `${ plugin.description.substr(0, MAX_DESCRIPTION_LENGTH) } ...`;
473
- }
301
+ return installedByName[plugin.name] === plugin;
474
302
  });
475
303
 
476
- // Sort by name
477
304
  return sortBy(all, 'name', false);
478
305
  }
479
306
  },
@@ -1021,6 +848,185 @@ export default {
1021
848
  }
1022
849
 
1023
850
  return statuses;
851
+ },
852
+
853
+ extractCertificationFlags(annotations) {
854
+ return {
855
+ primeOnly: annotations?.[CATALOG_ANNOTATIONS.PRIME_ONLY] === 'true',
856
+ experimental: annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL] === 'true',
857
+ certified: annotations?.[CATALOG_ANNOTATIONS.CERTIFIED] === CATALOG_ANNOTATIONS._RANCHER,
858
+ };
859
+ },
860
+
861
+ buildIncompatibilityMessage(versionData) {
862
+ const { versionIncompatibilityData, version } = versionData;
863
+ const params = {
864
+ version,
865
+ required: versionIncompatibilityData?.required,
866
+ };
867
+
868
+ if (versionIncompatibilityData?.type === EXTENSIONS_INCOMPATIBILITY_TYPES.HOST) {
869
+ params.mainHost = versionIncompatibilityData?.mainHost;
870
+ }
871
+
872
+ return this.t(versionIncompatibilityData?.cardMessageKey, params, true);
873
+ },
874
+
875
+ mapChartToPluginItem(chart) {
876
+ const label = uiPluginAnnotation(chart, UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME) || chart.chartNameDisplay;
877
+ const item = {
878
+ name: chart.chartName,
879
+ label,
880
+ description: chart.chartDescription,
881
+ id: chart.id,
882
+ versions: [...chart.versions],
883
+ installed: false,
884
+ builtin: false,
885
+ chart,
886
+ incompatibilityMessage: '',
887
+ };
888
+
889
+ item.installableVersions = item.versions.filter((version) => isSupportedChartVersion({
890
+ version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
891
+ }));
892
+
893
+ item.versions = item.versions.map((version) => isSupportedChartVersion({
894
+ version, rancherVersion: this.rancherVersion, kubeVersion: this.kubeVersion
895
+ }, true));
896
+
897
+ const latestCompatible = item.installableVersions?.[0];
898
+ const latestNotCompatible = item.versions.find((version) => !version.isVersionCompatible);
899
+
900
+ if (latestCompatible) {
901
+ Object.assign(item, {
902
+ ...this.extractCertificationFlags(latestCompatible?.annotations),
903
+ displayVersion: latestCompatible.version,
904
+ displayVersionLabel: getPluginChartVersionLabel(latestCompatible),
905
+ icon: latestCompatible.icon,
906
+ created: latestCompatible.created,
907
+ });
908
+ } else {
909
+ Object.assign(item, {
910
+ primeOnly: uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.PRIME_ONLY, 'true'),
911
+ experimental: uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.EXPERIMENTAL, 'true'),
912
+ certified: uiPluginHasAnnotation(chart, CATALOG_ANNOTATIONS.CERTIFIED, CATALOG_ANNOTATIONS._RANCHER),
913
+ displayVersion: item.versions?.[0]?.version,
914
+ displayVersionLabel: getPluginChartVersionLabel(item.versions?.[0]),
915
+ icon: chart.icon || latestCompatible?.annotations?.['catalog.cattle.io/ui-icon'],
916
+ created: item.versions?.[0]?.created,
917
+ });
918
+ }
919
+
920
+ if (latestNotCompatible && item.installableVersions.length && isChartVersionHigher(latestNotCompatible.version, item.installableVersions?.[0].version)) {
921
+ item.incompatibilityMessage = this.buildIncompatibilityMessage(latestNotCompatible);
922
+ }
923
+
924
+ if (this.installing[item.id]) {
925
+ item.installing = this.installing[item.id];
926
+ }
927
+
928
+ return item;
929
+ },
930
+
931
+ buildLoadedPluginItem(plugin) {
932
+ const rancher = typeof plugin.metadata?.rancher === 'object' ? plugin.metadata.rancher : {};
933
+ const label = rancher.annotations?.[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || plugin.name;
934
+
935
+ if (plugin.builtin && rancher[UI_PLUGIN_CHART_ANNOTATIONS.HIDDEN_BUILTIN]) {
936
+ return null;
937
+ }
938
+
939
+ return {
940
+ name: plugin.name,
941
+ label,
942
+ description: plugin.metadata?.description,
943
+ icon: plugin.metadata?.icon,
944
+ id: plugin.id,
945
+ versions: [],
946
+ displayVersion: plugin.metadata?.version,
947
+ displayVersionLabel: plugin.metadata?.version || '-',
948
+ installed: true,
949
+ installedVersion: plugin.metadata?.version,
950
+ builtin: !!plugin.builtin,
951
+ ...this.extractCertificationFlags(rancher?.annotations),
952
+ };
953
+ },
954
+
955
+ wirePluginCRToChart(pluginCR, all) {
956
+ const app = this.apps.find((a) => a.metadata.name === pluginCR.name && a.metadata.namespace === UI_PLUGIN_NAMESPACE);
957
+ const originalRepoName = app?.spec?.chart?.metadata?.annotations?.[CATALOG_ANNOTATIONS.SOURCE_REPO_NAME] || app?.metadata?.labels?.[CATALOG_ANNOTATIONS.CLUSTER_REPO_NAME];
958
+
959
+ let chart;
960
+
961
+ if (originalRepoName) {
962
+ chart = all.find((c) => c.name === pluginCR.name && c.chart?.repoName === originalRepoName);
963
+ }
964
+
965
+ if (chart) {
966
+ chart.installed = true;
967
+ chart.uiplugin = pluginCR;
968
+ chart.installedVersion = pluginCR.version;
969
+ chart.installing = this.installing[chart.id];
970
+
971
+ const latestInstallableVersion = chart.installableVersions?.[0];
972
+
973
+ if (latestInstallableVersion && pluginCR.version !== (latestInstallableVersion.appVersion ?? latestInstallableVersion.version)) {
974
+ const installedVersion = (chart.installableVersions || []).find((v) => (v.appVersion ?? v.version) === pluginCR.version);
975
+
976
+ if (installedVersion) {
977
+ Object.assign(chart, this.extractCertificationFlags(installedVersion?.annotations));
978
+ }
979
+
980
+ chart.upgrade = getPluginChartVersionLabel(latestInstallableVersion);
981
+ }
982
+ } else {
983
+ const appChartMeta = app?.spec?.chart?.metadata;
984
+ const appAnnotations = appChartMeta?.annotations || {};
985
+ let originalRepoDisplayName = null;
986
+
987
+ if (originalRepoName) {
988
+ originalRepoDisplayName = this.$store.getters['i18n/withFallback'](`catalog.repo.name."${ originalRepoName }"`, null, originalRepoName);
989
+ }
990
+
991
+ all.push({
992
+ name: pluginCR.name,
993
+ label: appAnnotations[UI_PLUGIN_CHART_ANNOTATIONS.DISPLAY_NAME] || appChartMeta?.name || pluginCR.name,
994
+ description: appChartMeta?.description || pluginCR.description || '-',
995
+ icon: appChartMeta?.icon || appAnnotations['catalog.cattle.io/ui-icon'],
996
+ id: `${ pluginCR.name }-${ pluginCR.version }`,
997
+ versions: [],
998
+ displayVersion: pluginCR.version,
999
+ displayVersionLabel: pluginCR.version || '-',
1000
+ isDeveloper: pluginCR.isDeveloper,
1001
+ installed: true,
1002
+ installedVersion: pluginCR.version,
1003
+ installing: false,
1004
+ builtin: false,
1005
+ uiplugin: pluginCR,
1006
+ originalRepoNameDisplay: originalRepoDisplayName,
1007
+ ...this.extractCertificationFlags(appAnnotations),
1008
+ });
1009
+ }
1010
+ },
1011
+
1012
+ mergePluginErrors(all) {
1013
+ Object.keys(this.uiErrors).forEach((errorName) => {
1014
+ const chart = all.find((c) => c.name === errorName);
1015
+
1016
+ if (chart) {
1017
+ const error = this.uiErrors[errorName];
1018
+
1019
+ chart.installedError = (error && typeof error === 'string') ? this.t(error) : '';
1020
+ }
1021
+ });
1022
+
1023
+ Object.keys(this.errors).forEach((errorId) => {
1024
+ const chart = all.find((c) => c.id === errorId);
1025
+
1026
+ if (chart) {
1027
+ chart.helmError = !!this.errors[errorId];
1028
+ }
1029
+ });
1024
1030
  }
1025
1031
  }
1026
1032
  };
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { CAPI, MANAGEMENT } from '@shell/config/types';
2
+ import { MANAGEMENT } from '@shell/config/types';
3
3
  import AsyncButton from '@shell/components/AsyncButton';
4
4
  import { downloadFile } from '@shell/utils/download';
5
5
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
@@ -12,28 +12,25 @@ export default {
12
12
  components: { AsyncButton },
13
13
 
14
14
  async fetch() {
15
- const provClusters = await this.$store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER });
16
- const readyClusters = provClusters.filter((c) => c.mgmt?.isReady);
17
- const clusterForCounts = filterHiddenLocalCluster(filterOnlyKubernetesClusters(readyClusters, this.$store), this.$store);
15
+ // Diagnostics does not scale with resources (this will be real heavy for rancher's with 1000s of clusters)
16
+ const mgmtClusters = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER });
17
+ const readyMgmtClusters = mgmtClusters.filter((c) => c.isReady);
18
+ const clusterForCounts = filterHiddenLocalCluster(filterOnlyKubernetesClusters(readyMgmtClusters, this.$store), this.$store);
18
19
  const finalCounts = [];
19
20
  const promises = [];
20
21
  const topFifteenForResponseTime = [];
21
22
  const schemaPromises = [];
22
23
 
23
- clusterForCounts.forEach((cluster, i) => {
24
- // Necessary to retrieve the proper display name of the cluster
25
- const mgmtCluster = this.$store.getters['management/byId'](MANAGEMENT.CLUSTER, cluster.metadata.name);
26
-
24
+ clusterForCounts.forEach((mgmtCluster, i) => {
27
25
  finalCounts.push({
28
- id: cluster.id,
29
- name: mgmtCluster?.spec?.displayName || cluster.metadata?.name,
30
- namespace: cluster.metadata?.namespace,
31
- capiId: cluster.mgmt?.id,
26
+ id: mgmtCluster.id,
27
+ name: mgmtCluster.spec.displayName || mgmtCluster.metadata?.name,
28
+ namespace: mgmtCluster.provClusterNamespace,
32
29
  counts: null,
33
30
  isTableVisible: !!(i === 0 && clusterForCounts.length === 1)
34
31
  });
35
- promises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ cluster.mgmt?.id }/v1/counts` }));
36
- schemaPromises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ cluster.mgmt?.id }/v1/schemas?exclude=metadata.managedFields` }));
32
+ promises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ mgmtCluster.id }/v1/counts` }));
33
+ schemaPromises.push(this.$store.dispatch('management/request', { url: `/k8s/clusters/${ mgmtCluster.id }/v1/schemas?exclude=metadata.managedFields` }));
37
34
  });
38
35
 
39
36
  const countsPerCluster = await Promise.all(promises);
@@ -62,7 +59,6 @@ export default {
62
59
 
63
60
  finalCount.forEach((item, i) => {
64
61
  finalCount[i].id = finalCounts[index].id;
65
- finalCount[i].capiId = finalCounts[index].capiId;
66
62
  });
67
63
 
68
64
  topFifteenForResponseTime.push(finalCount);
@@ -187,7 +183,7 @@ export default {
187
183
  setResourceResponseTiming(responseTimes) {
188
184
  responseTimes?.forEach((res) => {
189
185
  if ( res.outcome === 'success' ) {
190
- const cluster = this.finalCounts.find((c) => c.capiId === res.item.capiId);
186
+ const cluster = this.finalCounts.find((c) => c.id === res.item.id);
191
187
  const countIndex = cluster?.counts?.findIndex((c) => c.resource === res.item.resource);
192
188
 
193
189
  if ( (countIndex && countIndex !== -1) || countIndex === 0 ) {
@@ -218,7 +214,7 @@ export default {
218
214
  return cluster.map((item) => {
219
215
  const t = Date.now();
220
216
 
221
- return this.$store.dispatch('management/request', { url: `/k8s/clusters/${ item.capiId }/v1/${ item.resource }` })
217
+ return this.$store.dispatch('management/request', { url: `/k8s/clusters/${ item.id }/v1/${ item.resource }` })
222
218
  .then(() => ({
223
219
  outcome: 'success', item, durationMs: Date.now() - t
224
220
  }))
@@ -61,6 +61,10 @@ export default {
61
61
 
62
62
  <template>
63
63
  <div class="dashboard-root">
64
+ <a
65
+ href="#main-content"
66
+ class="skip-to-content btn role-primary"
67
+ >{{ t('nav.skipToContent') }}</a>
64
68
  <FixedBanner :header="true" />
65
69
  <PromptModal />
66
70
  <div
@@ -73,8 +77,10 @@ export default {
73
77
  />
74
78
 
75
79
  <main
80
+ id="main-content"
76
81
  class="main-layout"
77
82
  aria-label="Fail whale layout"
83
+ tabindex="-1"
78
84
  >
79
85
  <div
80
86
  v-if="error"
@@ -200,4 +206,16 @@ export default {
200
206
  padding: 0;
201
207
  }
202
208
  }
209
+
210
+ .skip-to-content {
211
+ position: fixed;
212
+ top: 0;
213
+ left: 0;
214
+ z-index: 9999;
215
+ transform: translateY(-100%);
216
+
217
+ &:focus {
218
+ transform: translate(1rem, 1rem);
219
+ }
220
+ }
203
221
  </style>