@rancher/shell 3.0.12-rc.1 → 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 (376) 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/images/providers/entraid-black.svg +4 -0
  54. package/assets/images/providers/entraid.svg +9 -0
  55. package/assets/images/vendor/entraid.svg +9 -0
  56. package/assets/styles/app.scss +0 -1
  57. package/assets/styles/base/_variables.scss +2 -0
  58. package/assets/styles/fonts/_fontstack.scss +132 -8
  59. package/assets/translations/en-us.yaml +41 -22
  60. package/assets/translations/zh-hans.yaml +4 -8
  61. package/chart/__tests__/S3.test.ts +10 -3
  62. package/chart/monitoring/index.vue +10 -1
  63. package/components/ActionDropdownShell.vue +2 -1
  64. package/components/CountBox.vue +20 -0
  65. package/components/CreateDriver.vue +0 -12
  66. package/components/CruResourceFooter.vue +9 -5
  67. package/components/DetailText.vue +12 -3
  68. package/components/ExplorerProjectsNamespaces.vue +1 -1
  69. package/components/InstallHelmCharts.vue +2 -2
  70. package/components/LandingPagePreference.vue +14 -5
  71. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
  72. package/components/Resource/Detail/Metadata/index.vue +6 -0
  73. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  74. package/components/Resource/Detail/SpacedRow.vue +3 -1
  75. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  76. package/components/ResourceList/Masthead.vue +12 -8
  77. package/components/SelectIconGrid.vue +5 -10
  78. package/components/SingleClusterInfo.vue +1 -0
  79. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  80. package/components/SortableTable/index.vue +6 -9
  81. package/components/SortableTable/selection.js +23 -5
  82. package/components/SortableTable/sorting.js +6 -3
  83. package/components/Wizard.vue +14 -13
  84. package/components/__tests__/CountBox.test.ts +72 -0
  85. package/components/__tests__/DetailText.test.ts +113 -0
  86. package/components/fleet/FleetBundles.vue +100 -12
  87. package/components/fleet/FleetClusterTargets/index.vue +54 -15
  88. package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
  89. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  90. package/components/form/InputWithSelect.vue +18 -10
  91. package/components/form/KeyValue.vue +17 -1
  92. package/components/form/LabeledSelect.vue +101 -26
  93. package/components/form/NameNsDescription.vue +11 -0
  94. package/components/form/Security.vue +6 -2
  95. package/components/form/Select.vue +73 -56
  96. package/components/form/ServiceNameSelect.vue +13 -11
  97. package/components/form/WorkloadPorts.vue +2 -7
  98. package/components/form/__tests__/KeyValue.test.ts +66 -0
  99. package/components/form/__tests__/NodeScheduling.test.ts +9 -0
  100. package/components/form/__tests__/Security.test.ts +76 -0
  101. package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
  102. package/components/formatter/Autoscaler.vue +4 -4
  103. package/components/formatter/ClusterKubeVersion.vue +27 -0
  104. package/components/formatter/ClusterLink.vue +1 -7
  105. package/components/formatter/ClusterProvider.vue +6 -10
  106. package/components/formatter/FleetSummaryGraph.vue +0 -3
  107. package/components/formatter/MachineSummaryGraph.vue +1 -1
  108. package/components/formatter/PodsUsage.vue +2 -2
  109. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  110. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  111. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  112. package/components/nav/Group.vue +7 -6
  113. package/components/nav/Header.vue +24 -3
  114. package/components/nav/NamespaceFilter.vue +2 -2
  115. package/components/nav/NotificationCenter/Notification.vue +4 -1
  116. package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
  117. package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
  118. package/components/nav/TopLevelMenu.helper.ts +15 -3
  119. package/components/nav/TopLevelMenu.vue +16 -5
  120. package/components/nav/Type.vue +8 -7
  121. package/components/nav/WindowManager/index.vue +2 -1
  122. package/components/nav/WorkspaceSwitcher.vue +13 -0
  123. package/components/nav/__tests__/Group.test.ts +67 -0
  124. package/components/nav/__tests__/Header.test.ts +235 -0
  125. package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
  126. package/components/nav/__tests__/Type.test.ts +20 -3
  127. package/components/templates/default.vue +34 -4
  128. package/components/templates/home.vue +30 -25
  129. package/components/templates/plain.vue +31 -26
  130. package/components/templates/standalone.vue +17 -0
  131. package/composables/useFormValidation.ts +93 -0
  132. package/composables/useLabeledFormElement.ts +10 -2
  133. package/composables/useLabeledSelect.ts +60 -0
  134. package/composables/useUserRetentionValidation.ts +1 -49
  135. package/composables/useVeeValidateField.test.ts +159 -0
  136. package/composables/useVeeValidateField.ts +67 -0
  137. package/config/cookies.js +0 -1
  138. package/config/labels-annotations.js +1 -0
  139. package/config/pagination-table-headers.js +18 -1
  140. package/config/product/manager.js +82 -21
  141. package/config/query-params.js +1 -0
  142. package/config/router/routes.js +6 -8
  143. package/config/table-headers.js +20 -1
  144. package/config/types.js +2 -1
  145. package/core/__tests__/plugin-products.test.ts +1505 -30
  146. package/core/plugin-products-base.ts +137 -20
  147. package/core/plugin-products-helpers.ts +5 -4
  148. package/core/plugin-products.ts +4 -0
  149. package/core/plugin-types.ts +129 -4
  150. package/core/plugin.ts +15 -7
  151. package/core/productDebugger.js +9 -4
  152. package/core/types-provisioning.ts +43 -30
  153. package/core/types.ts +58 -19
  154. package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
  155. package/detail/__tests__/pod.test.ts +41 -0
  156. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  157. package/detail/management.cattle.io.fleetworkspace.vue +49 -0
  158. package/detail/pod.vue +1 -1
  159. package/detail/provisioning.cattle.io.cluster.vue +4 -10
  160. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
  161. package/edit/__tests__/kontainerDriver.test.ts +0 -13
  162. package/edit/__tests__/nodeDriver.test.ts +5 -11
  163. package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
  164. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  165. package/edit/auth/__tests__/azuread.test.ts +217 -34
  166. package/edit/auth/__tests__/oidc.test.ts +54 -0
  167. package/edit/auth/azuread.vue +123 -15
  168. package/edit/auth/oidc.vue +10 -2
  169. package/edit/kontainerDriver.vue +1 -2
  170. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  171. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  172. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  173. package/edit/nodeDriver.vue +0 -2
  174. package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
  175. package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
  176. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  177. package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
  178. package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
  179. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  180. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  181. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  182. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  183. package/edit/secret/__tests__/ssh.test.ts +5 -6
  184. package/edit/secret/basic.vue +31 -0
  185. package/edit/secret/index.vue +68 -17
  186. package/edit/secret/registry.vue +38 -0
  187. package/edit/secret/ssh.vue +29 -0
  188. package/edit/secret/tls.vue +30 -0
  189. package/edit/service.vue +4 -4
  190. package/edit/workload/Upgrading.vue +3 -3
  191. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  192. package/edit/workload/mixins/workload.js +2 -1
  193. package/initialize/App.vue +29 -2
  194. package/initialize/install-plugins.js +0 -2
  195. package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
  196. package/list/catalog.cattle.io.app.vue +25 -5
  197. package/list/fleet.cattle.io.bundle.vue +7 -104
  198. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  199. package/list/management.cattle.io.feature.vue +1 -1
  200. package/list/management.cattle.io.fleetworkspace.vue +8 -0
  201. package/list/provisioning.cattle.io.cluster.vue +262 -180
  202. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  203. package/machine-config/amazonec2.vue +1 -0
  204. package/mixins/__tests__/chart.test.ts +112 -0
  205. package/mixins/brand.js +2 -1
  206. package/mixins/chart.js +50 -15
  207. package/mixins/resource-fetch-api-pagination.js +41 -5
  208. package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
  209. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
  210. package/models/__tests__/chart.test.ts +99 -6
  211. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  212. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  213. package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
  214. package/models/__tests__/management.cattle.io.node.ts +6 -5
  215. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  216. package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
  217. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
  218. package/models/base-cluster.x-k8s.io.js +26 -0
  219. package/models/catalog.cattle.io.app.js +21 -17
  220. package/models/catalog.cattle.io.clusterrepo.js +39 -11
  221. package/models/chart.js +33 -19
  222. package/models/cluster.js +1 -1
  223. package/models/cluster.x-k8s.io.machine.js +4 -22
  224. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  225. package/models/cluster.x-k8s.io.machineset.js +2 -20
  226. package/models/compliance.cattle.io.clusterscan.js +130 -2
  227. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  228. package/models/fleet-application.js +4 -2
  229. package/models/fleet.cattle.io.bundle.js +1 -1
  230. package/models/kontainerdriver.js +11 -0
  231. package/models/management.cattle.io.authconfig.js +5 -1
  232. package/models/management.cattle.io.cluster.js +402 -78
  233. package/models/management.cattle.io.feature.js +3 -3
  234. package/models/management.cattle.io.kontainerdriver.js +1 -26
  235. package/models/management.cattle.io.node.js +6 -4
  236. package/models/management.cattle.io.nodepool.js +1 -1
  237. package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
  238. package/models/networking.k8s.io.ingress.js +12 -4
  239. package/models/nodedriver.js +7 -0
  240. package/models/provisioning.cattle.io.cluster.js +47 -330
  241. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  242. package/package.json +20 -37
  243. package/pages/__tests__/readme.test.ts +49 -0
  244. package/pages/auth/setup.vue +2 -3
  245. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
  246. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
  247. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
  248. package/pages/c/_cluster/apps/charts/chart.vue +275 -39
  249. package/pages/c/_cluster/apps/charts/index.vue +2 -2
  250. package/pages/c/_cluster/apps/charts/install.vue +18 -10
  251. package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
  252. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  253. package/pages/c/_cluster/explorer/index.vue +5 -49
  254. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  255. package/pages/c/_cluster/istio/index.vue +21 -6
  256. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
  257. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
  258. package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
  259. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
  260. package/pages/c/_cluster/uiplugins/index.vue +226 -222
  261. package/pages/diagnostic.vue +13 -17
  262. package/pages/fail-whale.vue +18 -0
  263. package/pages/home.vue +77 -260
  264. package/pages/readme.vue +88 -0
  265. package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
  266. package/plugins/dashboard-store/actions.js +40 -18
  267. package/plugins/dashboard-store/resource-class.js +5 -2
  268. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  269. package/plugins/steve/steve-pagination-utils.ts +11 -3
  270. package/plugins/steve/subscribe.js +35 -5
  271. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
  272. package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
  273. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
  274. package/rancher-components/RcButton/RcButton.test.ts +37 -1
  275. package/rancher-components/RcButton/RcButton.vue +38 -8
  276. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  277. package/scripts/test-plugins-build.sh +5 -2
  278. package/server/server-middleware.js +2 -2
  279. package/static/humans.txt +1 -0
  280. package/static/robots.txt +34 -0
  281. package/static/welcome-cow.svg +18 -0
  282. package/store/__tests__/catalog.test.ts +276 -12
  283. package/store/__tests__/type-map.test.ts +556 -1
  284. package/store/action-menu.js +8 -3
  285. package/store/auth.js +1 -4
  286. package/store/aws.js +27 -16
  287. package/store/catalog.js +87 -11
  288. package/store/digitalocean.js +20 -38
  289. package/store/index.js +2 -0
  290. package/store/linode.js +25 -40
  291. package/store/pnap.js +1 -0
  292. package/store/type-map.js +111 -29
  293. package/tsconfig.paths.json +8 -8
  294. package/types/kube/kube-api.ts +14 -1
  295. package/types/rancher/steve.api.ts +12 -12
  296. package/types/resources/settings.d.ts +2 -1
  297. package/types/shell/index.d.ts +128 -24
  298. package/types/store/dashboard-store.types.ts +108 -11
  299. package/types/store/pagination.types.ts +6 -3
  300. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  301. package/utils/__tests__/async.test.ts +87 -0
  302. package/utils/__tests__/aws.test.ts +140 -0
  303. package/utils/__tests__/banners.test.ts +176 -0
  304. package/utils/__tests__/chart.test.ts +64 -1
  305. package/utils/__tests__/color.test.ts +226 -0
  306. package/utils/__tests__/duration.test.ts +140 -0
  307. package/utils/__tests__/fleet.test.ts +340 -0
  308. package/utils/__tests__/git.test.ts +270 -0
  309. package/utils/__tests__/inactivity.test.ts +316 -0
  310. package/utils/__tests__/ingress.test.ts +553 -0
  311. package/utils/__tests__/kube.test.ts +68 -0
  312. package/utils/__tests__/namespace-filter.test.ts +109 -0
  313. package/utils/__tests__/object.test.ts +77 -0
  314. package/utils/__tests__/pagination-utils.test.ts +361 -0
  315. package/utils/__tests__/parse-externalid.test.ts +137 -0
  316. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  317. package/utils/__tests__/poller-sequential.test.ts +177 -0
  318. package/utils/__tests__/poller.test.ts +170 -0
  319. package/utils/__tests__/promise.test.ts +346 -0
  320. package/utils/__tests__/settings.test.ts +140 -0
  321. package/utils/__tests__/sort-utils.test.ts +301 -0
  322. package/utils/__tests__/string-utils.test.ts +798 -0
  323. package/utils/__tests__/string.test.ts +23 -1
  324. package/utils/__tests__/style.test.ts +154 -0
  325. package/utils/__tests__/svg-filter.test.ts +184 -0
  326. package/utils/__tests__/time.test.ts +14 -1
  327. package/utils/__tests__/units.test.ts +417 -0
  328. package/utils/__tests__/url.test.ts +246 -0
  329. package/utils/__tests__/versions.test.ts +128 -0
  330. package/utils/__tests__/xccdf.test.ts +391 -0
  331. package/utils/chart.js +36 -0
  332. package/utils/fleet.ts +13 -3
  333. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  334. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  335. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  336. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  337. package/utils/gc/__tests__/gc.test.ts +487 -0
  338. package/utils/ingress.ts +9 -1
  339. package/utils/object.js +33 -2
  340. package/utils/pagination-utils.ts +2 -1
  341. package/utils/string.js +25 -2
  342. package/utils/time.ts +5 -0
  343. package/utils/uiplugins.ts +5 -5
  344. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  345. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  346. package/utils/validators/__tests__/index.test.ts +481 -0
  347. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  348. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  349. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  350. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  351. package/utils/validators/__tests__/role-template.test.ts +149 -0
  352. package/utils/validators/__tests__/service.test.ts +283 -0
  353. package/utils/validators/__tests__/setting.test.js +32 -0
  354. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  355. package/utils/validators/formRules/index.ts +5 -5
  356. package/utils/validators/machine-pool.ts +1 -1
  357. package/utils/validators/setting.js +18 -3
  358. package/utils/xccdf.ts +418 -0
  359. package/vue.config.js +0 -9
  360. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  361. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  362. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  363. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
  364. package/assets/images/providers/azuread-black.svg +0 -22
  365. package/assets/images/providers/azuread.svg +0 -25
  366. package/assets/images/vendor/azuread.svg +0 -18
  367. package/assets/styles/fonts/_dots.scss +0 -18
  368. package/components/EmberPage.vue +0 -622
  369. package/components/EmberPageView.vue +0 -39
  370. package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
  371. package/mixins/labeled-form-element.ts +0 -225
  372. package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
  373. package/pages/c/_cluster/manager/pages/_page.vue +0 -22
  374. package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
  375. package/plugins/ember-cookie.js +0 -17
  376. package/utils/ember-page.js +0 -30
@@ -0,0 +1,216 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import FleetSummaryGraph from '@shell/components/formatter/FleetSummaryGraph.vue';
3
+ import { FLEET } from '@shell/config/types';
4
+ import { ExtendedVue, Vue } from 'vue/types/vue';
5
+ import { DefaultProps } from 'vue/types/options';
6
+
7
+ const FleetSummaryGraphComponent = FleetSummaryGraph as unknown as ExtendedVue<Vue, {}, {}, {}, DefaultProps>;
8
+
9
+ function makeRow({
10
+ type = FLEET.GIT_REPO,
11
+ resourceCounts = {},
12
+ targetClusters = [],
13
+ statusResourceCountsForCluster = undefined,
14
+ }: {
15
+ type?: string;
16
+ resourceCounts?: Record<string, number>;
17
+ targetClusters?: any[];
18
+ statusResourceCountsForCluster?: any;
19
+ } = {}) {
20
+ const row: Record<string, any> = {
21
+ id: 'test-ns/test-row',
22
+ type,
23
+ status: { resourceCounts },
24
+ targetClusters,
25
+ };
26
+
27
+ if (statusResourceCountsForCluster !== undefined) {
28
+ row.statusResourceCountsForCluster = statusResourceCountsForCluster;
29
+ }
30
+
31
+ return row;
32
+ }
33
+
34
+ describe('component: FleetSummaryGraph', () => {
35
+ describe('summary', () => {
36
+ it('returns status.resourceCounts for GitRepo rows', () => {
37
+ const resourceCounts = {
38
+ desiredReady: 7,
39
+ ready: 7,
40
+ };
41
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
42
+ propsData: {
43
+ row: makeRow({
44
+ resourceCounts,
45
+ targetClusters: [{ id: 'cluster-1' }],
46
+ }),
47
+ },
48
+ });
49
+
50
+ expect((wrapper.vm as any).summary).toStrictEqual(resourceCounts);
51
+ });
52
+
53
+ it('returns status.resourceCounts for HelmOp rows', () => {
54
+ const resourceCounts = {
55
+ desiredReady: 3,
56
+ ready: 2,
57
+ modified: 1,
58
+ };
59
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
60
+ propsData: {
61
+ row: makeRow({
62
+ type: FLEET.HELM_OP,
63
+ resourceCounts,
64
+ targetClusters: [{ id: 'cluster-1' }],
65
+ }),
66
+ },
67
+ });
68
+
69
+ expect((wrapper.vm as any).summary).toStrictEqual(resourceCounts);
70
+ });
71
+
72
+ it('does not return function when row has statusResourceCountsForCluster as a method', () => {
73
+ const resourceCounts = {
74
+ desiredReady: 5,
75
+ ready: 5,
76
+ };
77
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
78
+ propsData: {
79
+ row: makeRow({
80
+ resourceCounts,
81
+ targetClusters: [{ id: 'cluster-1' }],
82
+ // Simulate a class method — the bug was that a truthy function
83
+ // caused summary to return the function itself instead of resourceCounts
84
+ statusResourceCountsForCluster: (clusterId: string) => ({ desiredReady: 0 }),
85
+ }),
86
+ },
87
+ });
88
+
89
+ const summary = (wrapper.vm as any).summary;
90
+
91
+ expect(typeof summary).not.toBe('function');
92
+ expect(summary).toStrictEqual(resourceCounts);
93
+ });
94
+
95
+ it('calls statusResourceCountsForCluster with clusterId when clusterId prop is set', () => {
96
+ const perClusterData = {
97
+ desiredReady: 2,
98
+ ready: 1,
99
+ };
100
+ const mockFn = jest.fn().mockReturnValue(perClusterData);
101
+
102
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
103
+ propsData: {
104
+ row: makeRow({ statusResourceCountsForCluster: mockFn }),
105
+ clusterId: 'cluster-1',
106
+ },
107
+ });
108
+
109
+ expect((wrapper.vm as any).summary).toStrictEqual(perClusterData);
110
+ expect(mockFn).toHaveBeenCalledWith('cluster-1');
111
+ });
112
+
113
+ it('returns empty object when status.resourceCounts is undefined', () => {
114
+ const wrapper = shallowMount(FleetSummaryGraphComponent, { propsData: { row: makeRow() } });
115
+
116
+ expect((wrapper.vm as any).summary).toStrictEqual({});
117
+ });
118
+ });
119
+
120
+ describe('show', () => {
121
+ it('returns true when stateParts exist and row has targetClusters', () => {
122
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
123
+ propsData: {
124
+ row: makeRow({
125
+ resourceCounts: {
126
+ desiredReady: 5,
127
+ ready: 5,
128
+ },
129
+ targetClusters: [{ id: 'cluster-1' }],
130
+ }),
131
+ },
132
+ });
133
+
134
+ expect((wrapper.vm as any).show).toBeTruthy();
135
+ });
136
+
137
+ it('returns false when stateParts exist but targetClusters is empty', () => {
138
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
139
+ propsData: {
140
+ row: makeRow({
141
+ resourceCounts: {
142
+ desiredReady: 5,
143
+ ready: 5,
144
+ },
145
+ targetClusters: [],
146
+ }),
147
+ },
148
+ });
149
+
150
+ expect((wrapper.vm as any).show).toBeFalsy();
151
+ });
152
+
153
+ it('returns true for FLEET.CLUSTER type even without targetClusters', () => {
154
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
155
+ propsData: {
156
+ row: makeRow({
157
+ type: FLEET.CLUSTER,
158
+ resourceCounts: {
159
+ desiredReady: 3,
160
+ ready: 3,
161
+ },
162
+ }),
163
+ },
164
+ });
165
+
166
+ expect((wrapper.vm as any).show).toBeTruthy();
167
+ });
168
+
169
+ it('returns false when resourceCounts is empty', () => {
170
+ const wrapper = shallowMount(FleetSummaryGraphComponent, { propsData: { row: makeRow({ targetClusters: [{ id: 'cluster-1' }] }) } });
171
+
172
+ expect((wrapper.vm as any).show).toBeFalsy();
173
+ });
174
+ });
175
+
176
+ describe('stateParts', () => {
177
+ it('filters out keys starting with "desired"', () => {
178
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
179
+ propsData: {
180
+ row: makeRow({
181
+ resourceCounts: {
182
+ desiredReady: 5,
183
+ ready: 5,
184
+ },
185
+ targetClusters: [{ id: 'cluster-1' }],
186
+ }),
187
+ },
188
+ });
189
+
190
+ const parts = (wrapper.vm as any).stateParts;
191
+
192
+ expect(parts.every((p: any) => !p.label.startsWith('Desired'))).toBe(true);
193
+ });
194
+
195
+ it('filters out entries with value 0', () => {
196
+ const wrapper = shallowMount(FleetSummaryGraphComponent, {
197
+ propsData: {
198
+ row: makeRow({
199
+ resourceCounts: {
200
+ desiredReady: 5,
201
+ ready: 5,
202
+ notReady: 0,
203
+ },
204
+ targetClusters: [{ id: 'cluster-1' }],
205
+ }),
206
+ },
207
+ });
208
+
209
+ const parts = (wrapper.vm as any).stateParts;
210
+ const labels = parts.map((p: any) => p.label);
211
+
212
+ expect(labels).toContain('Ready');
213
+ expect(labels).not.toContain('NotReady');
214
+ });
215
+ });
216
+ });
@@ -7,11 +7,9 @@ describe('component: PodsUsage', () => {
7
7
  props: {
8
8
  row: {
9
9
  isReady: true,
10
- mgmt: {
11
- status: {
12
- requested: { pods: 10 },
13
- allocatable: { pods: 20 }
14
- }
10
+ status: {
11
+ requested: { pods: 10 },
12
+ allocatable: { pods: 20 }
15
13
  }
16
14
  }
17
15
  },
@@ -28,11 +26,9 @@ describe('component: PodsUsage', () => {
28
26
  props: {
29
27
  row: {
30
28
  isReady: true,
31
- mgmt: {
32
- status: {
33
- requested: { pods: 10 },
34
- allocatable: { pods: 0 }
35
- }
29
+ status: {
30
+ requested: { pods: 10 },
31
+ allocatable: { pods: 0 }
36
32
  }
37
33
  }
38
34
  },
@@ -82,7 +82,8 @@ export default {
82
82
  const validRoute = filterLocationValidParams(this.$router, overviewRoute || {});
83
83
  const route = this.$router.resolve(validRoute);
84
84
 
85
- return this.$route.fullPath.split('#')[0] === route?.fullPath;
85
+ // Use .path instead of .fullPath to ignore query parameters and hashes when comparing routes
86
+ return this.$route.path === route?.path;
86
87
  }
87
88
  }
88
89
 
@@ -204,14 +205,14 @@ export default {
204
205
  } else if (item.route) {
205
206
  const navLevels = ['cluster', 'product', 'resource'];
206
207
  const matchesNavLevel = navLevels.filter((param) => !this.$route.params[param] || this.$route.params[param] !== item.route.params[param]).length === 0;
207
- const withoutHash = this.$route.hash ? this.$route.fullPath.slice(0, this.$route.fullPath.indexOf(this.$route.hash)) : this.$route.fullPath;
208
- const withoutQuery = withoutHash.split('?')[0];
209
208
  const validItemRoute = filterLocationValidParams(this.$router, item.route);
210
- const itemFullPath = this.$router.resolve(validItemRoute).fullPath;
211
209
 
212
- if (matchesNavLevel || itemFullPath === withoutQuery) {
210
+ // Use .path instead of .fullPath to ignore query parameters and hashes when comparing routes
211
+ const itemPath = this.$router.resolve(validItemRoute).path;
212
+
213
+ if (matchesNavLevel || itemPath === this.$route.path) {
213
214
  return true;
214
- } else if (parentPath && itemFullPath === parentPath) {
215
+ } else if (parentPath && itemPath === parentPath) {
215
216
  return true;
216
217
  }
217
218
  }
@@ -189,12 +189,30 @@ export default {
189
189
  (this.currentProduct && this.currentProduct.showWorkspaceSwitcher);
190
190
  // Don't show if the header is in 'simple' mode
191
191
  const notSimple = !this.simple;
192
- // One of these must be enabled, otherwise t here's no component to show
193
- const validFilterSettings = this.currentProduct?.showNamespaceFilter || this.currentProduct?.showWorkspaceSwitcher;
192
+ // One of these must be enabled, otherwise there's no component to show
193
+ const validFilterSettings = this.currentProduct?.showNamespaceFilter || this.showWorkspaceSwitcher;
194
194
 
195
195
  return validClusterOrProduct && notSimple && validFilterSettings;
196
196
  },
197
197
 
198
+ /**
199
+ * The workspace switcher should be disabled on detail, edit and create pages.
200
+ * Only list pages should allow changing the workspace.
201
+ */
202
+ disableWorkspaceSwitcher() {
203
+ // Disable on detail/edit pages (route has an id param)
204
+ if (this.$route?.params?.id) {
205
+ return true;
206
+ }
207
+
208
+ // Disable on create pages (route names end with '-create')
209
+ if (this.$route?.name?.endsWith('-create')) {
210
+ return true;
211
+ }
212
+
213
+ return false;
214
+ },
215
+
198
216
  featureRancherDesktop() {
199
217
  return this.$config.rancherEnv === 'desktop';
200
218
  },
@@ -581,7 +599,10 @@ export default {
581
599
  class="top"
582
600
  >
583
601
  <NamespaceFilter v-if="clusterReady && currentProduct && (currentProduct.showNamespaceFilter || isExplorer)" />
584
- <WorkspaceSwitcher v-else-if="clusterReady && currentProduct && currentProduct.showWorkspaceSwitcher && showWorkspaceSwitcher" />
602
+ <WorkspaceSwitcher
603
+ v-else-if="clusterReady && showWorkspaceSwitcher"
604
+ :disabled="disableWorkspaceSwitcher"
605
+ />
585
606
  </div>
586
607
  <div
587
608
  v-if="currentCluster && !simple"
@@ -1005,8 +1005,8 @@ export default {
1005
1005
  .ns-filter-clear {
1006
1006
  cursor: pointer;
1007
1007
  position: absolute;
1008
- right: 10px;
1009
- top: 10px;
1008
+ right: 12px;
1009
+ top: 5px;
1010
1010
  line-height: 24px;
1011
1011
  text-align: center;
1012
1012
  width: 14px;
@@ -246,7 +246,10 @@ const findNewIndex = (shouldAdvance: boolean, activeIndex: number, itemsArr: Ele
246
246
  :class="clz"
247
247
  />
248
248
  </div>
249
- <div class="item-title">
249
+ <div
250
+ v-clean-tooltip="item.title"
251
+ class="item-title"
252
+ >
250
253
  {{ item.title }}
251
254
  </div>
252
255
  <button
@@ -2,17 +2,19 @@
2
2
  import { useStore } from 'vuex';
3
3
  import { computed, inject, ref } from 'vue';
4
4
  import { DropdownContext, defaultContext } from '@components/RcDropdown/types';
5
+ import RcButton from '@components/RcButton/RcButton.vue';
6
+ import { RcButtonType } from '@components/RcButton/types';
5
7
 
6
8
  const { dropdownItems } = inject<DropdownContext>('dropdownContext') || defaultContext;
7
9
  const store = useStore();
8
10
  const unreadCount = computed<number>(() => store.getters['notifications/unreadCount']);
9
- const markAllReadButton = ref<HTMLElement>();
11
+ const markAllReadButton = ref<RcButtonType | null>(null);
10
12
 
11
13
  const markAllRead = (keyboard: boolean) => {
12
14
  store.dispatch('notifications/markAllRead');
13
15
 
14
- // If we have focus, then move to the next item if activated by the keyboard
15
- if (keyboard && document.activeElement === markAllReadButton?.value) {
16
+ // If activated via keyboard, move focus to the next dropdown item
17
+ if (keyboard) {
16
18
  moveFocus(true);
17
19
  }
18
20
  };
@@ -65,18 +67,19 @@ const gotFocus = (e: Event) => {
65
67
  {{ t('notificationCenter.title') }}
66
68
  </div>
67
69
  <div v-if="unreadCount !== 0">
68
- <a
70
+ <RcButton
69
71
  ref="markAllReadButton"
70
- role="button"
72
+ variant="ghost"
73
+ size="small"
71
74
  tabindex="-1"
72
- href="#"
75
+ class="mark-all-read"
73
76
  data-testid="notifications-center-markall-read"
74
77
  @keydown.up.down.stop.prevent="handleKeydown"
75
78
  @keydown.enter.space.stop="markAllRead(true)"
76
79
  @click="markAllRead(false)"
77
80
  >
78
81
  {{ t('notificationCenter.markAllRead') }}
79
- </a>
82
+ </RcButton>
80
83
  </div>
81
84
  </div>
82
85
  <div class="notification-border" />
@@ -104,8 +107,17 @@ const gotFocus = (e: Event) => {
104
107
  flex: 1;
105
108
  }
106
109
 
107
- A {
110
+ .mark-all-read {
111
+ padding: 0;
112
+ min-height: auto;
113
+ font-size: inherit;
114
+ line-height: inherit;
108
115
  color: var(--link);
116
+
117
+ &:hover {
118
+ color: var(--body-text);
119
+ text-decoration: underline;
120
+ }
109
121
  }
110
122
  }
111
123
  }
@@ -0,0 +1,80 @@
1
+ import { ref } from 'vue';
2
+ import { mount, shallowMount } from '@vue/test-utils';
3
+ import NotificationHeader from '@shell/components/nav/NotificationCenter/NotificationHeader.vue';
4
+ import { defaultContext } from '@components/RcDropdown/types';
5
+
6
+ const buildStore = (unreadCount = 1) => {
7
+ const dispatch = jest.fn();
8
+ const store = {
9
+ dispatch,
10
+ getters: { 'notifications/unreadCount': unreadCount },
11
+ };
12
+
13
+ return { store, dispatch };
14
+ };
15
+
16
+ const buildGlobal = (store: any) => ({
17
+ provide: {
18
+ store,
19
+ dropdownContext: { ...defaultContext, dropdownItems: ref<HTMLElement[]>([]) },
20
+ },
21
+ mocks: { $store: store },
22
+ });
23
+
24
+ jest.mock('vuex', () => ({ useStore: () => (globalThis as any).__testStore }));
25
+
26
+ describe('component: NotificationHeader', () => {
27
+ afterEach(() => {
28
+ (globalThis as any).__testStore = undefined;
29
+ });
30
+
31
+ it('renders the mark all read action when there are unread notifications', () => {
32
+ const { store } = buildStore(3);
33
+
34
+ (globalThis as any).__testStore = store;
35
+
36
+ const wrapper = shallowMount(NotificationHeader, { global: buildGlobal(store) });
37
+
38
+ expect(wrapper.find('[data-testid="notifications-center-markall-read"]').exists()).toBe(true);
39
+ });
40
+
41
+ it('hides the mark all read action when there are no unread notifications', () => {
42
+ const { store } = buildStore(0);
43
+
44
+ (globalThis as any).__testStore = store;
45
+
46
+ const wrapper = shallowMount(NotificationHeader, { global: buildGlobal(store) });
47
+
48
+ expect(wrapper.find('[data-testid="notifications-center-markall-read"]').exists()).toBe(false);
49
+ });
50
+
51
+ it('dispatches notifications/markAllRead when clicked', async() => {
52
+ const { store, dispatch } = buildStore(2);
53
+
54
+ (globalThis as any).__testStore = store;
55
+
56
+ const wrapper = mount(NotificationHeader, { global: buildGlobal(store) });
57
+
58
+ await wrapper.find('[data-testid="notifications-center-markall-read"]').trigger('click');
59
+
60
+ expect(dispatch).toHaveBeenCalledWith('notifications/markAllRead');
61
+ });
62
+
63
+ // Regression test for https://github.com/rancher/dashboard/issues/16923
64
+ // "Mark all as read" was originally an <a href="#"> which, on click, navigated
65
+ // to "#" and stripped any existing URL hash fragment (e.g. #pod). Rendering it
66
+ // as a <button> (via RcButton) removes the default navigation behavior entirely,
67
+ // so the URL hash is preserved and extensions scoped via LocationConfig.hash
68
+ // continue to match after activation.
69
+ it('renders mark all read as a <button> so activating it cannot strip the URL hash', () => {
70
+ const { store } = buildStore(2);
71
+
72
+ (globalThis as any).__testStore = store;
73
+
74
+ const wrapper = mount(NotificationHeader, { global: buildGlobal(store) });
75
+ const markAll = wrapper.find('[data-testid="notifications-center-markall-read"]');
76
+
77
+ expect(markAll.element.tagName).toBe('BUTTON');
78
+ expect(markAll.attributes('href')).toBeUndefined();
79
+ });
80
+ });
@@ -35,7 +35,18 @@ interface UpdateArgs {
35
35
  }
36
36
 
37
37
  type MgmtCluster = {
38
- [key: string]: any
38
+ [key: string]: any,
39
+ id: string,
40
+ nameDisplay: string,
41
+ canExplore: boolean,
42
+ providerMenuLogo: string,
43
+ badge: string,
44
+ iconColor: string,
45
+ isLocal: boolean,
46
+ pinned: boolean,
47
+ description: string,
48
+ pin: () => void
49
+ unpin: () => void
39
50
  }
40
51
 
41
52
  type ProvCluster = {
@@ -148,7 +159,8 @@ export abstract class BaseTopLevelMenuHelper {
148
159
  return {
149
160
  id: mgmtCluster.id,
150
161
  label: mgmtCluster.nameDisplay,
151
- ready: mgmtCluster.isReady,
162
+ // Align side nav cluster, home page name link and cluster management cluster explore buttons on canExplore
163
+ ready: mgmtCluster.canExplore,
152
164
  providerNavLogo: mgmtCluster.providerMenuLogo,
153
165
  badge: mgmtCluster.badge,
154
166
  iconColor: mgmtCluster.iconColor,
@@ -488,7 +500,7 @@ export class TopLevelMenuHelperLegacy extends BaseTopLevelMenuHelper implements
488
500
  const maxClustersToShow = args.unPinnedMax || 10;
489
501
 
490
502
  const search = (clusterFilter || '').toLowerCase();
491
- let localCluster: MgmtCluster | null = null;
503
+ let localCluster: TopLevelMenuCluster | null = null;
492
504
 
493
505
  const filtered = clusters.filter((c) => {
494
506
  // If we're searching we don't care if pinned or not
@@ -98,6 +98,17 @@ export default {
98
98
  return count?.summary.count;
99
99
  },
100
100
 
101
+ routeComboActive() {
102
+ if (!this.routeCombo) {
103
+ return false;
104
+ }
105
+
106
+ const ready = [...this.appBar.pinFiltered, ...this.appBar.clustersFiltered].filter((c) => c.ready);
107
+ const readyCount = ready.length;
108
+
109
+ return readyCount > 1 || (readyCount === 1 && this.clusterId !== ready[0].id);
110
+ },
111
+
101
112
  // New
102
113
  search() {
103
114
  return (this.clusterFilter || '').toLowerCase();
@@ -386,7 +397,7 @@ export default {
386
397
  },
387
398
 
388
399
  clusterMenuClick(ev, cluster) {
389
- if (this.routeCombo) {
400
+ if (this.routeComboActive) {
390
401
  ev.preventDefault();
391
402
 
392
403
  if (this.isCurrRouteClusterExplorer && this.productFromRoute === this.currentProduct?.name) {
@@ -423,7 +434,7 @@ export default {
423
434
  },
424
435
 
425
436
  async goToHarvesterCluster() {
426
- const localCluster = this.$store.getters['management/all'](CAPI.RANCHER_CLUSTER).find((C) => C.id === 'fleet-local/local');
437
+ const localCluster = this.$store.getters['management/byId'](CAPI.RANCHER_CLUSTER, 'fleet-local/local');
427
438
 
428
439
  try {
429
440
  await localCluster.goToHarvesterCluster();
@@ -446,7 +457,7 @@ export default {
446
457
  content = this.shown ? null : contentText;
447
458
 
448
459
  // if key combo is pressed, then we update the tooltip as well
449
- } else if (this.routeCombo &&
460
+ } else if (this.routeComboActive &&
450
461
  typeof item === 'object' &&
451
462
  !Array.isArray(item) &&
452
463
  item !== null &&
@@ -706,7 +717,7 @@ export default {
706
717
  <ClusterIconMenu
707
718
  v-clean-tooltip="getTooltipConfig(c, true)"
708
719
  :cluster="c"
709
- :route-combo="routeCombo"
720
+ :route-combo="routeComboActive"
710
721
  class="rancher-provider-icon"
711
722
  />
712
723
  <div
@@ -785,7 +796,7 @@ export default {
785
796
  <ClusterIconMenu
786
797
  v-clean-tooltip="getTooltipConfig(c, true)"
787
798
  :cluster="c"
788
- :route-combo="routeCombo"
799
+ :route-combo="routeComboActive"
789
800
  class="rancher-provider-icon"
790
801
  />
791
802
  <div
@@ -68,8 +68,9 @@ export default {
68
68
  },
69
69
 
70
70
  isActive() {
71
- const typeFullPath = this.$router.resolve(this.typeRoute)?.fullPath.toLowerCase();
72
- const pageFullPath = this.$route.fullPath?.toLowerCase().split('#')[0]; // Ignore the shebang when comparing routes
71
+ // Use .path instead of .fullPath to ignore query parameters and hashes when comparing routes
72
+ const typePath = this.$router.resolve(this.typeRoute)?.path.toLowerCase();
73
+ const pagePath = this.$route.path?.toLowerCase();
73
74
  const routeMetaNav = this.$route.meta?.nav;
74
75
 
75
76
  // If the route explicitly declares the nav path that should be highlighted, then use that
@@ -80,14 +81,14 @@ export default {
80
81
  .replace(':cluster', cluster)
81
82
  .replace(':product', product);
82
83
 
83
- if (navPath === typeFullPath) {
84
+ if (navPath === typePath) {
84
85
  return true;
85
86
  }
86
87
  }
87
88
 
88
89
  if ( !this.type.exact) {
89
- const typeSplit = typeFullPath.split('/');
90
- const pageSplit = pageFullPath.split('/');
90
+ const typeSplit = typePath.split('/');
91
+ const pageSplit = pagePath.split('/');
91
92
 
92
93
  for (let index = 0; index < typeSplit.length; ++index) {
93
94
  if ( index >= pageSplit.length || typeSplit[index] !== pageSplit[index] ) {
@@ -98,7 +99,7 @@ export default {
98
99
  return true;
99
100
  }
100
101
 
101
- return typeFullPath === pageFullPath;
102
+ return typePath === pagePath;
102
103
  },
103
104
 
104
105
  typeRoute() {
@@ -131,7 +132,7 @@ export default {
131
132
  <router-link
132
133
  v-if="type.route"
133
134
  :key="type.name"
134
- v-slot="{ href, navigate,isExactActive }"
135
+ v-slot="{ href, navigate, isExactActive }"
135
136
  custom
136
137
  :to="typeRoute"
137
138
  >
@@ -36,7 +36,7 @@ const props = defineProps({
36
36
 
37
37
  const { loadComponent } = useComponentsMount();
38
38
 
39
- const { isPanelEnabled } = usePanelsHandler({ layout: props.layout, positions: props.positions });
39
+ const { isPanelEnabled } = usePanelsHandler(props);
40
40
  const { tabs } = useTabsHandler();
41
41
  </script>
42
42
 
@@ -66,6 +66,7 @@ const { tabs } = useTabsHandler();
66
66
  :active="true"
67
67
  :height="tab.containerHeight"
68
68
  :width="tab.containerWidth"
69
+ :layout="layout"
69
70
  v-bind="tab.attrs"
70
71
  />
71
72
  </keep-alive>