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

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 (473) 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/styles/global/_layout.scss +4 -0
  56. package/assets/translations/en-us.yaml +165 -45
  57. package/assets/translations/zh-hans.yaml +1 -7
  58. package/chart/monitoring/ClusterSelector.vue +0 -21
  59. package/chart/monitoring/index.vue +10 -1
  60. package/chart/monitoring/prometheus/index.vue +6 -3
  61. package/components/ActionDropdownShell.vue +2 -1
  62. package/components/CruResource.vue +161 -14
  63. package/components/CruResourceFooter.vue +9 -5
  64. package/components/ExplorerMembers.vue +8 -4
  65. package/components/ExplorerProjectsNamespaces.vue +11 -7
  66. package/components/GrowlManager.vue +4 -0
  67. package/components/InstallHelmCharts.vue +2 -2
  68. package/components/LandingPagePreference.vue +14 -5
  69. package/components/MgmtNodeList.vue +184 -0
  70. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  71. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  72. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  73. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  74. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +17 -1
  75. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  76. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  77. package/components/Resource/Detail/Metadata/index.vue +6 -0
  78. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  79. package/components/Resource/Detail/SpacedRow.vue +3 -1
  80. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  81. package/components/ResourceDetail/index.vue +1 -1
  82. package/components/ResourceList/Masthead.vue +19 -9
  83. package/components/ResourceList/index.vue +82 -1
  84. package/components/RichTranslation.vue +5 -2
  85. package/components/SelectIconGrid.vue +0 -10
  86. package/components/Setting.vue +1 -0
  87. package/components/SingleClusterInfo.vue +1 -0
  88. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  89. package/components/SortableTable/index.vue +6 -9
  90. package/components/SortableTable/selection.js +23 -5
  91. package/components/SortableTable/sorting.js +6 -3
  92. package/components/SubtleLink.vue +31 -6
  93. package/components/Tabbed/Tab.vue +29 -3
  94. package/components/Tabbed/index.vue +25 -3
  95. package/components/TableOfContents/TableOfContents.vue +109 -0
  96. package/components/TableOfContents/composables.ts +258 -0
  97. package/components/Window/ContainerShell.vue +21 -11
  98. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  99. package/components/Wizard.vue +23 -17
  100. package/components/fleet/AppCoChartGrid.vue +401 -0
  101. package/components/fleet/AppCoEmptyState.vue +127 -0
  102. package/components/fleet/AppCoPageHeader.vue +119 -0
  103. package/components/fleet/AppCoVersionSelect.vue +70 -0
  104. package/components/fleet/FleetBundles.vue +100 -12
  105. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  106. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  107. package/components/fleet/FleetClusterTargets/index.vue +226 -161
  108. package/components/fleet/FleetIntro.vue +7 -3
  109. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  110. package/components/fleet/FleetSecretSelector.vue +5 -3
  111. package/components/fleet/FleetValuesFrom.vue +8 -2
  112. package/components/fleet/GitRepoTargetTab.vue +0 -2
  113. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  114. package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
  115. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  116. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  117. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  118. package/components/fleet/HelmOpTargetTab.vue +64 -60
  119. package/components/fleet/HelmOpValuesTab.vue +129 -105
  120. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  121. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  122. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  123. package/components/fleet/__tests__/FleetClusterTargets.test.ts +402 -115
  124. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  125. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  126. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  127. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  128. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  129. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  130. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  131. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  132. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  133. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  134. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  135. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  136. package/components/fleet/dashboard/Empty.vue +8 -4
  137. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  138. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  139. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  140. package/components/form/ArrayList.vue +61 -4
  141. package/components/form/KeyValue.vue +23 -2
  142. package/components/form/LabeledSelect.vue +59 -4
  143. package/components/form/Labels.vue +22 -3
  144. package/components/form/NameNsDescription.vue +24 -5
  145. package/components/form/ResourceTabs/index.vue +1 -0
  146. package/components/form/Security.vue +6 -2
  147. package/components/form/WorkloadPorts.vue +2 -7
  148. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  149. package/components/form/__tests__/Security.test.ts +76 -0
  150. package/components/formatter/Autoscaler.vue +4 -4
  151. package/components/formatter/ClusterKubeVersion.vue +27 -0
  152. package/components/formatter/ClusterLink.vue +1 -7
  153. package/components/formatter/ClusterProvider.vue +6 -10
  154. package/components/formatter/FleetSummaryGraph.vue +0 -3
  155. package/components/formatter/InternalExternalIP.vue +10 -4
  156. package/components/formatter/MachineSummaryGraph.vue +1 -1
  157. package/components/formatter/PodsUsage.vue +2 -2
  158. package/components/formatter/ServiceTargets.vue +26 -7
  159. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  160. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  161. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  162. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  163. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  164. package/components/nav/Header.vue +4 -0
  165. package/components/nav/NamespaceFilter.vue +2 -2
  166. package/components/nav/TopLevelMenu.helper.ts +15 -3
  167. package/components/nav/TopLevelMenu.vue +22 -6
  168. package/components/nav/__tests__/Header.test.ts +15 -0
  169. package/components/nav/__tests__/TopLevelMenu.test.ts +263 -21
  170. package/components/templates/default.vue +9 -4
  171. package/components/templates/home.vue +23 -0
  172. package/components/templates/plain.vue +23 -0
  173. package/components/templates/standalone.vue +17 -0
  174. package/composables/useFormValidation.ts +93 -0
  175. package/composables/useHelmOpResources.test.ts +56 -0
  176. package/composables/useHelmOpResources.ts +32 -0
  177. package/composables/useStateColor.test.ts +325 -0
  178. package/composables/useStateColor.ts +128 -0
  179. package/composables/useVeeValidateField.test.ts +159 -0
  180. package/composables/useVeeValidateField.ts +67 -0
  181. package/config/home-links.js +1 -1
  182. package/config/labels-annotations.js +1 -0
  183. package/config/pagination-table-headers.js +18 -1
  184. package/config/product/explorer.js +17 -4
  185. package/config/product/manager.js +84 -21
  186. package/config/router/index.js +16 -0
  187. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  188. package/config/router/navigation-guards/authentication.js +10 -4
  189. package/config/router/routes.js +26 -6
  190. package/config/settings.ts +0 -2
  191. package/config/table-headers.js +23 -5
  192. package/config/types.js +11 -1
  193. package/core/__tests__/plugin-products.test.ts +904 -20
  194. package/core/plugin-products-base.ts +110 -10
  195. package/core/plugin-products.ts +4 -0
  196. package/core/plugin-types.ts +194 -31
  197. package/core/plugin.ts +18 -7
  198. package/core/productDebugger.js +9 -4
  199. package/core/types-provisioning.ts +77 -31
  200. package/core/types.ts +72 -22
  201. package/detail/__tests__/pod.test.ts +41 -0
  202. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  203. package/detail/__tests__/workload.test.ts +3 -152
  204. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  205. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  206. package/detail/pod.vue +1 -1
  207. package/detail/provisioning.cattle.io.cluster.vue +34 -14
  208. package/detail/workload/index.vue +12 -55
  209. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  210. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
  211. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  212. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  213. package/edit/auth/__tests__/azuread.test.ts +247 -39
  214. package/edit/auth/__tests__/github.test.ts +234 -0
  215. package/edit/auth/__tests__/oidc.test.ts +26 -6
  216. package/edit/auth/__tests__/saml.test.ts +196 -0
  217. package/edit/auth/azuread.vue +197 -56
  218. package/edit/auth/github.vue +72 -13
  219. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  220. package/edit/auth/ldap/config.vue +8 -0
  221. package/edit/auth/ldap/index.vue +75 -1
  222. package/edit/auth/oidc.vue +119 -73
  223. package/edit/auth/saml.vue +76 -12
  224. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  225. package/edit/fleet.cattle.io.helmop.vue +491 -136
  226. package/edit/management.cattle.io.user.vue +5 -2
  227. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  228. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  229. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  230. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  231. package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
  232. package/edit/provisioning.cattle.io.cluster/rke2.vue +92 -14
  233. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +22 -0
  234. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  235. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  236. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  237. package/edit/secret/__tests__/ssh.test.ts +5 -6
  238. package/edit/secret/basic.vue +31 -0
  239. package/edit/secret/index.vue +68 -17
  240. package/edit/secret/registry.vue +38 -0
  241. package/edit/secret/ssh.vue +29 -0
  242. package/edit/secret/tls.vue +30 -0
  243. package/edit/service.vue +4 -4
  244. package/edit/workload/Upgrading.vue +3 -3
  245. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  246. package/edit/workload/mixins/workload.js +2 -1
  247. package/list/fleet.cattle.io.bundle.vue +7 -104
  248. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  249. package/list/group.principal.vue +5 -4
  250. package/list/harvesterhci.io.management.cluster.vue +8 -9
  251. package/list/management.cattle.io.user.vue +12 -9
  252. package/list/provisioning.cattle.io.cluster.vue +268 -180
  253. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  254. package/mixins/__tests__/auth-config.test.ts +90 -0
  255. package/mixins/__tests__/chart.test.ts +206 -0
  256. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  257. package/mixins/auth-config.js +7 -0
  258. package/mixins/brand.js +2 -1
  259. package/mixins/chart.js +22 -9
  260. package/mixins/child-hook.js +12 -6
  261. package/mixins/create-edit-view/impl.js +5 -3
  262. package/mixins/resource-fetch-api-pagination.js +62 -6
  263. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  264. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  265. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  266. package/models/__tests__/fleet-application.test.ts +175 -0
  267. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  268. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  269. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  270. package/models/__tests__/management.cattle.io.node.ts +28 -5
  271. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  272. package/models/__tests__/namespace.test.ts +36 -0
  273. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +81 -11
  274. package/models/__tests__/workload.test.ts +401 -26
  275. package/models/base-cluster.x-k8s.io.js +26 -0
  276. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  277. package/models/cluster.js +1 -1
  278. package/models/cluster.x-k8s.io.machine.js +4 -22
  279. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  280. package/models/cluster.x-k8s.io.machineset.js +2 -20
  281. package/models/compliance.cattle.io.clusterscan.js +165 -2
  282. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  283. package/models/fleet-application.js +7 -1
  284. package/models/fleet.cattle.io.helmop.js +20 -1
  285. package/models/management.cattle.io.cluster.js +434 -41
  286. package/models/management.cattle.io.node.js +50 -7
  287. package/models/management.cattle.io.nodepool.js +1 -1
  288. package/models/namespace.js +1 -1
  289. package/models/networking.k8s.io.ingress.js +12 -4
  290. package/models/pod.js +33 -1
  291. package/models/provisioning.cattle.io.cluster.js +51 -334
  292. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  293. package/models/workload.js +108 -13
  294. package/models/workload.service.js +5 -0
  295. package/package.json +22 -39
  296. package/pages/__tests__/readme.test.ts +49 -0
  297. package/pages/about.vue +5 -6
  298. package/pages/auth/login.vue +0 -35
  299. package/pages/auth/setup.vue +13 -3
  300. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  301. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  302. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
  303. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  304. package/pages/c/_cluster/apps/charts/chart.vue +62 -9
  305. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  306. package/pages/c/_cluster/apps/charts/install.vue +122 -113
  307. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  308. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  309. package/pages/c/_cluster/explorer/index.vue +5 -49
  310. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  311. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  312. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  313. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  314. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  315. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  316. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  317. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  318. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  319. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  320. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  321. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  322. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  323. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  324. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  325. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  326. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  327. package/pages/c/_cluster/fleet/index.vue +2 -2
  328. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  329. package/pages/c/_cluster/istio/index.vue +21 -6
  330. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -0
  331. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +815 -2
  332. package/pages/c/_cluster/uiplugins/index.vue +218 -197
  333. package/pages/diagnostic.vue +13 -17
  334. package/pages/fail-whale.vue +30 -7
  335. package/pages/home.vue +93 -306
  336. package/pages/readme.vue +88 -0
  337. package/plugins/clean-html.d.ts +9 -0
  338. package/plugins/dashboard-store/__tests__/resource-class.test.ts +181 -0
  339. package/plugins/dashboard-store/actions.js +40 -18
  340. package/plugins/dashboard-store/resource-class.js +67 -9
  341. package/plugins/steve/__tests__/actions.test.ts +212 -0
  342. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  343. package/plugins/steve/actions.js +96 -0
  344. package/plugins/steve/steve-pagination-utils.ts +12 -4
  345. package/plugins/steve/subscribe.js +35 -5
  346. package/rancher-components/Accordion/Accordion.vue +53 -9
  347. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  348. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
  349. package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
  350. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  351. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  352. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  353. package/rancher-components/RcButton/RcButton.test.ts +140 -1
  354. package/rancher-components/RcButton/RcButton.vue +126 -17
  355. package/rancher-components/RcButton/types.ts +3 -0
  356. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  357. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  358. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  359. package/rancher-components/RcSection/RcSection.vue +28 -3
  360. package/scripts/extension/helm/package/Dockerfile +1 -1
  361. package/scripts/test-plugins-build.sh +2 -1
  362. package/store/__tests__/catalog.test.ts +115 -1
  363. package/store/__tests__/notifications.test.ts +434 -0
  364. package/store/__tests__/type-map.test.ts +556 -1
  365. package/store/action-menu.js +8 -3
  366. package/store/auth.js +1 -1
  367. package/store/aws.js +27 -16
  368. package/store/catalog.js +84 -3
  369. package/store/digitalocean.js +20 -38
  370. package/store/index.js +2 -0
  371. package/store/linode.js +25 -40
  372. package/store/plugins.js +7 -4
  373. package/store/pnap.js +1 -0
  374. package/store/type-map.js +111 -29
  375. package/tsconfig.paths.json +8 -8
  376. package/types/components/buttonGroup.ts +5 -0
  377. package/types/kube/kube-api.ts +14 -1
  378. package/types/rancher/steve.api.ts +12 -12
  379. package/types/resources/settings.d.ts +2 -1
  380. package/types/shell/index.d.ts +206 -72
  381. package/types/store/dashboard-store.types.ts +108 -11
  382. package/types/store/pagination.types.ts +6 -3
  383. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  384. package/utils/__tests__/async.test.ts +87 -0
  385. package/utils/__tests__/auth.test.ts +273 -0
  386. package/utils/__tests__/aws.test.ts +140 -0
  387. package/utils/__tests__/banners.test.ts +176 -0
  388. package/utils/__tests__/chart.test.ts +64 -1
  389. package/utils/__tests__/color.test.ts +226 -0
  390. package/utils/__tests__/computed.test.ts +193 -0
  391. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  392. package/utils/__tests__/dom.test.ts +81 -0
  393. package/utils/__tests__/duration.test.ts +176 -0
  394. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  395. package/utils/__tests__/fleet-appco.test.ts +312 -0
  396. package/utils/__tests__/fleet.test.ts +340 -0
  397. package/utils/__tests__/ingress.test.ts +553 -0
  398. package/utils/__tests__/kube.test.ts +68 -0
  399. package/utils/__tests__/monitoring.test.ts +130 -0
  400. package/utils/__tests__/namespace-filter.test.ts +109 -0
  401. package/utils/__tests__/object.test.ts +22 -0
  402. package/utils/__tests__/pagination-utils.test.ts +361 -0
  403. package/utils/__tests__/parse-externalid.test.ts +137 -0
  404. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  405. package/utils/__tests__/platform.test.ts +91 -0
  406. package/utils/__tests__/poller-sequential.test.ts +177 -0
  407. package/utils/__tests__/poller.test.ts +170 -0
  408. package/utils/__tests__/position.test.ts +237 -0
  409. package/utils/__tests__/promise.test.ts +346 -0
  410. package/utils/__tests__/provider.test.ts +51 -1
  411. package/utils/__tests__/queue.test.ts +232 -0
  412. package/utils/__tests__/release-notes.test.ts +221 -0
  413. package/utils/__tests__/router.test.js +254 -1
  414. package/utils/__tests__/select.test.ts +208 -0
  415. package/utils/__tests__/settings.test.ts +140 -0
  416. package/utils/__tests__/sort-utils.test.ts +301 -0
  417. package/utils/__tests__/string-utils.test.ts +798 -0
  418. package/utils/__tests__/string.test.ts +23 -1
  419. package/utils/__tests__/style.test.ts +154 -0
  420. package/utils/__tests__/svg-filter.test.ts +184 -0
  421. package/utils/__tests__/time.test.ts +265 -1
  422. package/utils/__tests__/title.test.ts +47 -0
  423. package/utils/__tests__/units.test.ts +417 -0
  424. package/utils/__tests__/versions.test.ts +128 -0
  425. package/utils/__tests__/width.test.ts +53 -0
  426. package/utils/__tests__/window.test.ts +158 -0
  427. package/utils/__tests__/xccdf.test.ts +511 -0
  428. package/utils/chart.js +36 -0
  429. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  430. package/utils/crypto/__tests__/index.test.ts +144 -0
  431. package/utils/duration.ts +104 -0
  432. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  433. package/utils/dynamic-content/info.ts +2 -1
  434. package/utils/error.js +13 -0
  435. package/utils/fleet-appco.ts +323 -0
  436. package/utils/fleet.ts +13 -3
  437. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  438. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  439. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  440. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  441. package/utils/gc/__tests__/gc.test.ts +487 -0
  442. package/utils/ingress.ts +9 -1
  443. package/utils/object.js +22 -2
  444. package/utils/pagination-utils.ts +2 -1
  445. package/utils/provider.ts +12 -0
  446. package/utils/string.js +25 -2
  447. package/utils/uiplugins.ts +5 -5
  448. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  449. package/utils/validators/__tests__/container-images.test.ts +104 -0
  450. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  451. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  452. package/utils/validators/__tests__/index.test.ts +481 -0
  453. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  454. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  455. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  456. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  457. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  458. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  459. package/utils/validators/__tests__/role-template.test.ts +149 -0
  460. package/utils/validators/__tests__/service.test.ts +283 -0
  461. package/utils/validators/__tests__/setting.test.js +32 -0
  462. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  463. package/utils/validators/formRules/index.ts +5 -5
  464. package/utils/validators/machine-pool.ts +1 -1
  465. package/utils/validators/setting.js +18 -3
  466. package/utils/xccdf.ts +415 -0
  467. package/vue.config.js +1 -1
  468. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  469. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  470. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  471. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
  472. package/pages/support/index.vue +0 -264
  473. package/utils/duration.js +0 -43
@@ -0,0 +1,440 @@
1
+ import {
2
+ ref, computed, watch, onMounted, onBeforeUnmount
3
+ } from 'vue';
4
+ import { useStore } from 'vuex';
5
+ import { useRouter, type RouteLocationRaw } from 'vue-router';
6
+ import { NAMESPACE } from '@shell/config/types';
7
+ import type { StateColor } from '@shell/utils/style';
8
+ import { useI18n } from '@shell/composables/useI18n';
9
+ import { useStateColor } from '@shell/composables/useStateColor';
10
+ import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
11
+ import { ALL_NAMESPACES } from '@shell/store/prefs';
12
+ import {
13
+ NAMESPACE_FILTER_ALL_USER,
14
+ NAMESPACE_FILTER_ALL_SYSTEM,
15
+ NAMESPACE_FILTER_P_FULL_PREFIX,
16
+ NAMESPACE_FILTER_NS_FULL_PREFIX,
17
+ } from '@shell/utils/namespace-filter';
18
+ import stevePaginationUtils from '@shell/plugins/steve/steve-pagination-utils';
19
+ import {
20
+ WORKLOAD_RESOURCE_TYPES, COLOR_ORDER,
21
+ type WorkloadDashboardSummaryEntry,
22
+ type WorkloadDashboardEntry,
23
+ type WorkloadDashboardStateCard,
24
+ type WorkloadDashboardByStateLayout,
25
+ type WorkloadDashboardByTypeCard,
26
+ type WorkloadDashboardByNamespaceCard,
27
+ } from './types';
28
+
29
+ export function useWorkloadDashboard() {
30
+ const store = useStore();
31
+ const router = useRouter();
32
+ const { t } = useI18n(store);
33
+ const { toStateColor, resolveStateColors } = useStateColor();
34
+
35
+ const summaries = ref<WorkloadDashboardSummaryEntry[]>([]);
36
+ const fetchError = ref<string | null>(null);
37
+ const loading = ref(true);
38
+ let pollTimer: ReturnType<typeof setInterval> | null = null;
39
+
40
+ const clusterId = computed<string>(() => store.getters['clusterId']);
41
+
42
+ // ── Namespace filtering ──
43
+
44
+ const isAllNamespaces = computed<boolean>(() => store.getters['isAllNamespaces']);
45
+
46
+ const namespaceFilterParam = ref('');
47
+
48
+ function buildNamespaceFilterParam(): string {
49
+ const selection: string[] = store.getters['namespaceFilters'];
50
+ const { projectsOrNamespaces, filters } = stevePaginationUtils.createParamsFromNsFilter({
51
+ allNamespaces: store.getters['cluster/all'](NAMESPACE),
52
+ selection,
53
+ isAllNamespaces: isAllNamespaces.value,
54
+ isLocalCluster: store.getters['currentCluster']?.isLocal,
55
+ showReservedRancherNamespaces: store.getters['prefs/get'](ALL_NAMESPACES),
56
+ productHidesSystemNamespaces: store.getters['currentProduct']?.hideSystemResources,
57
+ });
58
+
59
+ // Getting the first schema is sufficient since the namespace filter param structure is the same across all resource types
60
+ const schema = WORKLOAD_RESOURCE_TYPES
61
+ .map((type) => store.getters['cluster/schemaFor'](type))
62
+ .find((s) => !!s);
63
+
64
+ // To generate proper params path to be used
65
+ const path = stevePaginationUtils.createParamsForPagination({
66
+ schema,
67
+ opt: {
68
+ pagination: {
69
+ filters,
70
+ projectsOrNamespaces,
71
+ page: 1,
72
+ sort: [],
73
+ }
74
+ }
75
+ }) || '';
76
+
77
+ return path.replace(/page=\d+&?/g, '').replace(/pagesize=\d+&?/g, '').replace(/&$/, '');
78
+ }
79
+
80
+ watch(() => store.getters['namespaceFilters'], () => {
81
+ namespaceFilterParam.value = buildNamespaceFilterParam();
82
+ }, { immediate: true });
83
+
84
+ // ── Subtitle ──
85
+
86
+ const totalWorkloads = computed<number>(() => {
87
+ return workloadData.value.reduce((sum, w) => sum + (w.error ? 0 : w.total), 0);
88
+ });
89
+
90
+ const namespaceSubtitle = computed<string>(() => {
91
+ const count = totalWorkloads.value;
92
+ const countSuffix = t('workloadDashboard.workloadCount', { count });
93
+ const filters: string[] = store.getters['namespaceFilters'];
94
+
95
+ if (isAllNamespaces.value) {
96
+ return `${ t('workloadDashboard.subtitle.allNamespaces') } ${ countSuffix }`;
97
+ }
98
+
99
+ if (filters.length === 1) {
100
+ const filter = filters[0];
101
+
102
+ if (filter === NAMESPACE_FILTER_ALL_USER) {
103
+ return `${ t('workloadDashboard.subtitle.userNamespaces') } ${ countSuffix }`;
104
+ }
105
+
106
+ if (filter === NAMESPACE_FILTER_ALL_SYSTEM) {
107
+ return `${ t('workloadDashboard.subtitle.systemNamespaces') } ${ countSuffix }`;
108
+ }
109
+
110
+ if (filter.startsWith(NAMESPACE_FILTER_P_FULL_PREFIX)) {
111
+ const projectId = filter.replace(NAMESPACE_FILTER_P_FULL_PREFIX, '');
112
+ const projects = store.getters['management/all']('management.cattle.io.project');
113
+ const project = projects.find((p: { id?: string; nameDisplay?: string; metadata?: { name: string } }) => p.id?.endsWith(`/${ projectId }`) || p.metadata?.name === projectId);
114
+
115
+ return `${ t('workloadDashboard.subtitle.project', { name: project?.nameDisplay || projectId }) } ${ countSuffix }`;
116
+ }
117
+
118
+ if (filter.startsWith(NAMESPACE_FILTER_NS_FULL_PREFIX)) {
119
+ const name = filter.replace(NAMESPACE_FILTER_NS_FULL_PREFIX, '');
120
+
121
+ return `${ t('workloadDashboard.subtitle.namespace', { name }) } ${ countSuffix }`;
122
+ }
123
+ }
124
+
125
+ return `${ t('workloadDashboard.subtitle.multipleSelected', { selected: filters.length }) } ${ countSuffix }`;
126
+ });
127
+
128
+ // ── Workload data ──
129
+
130
+ const workloadData = computed<WorkloadDashboardEntry[]>(() => {
131
+ return summaries.value.map((entry) => {
132
+ const label = t(`typeLabel."${ entry.type }"`, { count: 2 })?.trim() || entry.type;
133
+ const stateCounts: Record<string, number> = {};
134
+ let total = 0;
135
+
136
+ if (entry.summary) {
137
+ for (const s of entry.summary) {
138
+ if (s.property === 'metadata.state.name') {
139
+ for (const [state, detail] of Object.entries(s.counts)) {
140
+ stateCounts[state] = detail.total;
141
+ total += detail.total;
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ return {
148
+ type: entry.type,
149
+ label,
150
+ total,
151
+ stateCounts,
152
+ error: entry.error,
153
+ };
154
+ });
155
+ });
156
+
157
+ const hasWorkloads = computed<boolean>(() => {
158
+ return workloadData.value.some((w) => !w.error && w.total > 0);
159
+ });
160
+
161
+ // ── By State cards ──
162
+
163
+ const byStateCards = computed<WorkloadDashboardStateCard[]>(() => {
164
+ const colorGroups: Record<string, Record<string, { count: number; type: string; stateNames: Set<string> }>> = {
165
+ error: {},
166
+ warning: {},
167
+ info: {},
168
+ success: {},
169
+ disabled: {},
170
+ };
171
+
172
+ for (const w of workloadData.value) {
173
+ if (w.error || w.total === 0) {
174
+ continue;
175
+ }
176
+
177
+ for (const [state, count] of Object.entries(w.stateCounts)) {
178
+ const color = toStateColor(state, w.type);
179
+
180
+ if (!colorGroups[color][w.label]) {
181
+ colorGroups[color][w.label] = {
182
+ count: 0, type: w.type, stateNames: new Set()
183
+ };
184
+ }
185
+ colorGroups[color][w.label].count += count;
186
+ colorGroups[color][w.label].stateNames.add(state);
187
+ }
188
+ }
189
+
190
+ return Object.entries(colorGroups)
191
+ .filter(([, typeMap]) => Object.keys(typeMap).length > 0)
192
+ .map(([color, typeMap]) => ({
193
+ color: color as StateColor,
194
+ rows: Object.entries(typeMap).map(([label, { count, type, stateNames }]) => ({
195
+ label,
196
+ color: color as StateColor,
197
+ type,
198
+ stateNames: Array.from(stateNames),
199
+ counts: [{ label: '', count }],
200
+ })),
201
+ }));
202
+ });
203
+
204
+ const byStateLayout = computed<WorkloadDashboardByStateLayout>(() => {
205
+ const cards = byStateCards.value;
206
+ const hero = cards.find((c) => c.color === 'success') ||
207
+ cards.find((c) => c.color === 'info') ||
208
+ cards.find((c) => c.color === 'error') ||
209
+ (cards.length === 1 ? cards[0] : null) || null;
210
+
211
+ const others = cards.filter((c) => c !== hero);
212
+
213
+ const subHero =
214
+ (hero && others.length >= 2) ? others.find((c) => c.color === 'info') ||
215
+ null : null;
216
+
217
+ const regularCards = subHero ? others.filter((c) => c !== subHero) : others;
218
+
219
+ return {
220
+ hero,
221
+ subHero,
222
+ cards: regularCards,
223
+ };
224
+ });
225
+
226
+ // ── By Type cards ──
227
+
228
+ const byTypeCards = computed<WorkloadDashboardByTypeCard[]>(() => {
229
+ return workloadData.value.filter((w) => !w.error && w.total > 0).map((w) => {
230
+ const resources = Object.entries(w.stateCounts)
231
+ .sort(([a], [b]) => (COLOR_ORDER[toStateColor(a, w.type)] ?? 5) - (COLOR_ORDER[toStateColor(b, w.type)] ?? 5))
232
+ .map(([state, count]) => ({
233
+ stateDisplay: stateDisplay(state, true),
234
+ stateId: state,
235
+ stateSimpleColor: toStateColor(state, w.type),
236
+ count,
237
+ }));
238
+
239
+ return {
240
+ title: w.label,
241
+ type: w.type,
242
+ resources,
243
+ };
244
+ });
245
+ });
246
+
247
+ // ── By Namespace cards ──
248
+
249
+ const byNamespaceCards = computed<WorkloadDashboardByNamespaceCard[]>(() => {
250
+ // namespace -> type -> color -> { count, stateNames }
251
+ const nsMap: Record<string, Record<string, Record<string, { count: number; stateNames: Set<string> }>>> = {};
252
+
253
+ for (const entry of summaries.value) {
254
+ if (entry.error || !entry.summary) {
255
+ continue;
256
+ }
257
+
258
+ for (const s of entry.summary) {
259
+ if (s.property !== 'metadata.state.name') {
260
+ continue;
261
+ }
262
+
263
+ for (const [state, detail] of Object.entries(s.counts)) {
264
+ const color = toStateColor(state, entry.type);
265
+
266
+ for (const [ns, count] of Object.entries(detail.namespace)) {
267
+ if (!nsMap[ns]) {
268
+ nsMap[ns] = {};
269
+ }
270
+ if (!nsMap[ns][entry.type]) {
271
+ nsMap[ns][entry.type] = {};
272
+ }
273
+ if (!nsMap[ns][entry.type][color]) {
274
+ nsMap[ns][entry.type][color] = { count: 0, stateNames: new Set() };
275
+ }
276
+ nsMap[ns][entry.type][color].count += count;
277
+ nsMap[ns][entry.type][color].stateNames.add(state);
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ return Object.entries(nsMap)
284
+ .sort(([a], [b]) => a.localeCompare(b))
285
+ .map(([ns, typeMap]) => {
286
+ const rows = WORKLOAD_RESOURCE_TYPES
287
+ .filter((type) => typeMap[type])
288
+ .map((type) => {
289
+ const label = t(`typeLabel."${ type }"`, { count: 2 })?.trim() || type;
290
+ const counts = Object.entries(typeMap[type])
291
+ .sort(([a], [b]) => (COLOR_ORDER[a] ?? 5) - (COLOR_ORDER[b] ?? 5))
292
+ .map(([color, { count, stateNames }]) => ({
293
+ color: color as StateColor,
294
+ count,
295
+ stateNames: Array.from(stateNames),
296
+ }));
297
+
298
+ return {
299
+ label, type, counts
300
+ };
301
+ });
302
+
303
+ return { title: ns, rows };
304
+ });
305
+ });
306
+
307
+ // ── Actions ──
308
+
309
+ function resetNamespaceFilter(): void {
310
+ store.dispatch('switchNamespaces', {
311
+ ids: [],
312
+ key: clusterId.value,
313
+ });
314
+ }
315
+
316
+ function filterByNamespace(namespace: string): void {
317
+ store.dispatch('switchNamespaces', {
318
+ ids: [`${ NAMESPACE_FILTER_NS_FULL_PREFIX }${ namespace }`],
319
+ key: clusterId.value,
320
+ });
321
+ }
322
+
323
+ function resourceRoute(type: string, stateNames?: string[]): RouteLocationRaw {
324
+ const loc: { name: string; params: Record<string, string>; query?: Record<string, string> } = {
325
+ name: 'c-cluster-product-resource',
326
+ params: {
327
+ cluster: clusterId.value,
328
+ product: 'explorer',
329
+ resource: type,
330
+ },
331
+ };
332
+
333
+ if (stateNames?.length) {
334
+ loc.query = { stateFilter: stateNames.join(',') };
335
+ }
336
+
337
+ return loc;
338
+ }
339
+
340
+ function navigateToNamespace(type: string, namespace: string, stateNames?: string[]): void {
341
+ filterByNamespace(namespace);
342
+ router.push(resourceRoute(type, stateNames));
343
+ }
344
+
345
+ // ── Fetching & polling ──
346
+
347
+ async function fetchSummaries(): Promise<void> {
348
+ try {
349
+ const accessibleTypes = WORKLOAD_RESOURCE_TYPES.filter(
350
+ (type) => store.getters['cluster/canList'](type)
351
+ );
352
+
353
+ const workloadPromises = accessibleTypes.map(async(type): Promise<WorkloadDashboardSummaryEntry> => {
354
+ try {
355
+ let url = `${ store.getters['cluster/urlFor'](type) }`;
356
+
357
+ if (namespaceFilterParam.value) {
358
+ url += `&${ namespaceFilterParam.value }`;
359
+ }
360
+ url += `&summary=metadata.state.name&summaryonly&summarynamespaced`;
361
+
362
+ const res = await store.dispatch('cluster/request', { url });
363
+
364
+ return {
365
+ type, summary: res.summary || [], error: null
366
+ };
367
+ } catch (e: unknown) {
368
+ const message = e instanceof Error ? e.message : t('workloadDashboard.errors.fetchType', { type });
369
+
370
+ return {
371
+ type, summary: null, error: message
372
+ };
373
+ }
374
+ });
375
+
376
+ const results = await Promise.all(workloadPromises);
377
+
378
+ await resolveStateColors(results);
379
+ summaries.value = results;
380
+ fetchError.value = null;
381
+ } catch (e: unknown) {
382
+ fetchError.value = e instanceof Error ? e.message : t('workloadDashboard.errors.fetchAll');
383
+ }
384
+ }
385
+
386
+ function stopPollTimer(): void {
387
+ if (pollTimer) {
388
+ clearInterval(pollTimer);
389
+ pollTimer = null;
390
+ }
391
+ }
392
+
393
+ function startPollTimer(): void {
394
+ stopPollTimer();
395
+
396
+ pollTimer = setInterval(() => {
397
+ fetchSummaries();
398
+ }, 5000);
399
+ }
400
+
401
+ function handleVisibilityChange(): void {
402
+ if (document.hidden) {
403
+ stopPollTimer();
404
+ } else {
405
+ fetchSummaries();
406
+ startPollTimer();
407
+ }
408
+ }
409
+
410
+ watch(namespaceFilterParam, () => {
411
+ fetchSummaries();
412
+ startPollTimer();
413
+ });
414
+
415
+ onMounted(async() => {
416
+ await fetchSummaries();
417
+ loading.value = false;
418
+ startPollTimer();
419
+ document.addEventListener('visibilitychange', handleVisibilityChange);
420
+ });
421
+
422
+ onBeforeUnmount(() => {
423
+ stopPollTimer();
424
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
425
+ });
426
+
427
+ return {
428
+ loading,
429
+ fetchError,
430
+ hasWorkloads,
431
+ namespaceSubtitle,
432
+ byStateLayout,
433
+ byTypeCards,
434
+ byNamespaceCards,
435
+ resetNamespaceFilter,
436
+ filterByNamespace,
437
+ resourceRoute,
438
+ navigateToNamespace,
439
+ };
440
+ }
@@ -0,0 +1,187 @@
1
+ <script setup lang="ts">
2
+ import { Banner } from '@components/Banner';
3
+ import Loading from '@shell/components/Loading';
4
+ import Masthead from '@shell/components/ResourceList/Masthead';
5
+ import RichTranslation from '@shell/components/RichTranslation.vue';
6
+ import SubtleLink from '@shell/components/SubtleLink.vue';
7
+ import { DOCS_BASE } from '@shell/config/private-label';
8
+ import { useI18n } from '@shell/composables/useI18n';
9
+ import { useStore } from 'vuex';
10
+ import { useWorkloadDashboard } from './composable';
11
+ import ByStateSection from './ByStateSection.vue';
12
+ import ByTypeSection from './ByTypeSection.vue';
13
+ import ByNamespaceSection from './ByNamespaceSection.vue';
14
+
15
+ const store = useStore();
16
+ const { t } = useI18n(store);
17
+
18
+ const {
19
+ loading,
20
+ fetchError,
21
+ hasWorkloads,
22
+ namespaceSubtitle,
23
+ byStateLayout,
24
+ byTypeCards,
25
+ byNamespaceCards,
26
+ resetNamespaceFilter,
27
+ filterByNamespace,
28
+ resourceRoute,
29
+ navigateToNamespace,
30
+ } = useWorkloadDashboard();
31
+ </script>
32
+
33
+ <template>
34
+ <Loading v-if="loading" />
35
+
36
+ <div
37
+ v-else
38
+ class="workload-dashboard"
39
+ >
40
+ <Banner
41
+ v-if="fetchError"
42
+ color="error"
43
+ >
44
+ {{ fetchError }}
45
+ </Banner>
46
+
47
+ <!-- ━━━ Empty state ━━━ -->
48
+ <div
49
+ v-if="!hasWorkloads"
50
+ class="empty-state"
51
+ data-testid="workload-dashboard-empty"
52
+ >
53
+ <h1 class="m-0">
54
+ {{ t('workloadDashboard.empty.title') }}
55
+ </h1>
56
+ <div class="empty-state-tips">
57
+ <RichTranslation k="workloadDashboard.empty.message">
58
+ <template #resetLink="{ content }">
59
+ <a
60
+ role="button"
61
+ tabindex="0"
62
+ class="link"
63
+ @click="resetNamespaceFilter"
64
+ @keyup.enter="resetNamespaceFilter"
65
+ >{{ content }}</a>
66
+ </template>
67
+ </RichTranslation>
68
+ <RichTranslation
69
+ k="workloadDashboard.empty.docsMessage"
70
+ tag="div"
71
+ >
72
+ <template #docsLink="{ content }">
73
+ <SubtleLink
74
+ :href="`${DOCS_BASE}/how-to-guides/new-user-guides/kubernetes-resources-setup/workloads-and-pods`"
75
+ target="_blank"
76
+ :open-in-new-tab-label="t('generic.opensInNewTab')"
77
+ >
78
+ {{ content }}
79
+ </SubtleLink>
80
+ </template>
81
+ </RichTranslation>
82
+ </div>
83
+ </div>
84
+
85
+ <template v-else>
86
+ <Masthead
87
+ resource="workload"
88
+ :type-display="t('workloadDashboard.title')"
89
+ :is-creatable="false"
90
+ :show-favorite="false"
91
+ component-testid="workload-dashboard"
92
+ >
93
+ <template #subHeader>
94
+ <div
95
+ class="text-muted mmt-1"
96
+ data-testid="workload-dashboard-subtitle"
97
+ >
98
+ {{ namespaceSubtitle }}
99
+ </div>
100
+ </template>
101
+ </Masthead>
102
+ <div class="workload-content">
103
+ <!-- ━━━ By State ━━━ -->
104
+ <div
105
+ class="section"
106
+ data-testid="workload-dashboard-by-state"
107
+ >
108
+ <h4 class="m-0 text-deemphasized">
109
+ {{ t('workloadDashboard.sections.byState') }}
110
+ </h4>
111
+ <ByStateSection
112
+ :layout="byStateLayout"
113
+ :resource-route="resourceRoute"
114
+ />
115
+ </div>
116
+
117
+ <!-- ━━━ By Type ━━━ -->
118
+ <div
119
+ class="section"
120
+ data-testid="workload-dashboard-by-type"
121
+ >
122
+ <h4 class="m-0 text-deemphasized">
123
+ {{ t('workloadDashboard.sections.byType') }}
124
+ </h4>
125
+ <ByTypeSection
126
+ :cards="byTypeCards"
127
+ :resource-route="resourceRoute"
128
+ />
129
+ </div>
130
+
131
+ <!-- ━━━ By Namespace ━━━ -->
132
+ <div
133
+ class="section"
134
+ data-testid="workload-dashboard-by-namespace"
135
+ >
136
+ <h4 class="m-0 text-deemphasized">
137
+ {{ t('workloadDashboard.sections.byNamespace') }}
138
+ </h4>
139
+ <ByNamespaceSection
140
+ :cards="byNamespaceCards"
141
+ :navigate-to-namespace="navigateToNamespace"
142
+ :filter-by-namespace="filterByNamespace"
143
+ />
144
+ </div>
145
+ </div>
146
+ </template>
147
+ </div>
148
+ </template>
149
+
150
+ <style lang="scss" scoped>
151
+ .workload-dashboard {
152
+ display: flex;
153
+ flex-direction: column;
154
+
155
+ .workload-content {
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 24px;
159
+ }
160
+
161
+ .section {
162
+ h4 {
163
+ line-height: 21px;
164
+ }
165
+ gap: 16px;
166
+ display: flex;
167
+ flex-direction: column;
168
+ }
169
+
170
+ .empty-state {
171
+ text-align: center;
172
+ padding: 72px;
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: 16px;
176
+
177
+ h1 {
178
+ line-height: 38px;
179
+ }
180
+ .empty-state-tips {
181
+ font-size: 16px;
182
+ line-height: 29px;
183
+ }
184
+ }
185
+
186
+ }
187
+ </style>
@@ -0,0 +1,80 @@
1
+ import { WORKLOAD_TYPES, POD } from '@shell/config/types';
2
+ import type { StateColor } from '@shell/utils/style';
3
+ import type { RouteLocationRaw } from 'vue-router';
4
+
5
+ export interface WorkloadDashboardSummaryEntry {
6
+ type: string;
7
+ summary: { property: string; counts: Record<string, { total: number; namespace: Record<string, number> }> }[] | null;
8
+ error: string | null;
9
+ }
10
+
11
+ export interface WorkloadDashboardEntry {
12
+ type: string;
13
+ label: string;
14
+ total: number;
15
+ stateCounts: Record<string, number>;
16
+ error: string | null;
17
+ }
18
+
19
+ export interface WorkloadDashboardStateCardRow {
20
+ label: string;
21
+ color: StateColor;
22
+ type: string;
23
+ stateNames: string[];
24
+ counts: { label: string; count: number }[];
25
+ }
26
+
27
+ export interface WorkloadDashboardStateCard {
28
+ color: StateColor;
29
+ rows: WorkloadDashboardStateCardRow[];
30
+ }
31
+
32
+ export interface WorkloadDashboardByStateLayout {
33
+ hero: WorkloadDashboardStateCard | null;
34
+ subHero: WorkloadDashboardStateCard | null;
35
+ cards: WorkloadDashboardStateCard[];
36
+ }
37
+
38
+ export interface WorkloadDashboardByTypeCard {
39
+ title: string;
40
+ type: string;
41
+ resources: {
42
+ stateDisplay: string;
43
+ stateId: string;
44
+ stateSimpleColor: StateColor;
45
+ count: number;
46
+ }[];
47
+ }
48
+
49
+ export type WorkloadDashboardResourceRouteFn = (type: string, stateNames?: string[]) => RouteLocationRaw;
50
+
51
+ export interface WorkloadDashboardByNamespaceCardRow {
52
+ label: string;
53
+ type: string;
54
+ counts: {
55
+ color: StateColor;
56
+ count: number;
57
+ stateNames: string[];
58
+ }[];
59
+ }
60
+
61
+ export interface WorkloadDashboardByNamespaceCard {
62
+ title: string;
63
+ rows: WorkloadDashboardByNamespaceCardRow[];
64
+ }
65
+
66
+ export type WorkloadDashboardNamespaceNavigateFn = (type: string, namespace: string, stateNames?: string[]) => void;
67
+ export type WorkloadDashboardFilterByNamespaceFn = (namespace: string) => void;
68
+
69
+ export const WORKLOAD_RESOURCE_TYPES: string[] = [
70
+ WORKLOAD_TYPES.CRON_JOB,
71
+ WORKLOAD_TYPES.DAEMON_SET,
72
+ WORKLOAD_TYPES.DEPLOYMENT,
73
+ WORKLOAD_TYPES.JOB,
74
+ WORKLOAD_TYPES.STATEFUL_SET,
75
+ POD,
76
+ ];
77
+
78
+ export const COLOR_ORDER: Record<string, number> = {
79
+ error: 0, warning: 1, disabled: 2, info: 3, success: 4
80
+ };