@rancher/shell 0.3.0 → 0.3.2

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 (342) hide show
  1. package/assets/styles/global/_button.scss +5 -1
  2. package/assets/styles/global/_columns.scss +4 -0
  3. package/assets/styles/global/_gauges.scss +1 -1
  4. package/assets/styles/global/_layout.scss +5 -2
  5. package/assets/styles/global/_select.scss +1 -4
  6. package/assets/styles/themes/_dark.scss +5 -4
  7. package/assets/styles/themes/_light.scss +4 -3
  8. package/assets/styles/themes/_suse.scss +1 -1
  9. package/assets/styles/vendor/vue-select.scss +4 -3
  10. package/assets/translations/en-us.yaml +673 -73
  11. package/assets/translations/zh-hans.yaml +720 -207
  12. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  13. package/cloud-credential/azure.vue +23 -0
  14. package/cloud-credential/harvester.vue +25 -62
  15. package/cloud-credential/pnap.vue +80 -0
  16. package/components/.DS_Store +0 -0
  17. package/components/ActionMenu.vue +28 -7
  18. package/components/AdvancedSection.vue +9 -2
  19. package/components/Alert.vue +2 -2
  20. package/components/ButtonDropdown.vue +0 -2
  21. package/components/ButtonGroup.vue +1 -0
  22. package/components/CollapsibleCard.vue +0 -1
  23. package/components/CruResource.vue +41 -4
  24. package/components/DetailTop.vue +72 -4
  25. package/components/DisableAuthProviderModal.vue +106 -0
  26. package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
  27. package/components/ExplorerMembers.vue +253 -30
  28. package/components/ExplorerProjectsNamespaces.vue +77 -33
  29. package/components/ExtensionPanel.vue +42 -0
  30. package/components/GrowlManager.vue +3 -3
  31. package/components/IconOrSvg.vue +178 -0
  32. package/components/LogItem.vue +69 -0
  33. package/components/PodSecurityAdmission.vue +302 -0
  34. package/components/PromptModal.vue +1 -0
  35. package/components/ResourceDetail/Masthead.vue +69 -4
  36. package/components/ResourceDetail/index.vue +12 -5
  37. package/components/ResourceList/Masthead.vue +11 -1
  38. package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
  39. package/components/ResourceList/index.vue +66 -12
  40. package/components/ResourceList/resource-list.config.js +7 -0
  41. package/components/ResourceTable.vue +33 -6
  42. package/components/SimpleBox.vue +1 -1
  43. package/components/SortableTable/THead.vue +21 -14
  44. package/components/SortableTable/filtering.js +1 -1
  45. package/components/SortableTable/index.vue +21 -10
  46. package/components/SortableTable/selection.js +15 -3
  47. package/components/Tabbed/Tab.vue +1 -1
  48. package/components/Tabbed/index.vue +20 -15
  49. package/components/__tests__/.DS_Store +0 -0
  50. package/components/__tests__/AsyncButton.test.ts +140 -0
  51. package/components/__tests__/BackLink.test.ts +33 -0
  52. package/components/__tests__/ButtonGroup.test.ts +124 -0
  53. package/components/__tests__/ClusterBadge.test.ts +32 -0
  54. package/components/__tests__/CollapsibleCard.test.ts +64 -0
  55. package/components/__tests__/ConsumptionGauge.test.ts +88 -0
  56. package/components/__tests__/CruResource.test.ts +3 -2
  57. package/components/__tests__/FixedBanner.test.ts +129 -0
  58. package/components/__tests__/GrowlManager.test.ts +147 -0
  59. package/components/__tests__/NamespaceFilter.test.ts +33 -25
  60. package/components/__tests__/PercentageBar.test.ts +32 -0
  61. package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
  62. package/components/auth/AuthBanner.vue +20 -10
  63. package/components/auth/RoleDetailEdit.vue +26 -17
  64. package/components/auth/SelectPrincipal.vue +36 -5
  65. package/components/form/ArrayList.vue +3 -35
  66. package/components/form/ArrayListGrouped.vue +13 -4
  67. package/components/form/ArrayListSelect.vue +5 -5
  68. package/components/form/Error.vue +8 -0
  69. package/components/form/KeyValue.vue +39 -7
  70. package/components/form/LabeledSelect.vue +5 -2
  71. package/components/form/Labels.vue +46 -16
  72. package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
  73. package/components/form/Members/MembershipEditor.vue +12 -12
  74. package/components/form/NameNsDescription.vue +1 -1
  75. package/components/form/NodeScheduling.vue +1 -1
  76. package/components/form/Probe.vue +3 -3
  77. package/components/form/ResourceQuota/Project.vue +6 -6
  78. package/components/form/ResourceTabs/index.vue +24 -6
  79. package/components/form/Security.vue +7 -6
  80. package/components/form/Select.vue +3 -2
  81. package/components/form/SelectOrCreateAuthSecret.vue +22 -29
  82. package/components/form/ServicePorts.vue +8 -0
  83. package/components/form/WorkloadPorts.vue +7 -1
  84. package/components/form/__tests__/ArrayList.test.ts +74 -0
  85. package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
  86. package/components/formatter/Checked.vue +1 -1
  87. package/components/formatter/ClusterLink.vue +5 -0
  88. package/components/formatter/IconIsDefault.vue +2 -2
  89. package/components/formatter/InternalExternalIP.vue +11 -8
  90. package/components/formatter/LiveDuration.vue +78 -0
  91. package/components/formatter/WorkloadHealthScale.vue +5 -3
  92. package/components/nav/Header.vue +74 -7
  93. package/components/nav/NamespaceFilter.vue +146 -63
  94. package/components/nav/TopLevelMenu.vue +22 -19
  95. package/components/nav/WindowManager/ContainerLogs.vue +83 -126
  96. package/components/nav/WindowManager/ContainerShell.vue +9 -7
  97. package/components/nav/WindowManager/Window.vue +2 -0
  98. package/components/nav/WindowManager/index.vue +10 -0
  99. package/config/elemental-types.js +9 -0
  100. package/config/features.js +2 -0
  101. package/config/home-links.js +4 -1
  102. package/config/pod-security-admission.ts +82 -0
  103. package/config/product/apps.js +1 -1
  104. package/config/product/auth.js +6 -5
  105. package/config/product/backup.js +1 -1
  106. package/config/product/explorer.js +6 -6
  107. package/config/product/fleet.js +1 -1
  108. package/config/product/manager.js +6 -2
  109. package/config/query-params.js +1 -0
  110. package/config/secret.js +0 -1
  111. package/config/settings.ts +26 -9
  112. package/config/table-headers.js +22 -11
  113. package/config/types.js +4 -1
  114. package/config/uiplugins.js +3 -3
  115. package/content/docs/zh-hans/getting-started.md +113 -137
  116. package/content/docs/zh-hans/whats-new.md +8 -46
  117. package/core/plugin-helpers.js +171 -0
  118. package/core/plugin.ts +61 -1
  119. package/core/plugins.js +33 -0
  120. package/core/types.ts +128 -2
  121. package/creators/pkg/package-lock.json +37 -0
  122. package/creators/pkg/package.json +1 -1
  123. package/detail/catalog.cattle.io.app.vue +1 -1
  124. package/detail/pod.vue +1 -1
  125. package/detail/provisioning.cattle.io.cluster.vue +35 -9
  126. package/detail/service.vue +2 -9
  127. package/detail/workload/index.vue +0 -1
  128. package/dialog/AddClusterMemberDialog.vue +22 -28
  129. package/dialog/AddProjectMemberDialog.vue +53 -9
  130. package/dialog/DiagnosticTimingsDialog.vue +8 -7
  131. package/dialog/DrainNode.vue +44 -48
  132. package/dialog/ForceMachineRemoveDialog.vue +5 -7
  133. package/dialog/GenericPrompt.vue +15 -20
  134. package/dialog/RollbackWorkloadDialog.vue +15 -46
  135. package/dialog/RotateCertificatesDialog.vue +5 -7
  136. package/dialog/RotateEncryptionKeyDialog.vue +5 -9
  137. package/dialog/SaveAsRKETemplateDialog.vue +5 -13
  138. package/dialog/ScaleMachineDownDialog.vue +1 -1
  139. package/dialog/ScalePoolDownDialog.vue +121 -0
  140. package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
  141. package/edit/auth/azuread.vue +16 -16
  142. package/edit/auth/github.vue +8 -0
  143. package/edit/auth/googleoauth.vue +10 -1
  144. package/edit/auth/ldap/index.vue +10 -0
  145. package/edit/auth/oidc.vue +10 -0
  146. package/edit/auth/saml.vue +10 -0
  147. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
  148. package/edit/catalog.cattle.io.clusterrepo.vue +3 -0
  149. package/edit/cloudcredential.vue +3 -7
  150. package/edit/logging-flow/Match.vue +39 -8
  151. package/edit/logging-flow/index.vue +27 -4
  152. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
  153. package/edit/management.cattle.io.project.vue +8 -1
  154. package/edit/management.cattle.io.setting.vue +5 -2
  155. package/edit/management.cattle.io.user.vue +7 -1
  156. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +36 -8
  157. package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
  158. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
  159. package/edit/namespace.vue +18 -4
  160. package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
  161. package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
  162. package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
  163. package/edit/networking.k8s.io.ingress/index.vue +8 -6
  164. package/edit/persistentvolume/index.vue +30 -27
  165. package/edit/persistentvolume/plugins/cephfs.vue +29 -29
  166. package/edit/persistentvolume/plugins/csi.vue +102 -62
  167. package/edit/persistentvolume/plugins/fc.vue +19 -19
  168. package/edit/persistentvolume/plugins/iscsi.vue +45 -45
  169. package/edit/persistentvolume/plugins/rbd.vue +39 -39
  170. package/edit/persistentvolumeclaim.vue +78 -75
  171. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
  172. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
  173. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
  174. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
  175. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +96 -0
  176. package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
  177. package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
  178. package/edit/provisioning.cattle.io.cluster/rke2.vue +445 -154
  179. package/edit/secret/index.vue +3 -7
  180. package/edit/service.vue +3 -1
  181. package/edit/storage.k8s.io.storageclass/index.vue +100 -16
  182. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
  183. package/edit/workload/__tests__/index.test.ts +98 -0
  184. package/edit/workload/index.vue +58 -8
  185. package/edit/workload/mixins/workload.js +107 -70
  186. package/edit/workload/storage/ContainerMountPaths.vue +0 -10
  187. package/edit/workload/storage/emptyDir.vue +88 -0
  188. package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
  189. package/edit/workload/storage/index.vue +8 -0
  190. package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
  191. package/layouts/default.vue +57 -44
  192. package/list/__tests__/workload.test.ts +5 -2
  193. package/list/catalog.cattle.io.app.vue +1 -0
  194. package/list/cis.cattle.io.clusterscan.vue +1 -0
  195. package/list/fleet.cattle.io.bundle.vue +5 -6
  196. package/list/fleet.cattle.io.cluster.vue +6 -3
  197. package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
  198. package/list/fleet.cattle.io.gitrepo.vue +4 -9
  199. package/list/helm.cattle.io.projecthelmchart.vue +1 -5
  200. package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
  201. package/list/logging.banzaicloud.io.flow.vue +6 -5
  202. package/list/management.cattle.io.cluster.vue +1 -0
  203. package/list/management.cattle.io.feature.vue +3 -4
  204. package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
  205. package/list/management.cattle.io.setting.vue +2 -2
  206. package/list/management.cattle.io.user.vue +4 -10
  207. package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
  208. package/list/node.vue +8 -5
  209. package/list/persistentvolume.vue +3 -3
  210. package/list/persistentvolumeclaim.vue +3 -4
  211. package/list/provisioning.cattle.io.cluster.vue +18 -19
  212. package/list/service.vue +6 -14
  213. package/list/workload.vue +43 -38
  214. package/machine-config/azure.vue +429 -60
  215. package/machine-config/pnap.vue +288 -0
  216. package/mixins/auth-config.js +1 -3
  217. package/mixins/browser-tab-visibility.js +8 -14
  218. package/mixins/chart.js +1 -1
  219. package/mixins/create-edit-view/impl.js +4 -0
  220. package/mixins/create-edit-view/index.js +4 -2
  221. package/mixins/resource-fetch-namespaced.js +98 -0
  222. package/mixins/resource-fetch.js +79 -45
  223. package/mixins/resource-manager.js +1 -23
  224. package/models/apps.controllerrevision.js +7 -0
  225. package/models/apps.daemonset.js +18 -0
  226. package/models/apps.deployment.js +44 -0
  227. package/models/apps.replicaset.js +7 -0
  228. package/models/apps.statefulset.js +18 -0
  229. package/models/batch.job.js +7 -14
  230. package/models/cluster/node.js +10 -2
  231. package/models/cluster.x-k8s.io.machine.js +26 -4
  232. package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
  233. package/models/event.js +7 -0
  234. package/models/logging.banzaicloud.io.flow.js +4 -0
  235. package/models/management.cattle.io.cluster.js +1 -1
  236. package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
  237. package/models/management.cattle.io.globalrole.js +2 -2
  238. package/models/management.cattle.io.node.js +37 -2
  239. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
  240. package/models/management.cattle.io.project.js +30 -11
  241. package/models/management.cattle.io.setting.js +1 -1
  242. package/models/management.cattle.io.user.js +37 -1
  243. package/models/namespace.js +42 -5
  244. package/models/persistentvolume.js +14 -2
  245. package/models/pod.js +15 -0
  246. package/models/projectroletemplatebinding.js +7 -0
  247. package/models/provisioning.cattle.io.cluster.js +61 -10
  248. package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
  249. package/models/service.js +14 -13
  250. package/models/storage.k8s.io.storageclass.js +33 -18
  251. package/models/workload.js +38 -7
  252. package/nuxt.config.js +27 -17
  253. package/package.json +7 -7
  254. package/pages/about.vue +14 -2
  255. package/pages/c/_cluster/apps/charts/index.vue +21 -3
  256. package/pages/c/_cluster/apps/charts/install.vue +59 -22
  257. package/pages/c/_cluster/auth/config/_id.vue +6 -0
  258. package/pages/c/_cluster/auth/config/index.vue +8 -6
  259. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  260. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  261. package/pages/c/_cluster/explorer/index.vue +51 -6
  262. package/pages/c/_cluster/longhorn/index.vue +1 -1
  263. package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
  264. package/pages/c/_cluster/monitoring/index.vue +1 -1
  265. package/pages/c/_cluster/neuvector/index.vue +1 -1
  266. package/pages/c/_cluster/settings/performance.vue +48 -2
  267. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +2 -0
  268. package/pages/c/_cluster/uiplugins/InstallDialog.vue +3 -0
  269. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +42 -2
  270. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -0
  271. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +1 -0
  272. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +2 -0
  273. package/pages/c/_cluster/uiplugins/index.vue +42 -3
  274. package/pages/diagnostic.vue +5 -4
  275. package/pages/home.vue +105 -30
  276. package/pages/prefs.vue +23 -12
  277. package/pages/rio/mesh.vue +1 -1
  278. package/pkg/dynamic-importer.lib.js +8 -0
  279. package/pkg/vue.config.js +4 -0
  280. package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
  281. package/plugins/dashboard-store/actions.js +32 -25
  282. package/plugins/dashboard-store/getters.js +50 -33
  283. package/plugins/dashboard-store/mutations.js +134 -28
  284. package/plugins/dashboard-store/resource-class.js +37 -42
  285. package/plugins/steve/actions.js +30 -0
  286. package/plugins/steve/caches/resourceCache.js +60 -0
  287. package/plugins/steve/getters.js +44 -1
  288. package/plugins/steve/mutations.js +97 -36
  289. package/plugins/steve/resourceWatcher.js +277 -0
  290. package/plugins/steve/schema.utils.js +25 -0
  291. package/plugins/steve/subscribe.js +288 -115
  292. package/plugins/steve/worker/index.js +17 -0
  293. package/plugins/steve/worker/web-worker.advanced.js +302 -0
  294. package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
  295. package/rancher-components/Card/Card.vue +3 -3
  296. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
  297. package/rancher-components/StringList/StringList.test.ts +45 -420
  298. package/rancher-components/StringList/StringList.vue +1 -10
  299. package/rancher-components/components/Banner/Banner.test.ts +44 -0
  300. package/rancher-components/components/Banner/Banner.vue +130 -61
  301. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
  302. package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
  303. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
  304. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
  305. package/rancher-components/components/StringList/StringList.test.ts +7 -7
  306. package/rancher-components/components/StringList/StringList.vue +21 -15
  307. package/scripts/test-plugins-build.sh +8 -0
  308. package/static/loading-indicator.html +1 -1
  309. package/store/action-menu.js +4 -3
  310. package/store/index.js +54 -3
  311. package/store/plugins.js +0 -17
  312. package/store/pnap.js +128 -0
  313. package/store/prefs.js +4 -2
  314. package/store/type-map.js +81 -13
  315. package/types/pod-security-admission.ts +36 -0
  316. package/types/shell/index.d.ts +497 -396
  317. package/utils/__tests__/object.test.ts +17 -1
  318. package/utils/__tests__/pod-security-admission.test.ts +61 -0
  319. package/utils/async.ts +36 -0
  320. package/utils/color.js +45 -0
  321. package/utils/crypto/browserHashUtils.js +18 -0
  322. package/utils/dynamic-importer.js +8 -0
  323. package/utils/install-redirect.js +1 -1
  324. package/utils/object.js +24 -0
  325. package/utils/pod-security-admission.ts +39 -0
  326. package/utils/socket.js +61 -24
  327. package/utils/string.js +2 -0
  328. package/utils/svg-filter.js +301 -0
  329. package/utils/time.js +49 -0
  330. package/utils/validators/cidr.js +4 -0
  331. package/utils/validators/formRules/__tests__/index.test.ts +23 -3
  332. package/utils/validators/formRules/index.ts +14 -0
  333. package/config/product/harvester-manager.js +0 -162
  334. package/edit/harvesterhci.io.management.cluster.vue +0 -153
  335. package/list/harvesterhci.io.management.cluster.vue +0 -241
  336. package/machine-config/harvester.vue +0 -693
  337. package/models/harvesterhci.io.management.cluster.js +0 -228
  338. package/pages/c/_cluster/harvesterManager/index.vue +0 -24
  339. package/rancher-components/Card/Card.test.ts +0 -39
  340. package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
  341. package/rancher-components/Utils/DraggableZone/index.ts +0 -1
  342. package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
@@ -3,7 +3,7 @@ import { mapGetters } from 'vuex';
3
3
  import debounce from 'lodash/debounce';
4
4
  import { NORMAN, STEVE } from '@shell/config/types';
5
5
  import { ucFirst } from '@shell/utils/string';
6
- import { isMac } from '@shell/utils/platform';
6
+ import { isAlternate, isMac } from '@shell/utils/platform';
7
7
  import Import from '@shell/components/Import';
8
8
  import BrandImage from '@shell/components/BrandImage';
9
9
  import { getProduct } from '@shell/config/private-label';
@@ -15,6 +15,9 @@ import WorkspaceSwitcher from './WorkspaceSwitcher';
15
15
  import TopLevelMenu from './TopLevelMenu';
16
16
  import Jump from './Jump';
17
17
  import { allHash } from '@shell/utils/promise';
18
+ import { ActionLocation, ExtensionPoint } from '@shell/core/types';
19
+ import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
20
+ import IconOrSvg from '@shell/components/IconOrSvg';
18
21
 
19
22
  const PAGE_HEADER_ACTION = 'page-action';
20
23
 
@@ -29,6 +32,7 @@ export default {
29
32
  BrandImage,
30
33
  ClusterBadge,
31
34
  ClusterProviderIcon,
35
+ IconOrSvg
32
36
  },
33
37
 
34
38
  props: {
@@ -43,13 +47,15 @@ export default {
43
47
  const shellShortcut = '(Ctrl+`)';
44
48
 
45
49
  return {
46
- show: false,
47
- showTooltip: false,
48
- kubeConfigCopying: false,
50
+ show: false,
51
+ showTooltip: false,
52
+ kubeConfigCopying: false,
49
53
  searchShortcut,
50
54
  shellShortcut,
51
55
  LOGGED_OUT,
52
- navHeaderRight: null
56
+ navHeaderRight: null,
57
+ extensionHeaderActions: getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, this.$route),
58
+ ctx: this
53
59
  };
54
60
  },
55
61
 
@@ -170,6 +176,12 @@ export default {
170
176
  if (nue && old && nue.id !== old.id) {
171
177
  this.checkClusterName();
172
178
  }
179
+ },
180
+ // since the Header is a "persistent component" we need to update it at every route change...
181
+ $route(nue) {
182
+ if (nue) {
183
+ this.extensionHeaderActions = getApplicableExtensionEnhancements(this, ExtensionPoint.ACTION, ActionLocation.HEADER, nue);
184
+ }
173
185
  }
174
186
  },
175
187
 
@@ -288,6 +300,33 @@ export default {
288
300
  button.classList.remove('header-btn-active');
289
301
  }
290
302
  });
303
+ },
304
+
305
+ handleExtensionAction(action, event) {
306
+ const fn = action.invoke;
307
+ const opts = {
308
+ event,
309
+ action,
310
+ isAlt: isAlternate(event),
311
+ product: this.currentProduct.name,
312
+ cluster: this.currentCluster,
313
+ };
314
+ const enabled = action.enabled ? action.enabled.apply(this, [opts]) : true;
315
+
316
+ if (fn && enabled) {
317
+ fn.apply(this, [opts, []]);
318
+ }
319
+ },
320
+
321
+ handleExtensionTooltip(action) {
322
+ if (action.tooltipKey || action.tooltip) {
323
+ const tooltip = action.tooltipKey ? this.t(action.tooltipKey) : action.tooltip;
324
+ const shortcut = action.shortcutLabel ? action.shortcutLabel() : '';
325
+
326
+ return `${ tooltip } ${ shortcut }`;
327
+ }
328
+
329
+ return null;
291
330
  }
292
331
  }
293
332
  };
@@ -502,6 +541,31 @@ export default {
502
541
  </modal>
503
542
  </div>
504
543
 
544
+ <!-- Extension header actions -->
545
+ <div
546
+ v-if="extensionHeaderActions.length"
547
+ class="header-buttons"
548
+ >
549
+ <button
550
+ v-for="action, i in extensionHeaderActions"
551
+ :key="`${action.label}${i}`"
552
+ v-tooltip="handleExtensionTooltip(action)"
553
+ v-shortkey="action.shortcutKey"
554
+ :disabled="action.enabled ? !action.enabled(ctx) : false"
555
+ type="button"
556
+ class="btn header-btn role-tertiary"
557
+ @shortkey="handleExtensionAction(action, $event)"
558
+ @click="handleExtensionAction(action, $event)"
559
+ >
560
+ <IconOrSvg
561
+ class="icon icon-lg"
562
+ :icon="action.icon"
563
+ :src="action.svg"
564
+ color="header"
565
+ />
566
+ </button>
567
+ </div>
568
+
505
569
  <div
506
570
  v-if="showPageActions"
507
571
  id="page-actions"
@@ -671,8 +735,6 @@ export default {
671
735
 
672
736
  .vs__dropdown-toggle .vs__actions:after {
673
737
  color: var(--body-text) !important;
674
- font-size: 1.5rem;
675
- padding-right: 4px;
676
738
  }
677
739
 
678
740
  .vs__dropdown-toggle {
@@ -816,6 +878,11 @@ export default {
816
878
  background-color: var(--success);
817
879
  color: var(--success-text);
818
880
  }
881
+
882
+ img {
883
+ height: 20px;
884
+ width: 20px;
885
+ }
819
886
  }
820
887
  }
821
888
 
@@ -19,16 +19,17 @@ import { KEY } from '@shell/utils/platform';
19
19
  export default {
20
20
  data() {
21
21
  return {
22
- isOpen: false,
23
- filter: '',
24
- hidden: 0,
25
- total: 0,
26
- activeElement: null,
22
+ isOpen: false,
23
+ filter: '',
24
+ hidden: 0,
25
+ total: 0,
26
+ activeElement: null,
27
+ cachedFiltered: [],
27
28
  };
28
29
  },
29
30
 
30
31
  computed: {
31
- ...mapGetters(['currentProduct']),
32
+ ...mapGetters(['currentProduct', 'namespaceFilterMode']),
32
33
 
33
34
  hasFilter() {
34
35
  return this.filter.length > 0;
@@ -37,11 +38,26 @@ export default {
37
38
  filtered() {
38
39
  let out = this.options;
39
40
 
40
- // Filter by the current filter
41
- if (this.hasFilter) {
42
- out = out.filter((item) => {
41
+ out = out.filter((item) => {
42
+ // Filter out anything not applicable to singleton selection
43
+ if (this.namespaceFilterMode) {
44
+ // We always show dividers, projects and namespaces
45
+ if (!['divider', 'project', this.namespaceFilterMode].includes(item.kind)) {
46
+ // Hide any invalid option that's not selected
47
+ return this.value.findIndex(v => v.id === item.id) >= 0;
48
+ }
49
+ }
50
+
51
+ // Filter by the current filter
52
+ if (this.hasFilter) {
43
53
  return item.kind !== SPECIAL && item.label.toLowerCase().includes(this.filter.toLowerCase());
44
- });
54
+ }
55
+
56
+ return true;
57
+ });
58
+
59
+ if (out?.[0]?.kind === 'divider') {
60
+ out.splice(0, 1);
45
61
  }
46
62
 
47
63
  const mapped = this.value.reduce((m, v) => {
@@ -54,6 +70,8 @@ export default {
54
70
  out.forEach((i) => {
55
71
  i.selected = !!mapped[i.id] || (i.id === ALL && this.value && this.value.length === 0);
56
72
  i.elementId = (i.id || '').replace('://', '_');
73
+ // Are we in singleton resource type mode, if so is this an allowed type?
74
+ i.enabled = !this.namespaceFilterMode || i.kind === this.namespaceFilterMode;
57
75
  });
58
76
 
59
77
  return out;
@@ -326,6 +344,21 @@ export default {
326
344
  watch: {
327
345
  value(neu) {
328
346
  this.layout();
347
+ },
348
+
349
+ /**
350
+ * When there are thousands of entries certain actions (drop down opened, selection changed, etc) take a long time to complete (upwards
351
+ * of 5 seconds)
352
+ *
353
+ * This is caused by churn of the filtered and options computed properties causing multiple renders for each action.
354
+ *
355
+ * To break this multiple-render per cycle behaviour detatch `filtered` from the value used in `v-for`.
356
+ *
357
+ */
358
+ filtered(neu) {
359
+ if (!!neu) {
360
+ this.cachedFiltered = neu;
361
+ }
329
362
  }
330
363
  },
331
364
 
@@ -427,7 +460,10 @@ export default {
427
460
  e.preventDefault();
428
461
  e.stopPropagation();
429
462
  this.up();
430
- } else if (e.keyCode === KEY.SPACE) {
463
+ } else if (e.keyCode === KEY.SPACE || e.keyCode === KEY.CR) {
464
+ if (this.namespaceFilterMode && !opt.enabled) {
465
+ return;
466
+ }
431
467
  e.preventDefault();
432
468
  e.stopPropagation();
433
469
  this.selectOption(opt);
@@ -545,9 +581,22 @@ export default {
545
581
 
546
582
  const current = this.value;
547
583
  const exists = current.findIndex(v => v.id === option.id);
584
+ const optionIsSelected = exists !== -1;
585
+
586
+ // Any type of mode means only a single resource can be selected. So clear out any stale
587
+ // values (multiple selected in another context OR a single one selected in this context)
588
+ if (this.namespaceFilterMode) {
589
+ if (current.length === 1 && optionIsSelected) {
590
+ // Don't deselect the only selected option
591
+ return;
592
+ }
593
+ current.length = 0;
594
+ }
548
595
 
549
- // Remove if it exists, add if it does not
550
- if (exists !== -1) {
596
+ const remove = !this.namespaceFilterMode && optionIsSelected;
597
+
598
+ // Remove if it exists (or always add if in singleton mode - we've reset the list above)
599
+ if (remove) {
551
600
  current.splice(exists, 1);
552
601
  } else {
553
602
  current.push(option);
@@ -559,6 +608,14 @@ export default {
559
608
  document.activeElement.blur();
560
609
  }
561
610
  },
611
+ handleValueMouseDown(ns, event) {
612
+ this.removeOption(ns, event);
613
+
614
+ if (this.value.length === 0) {
615
+ this.open();
616
+ }
617
+ },
618
+
562
619
  removeOption(ns, event) {
563
620
  this.selectOption(ns);
564
621
  event.preventDefault();
@@ -634,9 +691,11 @@ export default {
634
691
  >
635
692
  <div>{{ ns.label }}</div>
636
693
  <i
694
+ v-if="!namespaceFilterMode"
637
695
  class="icon icon-close"
638
696
  :data-testid="`namespaces-values-close-${j}`"
639
697
  @click="removeOption(ns, $event)"
698
+ @mousedown="handleValueMouseDown(ns, $event)"
640
699
  />
641
700
  </div>
642
701
  </div>
@@ -686,7 +745,19 @@ export default {
686
745
  @click="filter = ''"
687
746
  />
688
747
  </div>
689
- <div class="ns-clear">
748
+ <div
749
+ v-if="namespaceFilterMode"
750
+ class="ns-singleton-info"
751
+ >
752
+ <i
753
+ v-tooltip="t('resourceList.nsFilterToolTip', { mode: namespaceFilterMode})"
754
+ class="icon icon-info"
755
+ />
756
+ </div>
757
+ <div
758
+ v-else
759
+ class="ns-clear"
760
+ >
690
761
  <i
691
762
  class="icon icon-close"
692
763
  @click="clear()"
@@ -700,18 +771,19 @@ export default {
700
771
  role="list"
701
772
  >
702
773
  <div
703
- v-for="(opt, i) in filtered"
774
+ v-for="(opt, i) in cachedFiltered"
704
775
  :id="opt.elementId"
705
776
  :key="opt.id"
706
777
  tabindex="0"
707
778
  class="ns-option"
779
+ :disabled="!opt.enabled"
708
780
  :class="{
709
781
  'ns-selected': opt.selected,
710
- 'ns-single-match': filtered.length === 1 && !opt.selected,
782
+ 'ns-single-match': cachedFiltered.length === 1 && !opt.selected,
711
783
  }"
712
784
  :data-testid="`namespaces-option-${i}`"
713
- @click="selectOption(opt)"
714
- @mouseover="mouseOver($event)"
785
+ @click="opt.enabled && selectOption(opt)"
786
+ @mouseover="opt.enabled && mouseOver($event)"
715
787
  @keydown="itemKeyHandler($event, opt)"
716
788
  >
717
789
  <div
@@ -734,7 +806,7 @@ export default {
734
806
  </div>
735
807
  </div>
736
808
  <div
737
- v-if="filtered.length === 0"
809
+ v-if="cachedFiltered.length === 0"
738
810
  class="ns-none"
739
811
  data-testid="namespaces-option-none"
740
812
  >
@@ -775,16 +847,17 @@ export default {
775
847
  }
776
848
 
777
849
  .ns-clear {
850
+ &:hover {
851
+ color: var(--primary);
852
+ cursor: pointer;
853
+ }
854
+ }
855
+
856
+ .ns-singleton-info, .ns-clear {
778
857
  align-items: center;
779
858
  display: flex;
780
859
  > i {
781
- font-size: 24px;
782
- padding: 0 5px;
783
- }
784
-
785
- &:hover {
786
- color: var(--link);
787
- cursor: pointer;
860
+ padding-right: 5px;
788
861
  }
789
862
  }
790
863
 
@@ -803,7 +876,6 @@ export default {
803
876
  position: absolute;
804
877
  right: 10px;
805
878
  top: 5px;
806
- font-size: 16px;
807
879
  line-height: 24px;
808
880
  text-align: center;
809
881
  width: 24px;
@@ -811,7 +883,7 @@ export default {
811
883
 
812
884
  .ns-dropdown-menu {
813
885
  background-color: var(--header-bg);
814
- border: 1px solid var(--link-border);
886
+ border: 1px solid var(--primary-border);
815
887
  border-bottom-left-radius: var(--border-radius);
816
888
  border-bottom-right-radius: var(--border-radius);
817
889
  color: var(--header-btn-text);
@@ -837,12 +909,49 @@ export default {
837
909
  padding-bottom: 10px;
838
910
  }
839
911
 
840
- .ns-option:focus {
841
- background-color: var(--dropdown-hover-bg);
842
- color: var(--dropdown-hover-text);
843
- }
844
-
845
912
  .ns-option {
913
+
914
+ &[disabled] {
915
+ cursor: default;
916
+ }
917
+
918
+ &:not([disabled]) {
919
+ &:focus {
920
+ background-color: var(--dropdown-hover-bg);
921
+ color: var(--dropdown-hover-text);
922
+ }
923
+ .ns-item {
924
+ &:hover, &:focus {
925
+ background-color: var(--dropdown-hover-bg);
926
+ color: var(--dropdown-hover-text);
927
+ cursor: pointer;
928
+
929
+ > i {
930
+ color: var(--dropdown-hover-text);
931
+ }
932
+ }
933
+ }
934
+
935
+ &.ns-selected {
936
+ &:hover,&:focus {
937
+ .ns-item {
938
+ > * {
939
+ background-color: var(--dropdown-hover-bg);
940
+ color: var(--dropdown-hover-text);
941
+ }
942
+ }
943
+ }
944
+ }
945
+
946
+ &.ns-selected:not(:hover) {
947
+ .ns-item {
948
+ > * {
949
+ color: var(--dropdown-hover-bg);
950
+ }
951
+ }
952
+ }
953
+ }
954
+
846
955
  .ns-item {
847
956
  align-items: center;
848
957
  display: flex;
@@ -862,33 +971,8 @@ export default {
862
971
  white-space: nowrap;
863
972
  }
864
973
 
865
- &:hover, &:focus {
866
- background-color: var(--dropdown-hover-bg);
867
- color: var(--dropdown-hover-text);
868
- cursor: pointer;
869
-
870
- > i {
871
- color: var(--dropdown-hover-text);
872
- }
873
- }
874
- }
875
- &.ns-selected:not(:hover) {
876
- .ns-item {
877
- > * {
878
- color: var(--dropdown-hover-bg);
879
- }
880
- }
881
- }
882
- &.ns-selected {
883
- &:hover,&:focus {
884
- .ns-item {
885
- > * {
886
- background-color: var(--dropdown-hover-bg);
887
- color: var(--dropdown-hover-text);
888
- }
889
- }
890
- }
891
974
  }
975
+
892
976
  &.ns-single-match {
893
977
  .ns-item {
894
978
  background-color: var(--dropdown-hover-bg);
@@ -915,7 +999,7 @@ export default {
915
999
  &.ns-open {
916
1000
  border-bottom-left-radius: 0;
917
1001
  border-bottom-right-radius: 0;
918
- border-color: var(--link-border);
1002
+ border-color: var(--primary-border);
919
1003
  }
920
1004
 
921
1005
  > .ns-values {
@@ -924,14 +1008,13 @@ export default {
924
1008
 
925
1009
  &:hover {
926
1010
  > i {
927
- color: var(--link);
1011
+ color: var(--primary);
928
1012
  }
929
1013
  }
930
1014
 
931
1015
  > i {
932
1016
  height: $ns_dropdown_size;
933
1017
  width: $ns_dropdown_size;
934
- font-size: 20px;
935
1018
  cursor: pointer;
936
1019
  text-align: center;
937
1020
  line-height: $ns_dropdown_size;
@@ -963,7 +1046,7 @@ export default {
963
1046
  margin-left: 5px;
964
1047
 
965
1048
  &:hover {
966
- color: var(--link);
1049
+ color: var(--primary);
967
1050
  };
968
1051
  }
969
1052
 
@@ -1,6 +1,7 @@
1
1
  <script>
2
2
  import BrandImage from '@shell/components/BrandImage';
3
3
  import ClusterProviderIcon from '@shell/components/ClusterProviderIcon';
4
+ import IconOrSvg from '../IconOrSvg';
4
5
  import { mapGetters } from 'vuex';
5
6
  import $ from 'jquery';
6
7
  import { CAPI, MANAGEMENT } from '@shell/config/types';
@@ -14,13 +15,13 @@ import { SETTING } from '@shell/config/settings';
14
15
  import { filterOnlyKubernetesClusters, filterHiddenLocalCluster } from '@shell/utils/cluster';
15
16
  import { isRancherPrime } from '@shell/config/version';
16
17
 
17
- const UNKNOWN = 'unknown';
18
- const UI_VERSION = process.env.VERSION || UNKNOWN;
19
- const UI_COMMIT = process.env.COMMIT || UNKNOWN;
20
-
21
18
  export default {
22
19
 
23
- components: { BrandImage, ClusterProviderIcon },
20
+ components: {
21
+ BrandImage,
22
+ ClusterProviderIcon,
23
+ IconOrSvg
24
+ },
24
25
 
25
26
  data() {
26
27
  const { displayVersion, fullVersion } = getVersionInfo(this.$store);
@@ -30,8 +31,6 @@ export default {
30
31
  shown: false,
31
32
  displayVersion,
32
33
  fullVersion,
33
- uiCommit: UI_COMMIT,
34
- uiVersion: UI_VERSION,
35
34
  clusterFilter: '',
36
35
  hasProvCluster,
37
36
  };
@@ -145,6 +144,7 @@ export default {
145
144
  return {
146
145
  label: this.$store.getters['i18n/withFallback'](`product."${ p.name }"`, null, ucFirst(p.name)),
147
146
  icon: `icon-${ p.icon || 'copy' }`,
147
+ svg: p.svg,
148
148
  value: p.name,
149
149
  removable: p.removable !== false,
150
150
  inStore: p.inStore || 'cluster',
@@ -347,9 +347,9 @@ export default {
347
347
  class="option"
348
348
  :to="a.to"
349
349
  >
350
- <i
351
- class="icon group-icon"
352
- :class="a.icon"
350
+ <IconOrSvg
351
+ :icon="a.icon"
352
+ :src="a.svg"
353
353
  />
354
354
  <div>{{ a.label }}</div>
355
355
  </nuxt-link>
@@ -368,9 +368,9 @@ export default {
368
368
  class="option"
369
369
  :to="a.to"
370
370
  >
371
- <i
372
- class="icon group-icon"
373
- :class="a.icon"
371
+ <IconOrSvg
372
+ :icon="a.icon"
373
+ :src="a.svg"
374
374
  />
375
375
  <div>{{ a.label }}</div>
376
376
  </nuxt-link>
@@ -389,9 +389,9 @@ export default {
389
389
  class="option"
390
390
  :to="a.to"
391
391
  >
392
- <i
393
- class="icon group-icon"
394
- :class="a.icon"
392
+ <IconOrSvg
393
+ :icon="a.icon"
394
+ :src="a.svg"
395
395
  />
396
396
  <div>{{ a.label }}</div>
397
397
  </nuxt-link>
@@ -410,11 +410,11 @@ export default {
410
410
  </div>
411
411
  <div @click="hide()">
412
412
  <nuxt-link
413
- v-tooltip="{ content: fullVersion, classes: 'footer-tooltip' }"
414
413
  :to="{ name: 'about' }"
415
414
  class="version"
416
- v-html="displayVersion"
417
- />
415
+ >
416
+ {{ t('about.title') }}
417
+ </nuxt-link>
418
418
  </div>
419
419
  </div>
420
420
  </div>
@@ -505,6 +505,9 @@ export default {
505
505
  margin-right: 8px;
506
506
  fill: var(--link);
507
507
  }
508
+ img {
509
+ margin-right: 8px;
510
+ }
508
511
 
509
512
  > div {
510
513
  color: var(--link);