dashboard-shell-shell 1.0.122 → 1.0.1000000081

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 (372) hide show
  1. package/.DS_Store +0 -0
  2. package/assets/brand/harvester/favicon.png +0 -0
  3. package/assets/brand/suse/favicon.png +0 -0
  4. package/assets/icons/iconfont.css +19 -3
  5. package/assets/icons/iconfont.js +1 -1
  6. package/assets/icons/iconfont.json +28 -0
  7. package/assets/icons/iconfont.ttf +0 -0
  8. package/assets/icons/iconfont.woff +0 -0
  9. package/assets/icons/iconfont.woff2 +0 -0
  10. package/assets/images/pl/half-logo.svg +2 -23
  11. package/assets/styles/base/_functions.scss +0 -0
  12. package/assets/styles/base/_mixins.scss +0 -0
  13. package/assets/styles/base/_variables.scss +1 -1
  14. package/assets/styles/global/_labeled-input.scss +0 -1
  15. package/assets/styles/global/_layout.scss +1 -1
  16. package/assets/styles/global/_select.scss +4 -2
  17. package/assets/styles/global/_table.scss +5 -0
  18. package/assets/styles/vendor/vue-select.scss +2 -1
  19. package/assets/translations/en-us.yaml +1 -1
  20. package/assets/translations/zh-hans.yaml +25 -15
  21. package/chart/monitoring/index.vue +3 -1
  22. package/chart/monitoring/prometheus/index.vue +13 -10
  23. package/cloud-credential/aws.vue +2 -0
  24. package/components/ActionDropdown.vue +1 -1
  25. package/components/ActionDropdownShell.vue +71 -0
  26. package/components/ActionMenu.vue +2 -2
  27. package/components/ActionMenuShell.vue +3 -0
  28. package/components/AppModal.vue +84 -8
  29. package/components/AssignTo.vue +25 -11
  30. package/components/AsyncButton.vue +24 -7
  31. package/components/BannerGraphic.vue +1 -0
  32. package/components/ButtonDropdown.vue +26 -4
  33. package/components/ButtonGroup.vue +4 -0
  34. package/components/ButtonMultiAction.vue +1 -0
  35. package/components/CodeMirror.vue +19 -6
  36. package/components/CommunityLinks.vue +3 -3
  37. package/components/ConsumptionGauge.vue +24 -5
  38. package/components/CopyToClipboardText.vue +2 -1
  39. package/components/CruResource.vue +13 -7
  40. package/components/CruResourceFooter.vue +2 -2
  41. package/components/DashboardOptions.vue +29 -17
  42. package/components/DetailText.vue +5 -0
  43. package/components/DisableAuthProviderModal.vue +1 -0
  44. package/components/DotState.vue +84 -0
  45. package/components/ExplorerMembers.vue +1 -1
  46. package/components/ExplorerProjectsNamespaces.vue +89 -16
  47. package/components/FixedBanner.vue +19 -12
  48. package/components/GlobalRoleBindings.vue +5 -1
  49. package/components/GrafanaDashboard.vue +4 -4
  50. package/components/GrowlManager.vue +4 -1
  51. package/components/HardwareResourceGauge.vue +39 -3
  52. package/components/InfoBox.vue +3 -3
  53. package/components/InputOrDisplay.vue +28 -2
  54. package/components/LabelValue.vue +20 -1
  55. package/components/LandingPagePreference.vue +5 -3
  56. package/components/LocaleSelector.vue +39 -93
  57. package/components/ModalManager.vue +55 -0
  58. package/components/ModalWithCard.vue +13 -3
  59. package/components/MoveModal.vue +1 -0
  60. package/components/PodSecurityAdmission.vue +1 -1
  61. package/components/PromptChangePassword.vue +1 -1
  62. package/components/PromptModal.vue +16 -3
  63. package/components/PromptRemove.vue +29 -9
  64. package/components/PromptRestore.vue +1 -0
  65. package/components/ResourceCancelModal.vue +1 -0
  66. package/components/ResourceDetail/Masthead.vue +52 -17
  67. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  68. package/components/ResourceDetail/index.vue +54 -16
  69. package/components/ResourceList/Masthead.vue +9 -4
  70. package/components/ResourceList/index.vue +4 -3
  71. package/components/ResourceTable.vue +1 -0
  72. package/components/SideNav.vue +20 -15
  73. package/components/SlideInPanelManager.vue +126 -0
  74. package/components/SortableTable/THead.vue +10 -4
  75. package/components/SortableTable/actions.js +1 -1
  76. package/components/SortableTable/index.vue +540 -553
  77. package/components/SortableTable/selection.js +2 -13
  78. package/components/StatusBadge.vue +77 -0
  79. package/components/Tabbed/Tab.vue +3 -3
  80. package/components/Tabbed/index.vue +47 -29
  81. package/components/Wizard.vue +2 -2
  82. package/components/YamlEditor.vue +1 -1
  83. package/components/__tests__/AsyncButton.test.ts +2 -2
  84. package/components/__tests__/FixedBanner.test.ts +3 -3
  85. package/components/__tests__/ModalManager.spec.ts +176 -0
  86. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  87. package/components/auth/Principal.vue +10 -3
  88. package/components/auth/RoleDetailEdit.vue +1 -1
  89. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  90. package/components/form/ArrayList.vue +123 -85
  91. package/components/form/ArrayListGrouped.vue +10 -2
  92. package/components/form/ArrayListSelect.vue +1 -1
  93. package/components/form/Command.vue +6 -15
  94. package/components/form/EnvVars.vue +16 -8
  95. package/components/form/Footer.vue +10 -7
  96. package/components/form/HealthCheck.vue +3 -3
  97. package/components/form/HookOption.vue +11 -16
  98. package/components/form/InputWithSelect.vue +6 -5
  99. package/components/form/KeyValue.vue +39 -10
  100. package/components/form/LabeledSelect.vue +73 -77
  101. package/components/form/Labels.vue +6 -3
  102. package/components/form/LifecycleHooks.vue +3 -3
  103. package/components/form/MatchExpressions.vue +42 -17
  104. package/components/form/NameNsDescription.vue +163 -116
  105. package/components/form/Networking.vue +20 -12
  106. package/components/form/NodeAffinity.vue +31 -23
  107. package/components/form/NodeScheduling.vue +13 -3
  108. package/components/form/Password.vue +11 -5
  109. package/components/form/PodAffinity.vue +47 -48
  110. package/components/form/Probe.vue +68 -66
  111. package/components/form/ResourceQuota/Namespace.vue +4 -4
  112. package/components/form/ResourceQuota/NamespaceRow.vue +5 -7
  113. package/components/form/ResourceQuota/Project.vue +9 -5
  114. package/components/form/ResourceQuota/ProjectRow.vue +4 -6
  115. package/components/form/ResourceSelector.vue +7 -9
  116. package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +6 -3
  117. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +12 -1
  118. package/components/form/SSHKnownHosts/index.vue +16 -2
  119. package/components/form/Security.vue +54 -56
  120. package/components/form/Select.vue +44 -7
  121. package/components/form/ShellInput.vue +5 -1
  122. package/components/form/SimpleSecretSelector.vue +29 -9
  123. package/components/form/Tolerations.vue +5 -1
  124. package/components/form/UnitInput.vue +10 -5
  125. package/components/form/ValueFromResource.vue +134 -121
  126. package/components/form/WorkloadPorts.vue +18 -18
  127. package/components/form/__tests__/ArrayList.test.ts +5 -2
  128. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  129. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  130. package/components/form/__tests__/Probe.test.ts +12 -8
  131. package/components/form/__tests__/SSHKnownHosts.test.ts +11 -0
  132. package/components/form/__tests__/Select.test.ts +37 -0
  133. package/components/form/__tests__/UnitInput.test.ts +4 -5
  134. package/components/formatter/BadgeStateFormatter.vue +8 -5
  135. package/components/formatter/InternalExternalIP.vue +2 -0
  136. package/components/formatter/LiveDate.vue +3 -3
  137. package/components/formatter/SecretData.vue +20 -7
  138. package/components/nav/Favorite.vue +5 -1
  139. package/components/nav/Group.vue +18 -4
  140. package/components/nav/Header.vue +39 -13
  141. package/components/nav/Jump.vue +7 -0
  142. package/components/nav/NamespaceFilter.vue +21 -11
  143. package/components/nav/Pinned.vue +1 -1
  144. package/components/nav/TopLevelMenu.vue +5 -17
  145. package/components/nav/Type.vue +30 -33
  146. package/components/nav/__tests__/TopLevelMenu.test.ts +0 -40
  147. package/components/rancherResourceDetail/Masthead.vue +769 -0
  148. package/components/rancherResourceDetail/__tests__/Masthead.test.ts +65 -0
  149. package/components/rancherResourceDetail/index.vue +591 -0
  150. package/components/rancherResourceList/Masthead-btn.vue +225 -0
  151. package/components/rancherResourceList/Masthead.vue +375 -0
  152. package/components/rancherResourceList/ResourceLoadingIndicator.vue +140 -0
  153. package/components/rancherResourceList/index.vue +307 -0
  154. package/components/rancherResourceList/resource-list.config.js +7 -0
  155. package/components/rancherResourceTable.vue +783 -0
  156. package/components/rancherSortableTable/THead.vue +561 -0
  157. package/components/rancherSortableTable/actions.js +153 -0
  158. package/components/rancherSortableTable/advanced-filtering.js +272 -0
  159. package/components/rancherSortableTable/debug.js +117 -0
  160. package/components/rancherSortableTable/filtering.js +290 -0
  161. package/components/rancherSortableTable/grouping.js +48 -0
  162. package/components/rancherSortableTable/index.vue +2712 -0
  163. package/components/rancherSortableTable/paging.js +155 -0
  164. package/components/rancherSortableTable/selection.js +629 -0
  165. package/components/rancherSortableTable/sortable-config.ts +4 -0
  166. package/components/rancherSortableTable/sorting.js +129 -0
  167. package/components/templates/blank.vue +4 -1
  168. package/components/templates/default.vue +8 -0
  169. package/components/templates/home.vue +10 -1
  170. package/components/templates/plain.vue +10 -1
  171. package/composables/focusTrap.ts +11 -3
  172. package/composables/useRuntimeFlag.ts +29 -0
  173. package/config/private-label.js +15 -10
  174. package/config/router/routes.js +21 -13
  175. package/config/store.js +4 -0
  176. package/config/table-headers.js +3 -2
  177. package/config/uiplugins.js +5 -1
  178. package/core/plugin-routes.ts +5 -115
  179. package/core/plugins.js +1 -1
  180. package/core/types.ts +23 -2
  181. package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +84 -23
  182. package/detail/autoscaling.horizontalpodautoscaler/index.vue +13 -3
  183. package/detail/provisioning.cattle.io.cluster.vue +72 -6
  184. package/dialog/AddCustomBadgeDialog.vue +1 -0
  185. package/dialog/DeactivateDriverDialog.vue +5 -4
  186. package/dialog/ForceMachineRemoveDialog.vue +6 -3
  187. package/dialog/GitRepoForceUpdateDialog.vue +1 -1
  188. package/dialog/ScalePoolDownDialog.vue +2 -2
  189. package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
  190. package/edit/auth/__tests__/oidc.test.ts +162 -88
  191. package/edit/auth/azuread.vue +2 -1
  192. package/edit/auth/github.vue +1 -1
  193. package/edit/auth/googleoauth.vue +5 -1
  194. package/edit/auth/ldap/__tests__/config.test.ts +0 -14
  195. package/edit/auth/ldap/config.vue +0 -24
  196. package/edit/auth/ldap/index.vue +1 -1
  197. package/edit/auth/oidc.vue +39 -6
  198. package/edit/auth/saml.vue +1 -1
  199. package/edit/autoscaling.horizontalpodautoscaler/metric-identifier.vue +5 -2
  200. package/edit/cloudcredential.vue +24 -9
  201. package/edit/fleet.cattle.io.clustergroup.vue +5 -3
  202. package/edit/fleet.cattle.io.gitrepo.vue +2 -0
  203. package/edit/logging-flow/Match.vue +1 -1
  204. package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
  205. package/edit/management.cattle.io.user.vue +28 -3
  206. package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +19 -19
  207. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +31 -31
  208. package/edit/monitoring.coreos.com.alertmanagerconfig/routeConfig.vue +36 -12
  209. package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +6 -6
  210. package/edit/monitoring.coreos.com.alertmanagerconfig/types/opsgenie.vue +10 -10
  211. package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +4 -4
  212. package/edit/monitoring.coreos.com.alertmanagerconfig/types/slack.vue +4 -4
  213. package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +1 -1
  214. package/edit/monitoring.coreos.com.receiver/auth.vue +29 -29
  215. package/edit/monitoring.coreos.com.receiver/types/email.vue +6 -6
  216. package/edit/monitoring.coreos.com.receiver/types/opsgenie.vue +10 -10
  217. package/edit/monitoring.coreos.com.receiver/types/pagerduty.vue +5 -5
  218. package/edit/monitoring.coreos.com.receiver/types/slack.vue +4 -4
  219. package/edit/namespace.vue +1 -2
  220. package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
  221. package/edit/networking.k8s.io.ingress/RulePath.vue +1 -1
  222. package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
  223. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
  224. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
  225. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -9
  226. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +8 -10
  227. package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -40
  228. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +5 -2
  229. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
  230. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +33 -2
  231. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +3 -3
  232. package/edit/service.vue +0 -3
  233. package/edit/token.vue +32 -11
  234. package/edit/workload/Job.vue +6 -6
  235. package/edit/workload/__tests__/Job.test.ts +0 -1
  236. package/edit/workload/index.vue +1 -0
  237. package/edit/workload/mixins/workload.js +3 -3
  238. package/initialize/install-plugins.js +2 -1
  239. package/list/harvesterhci.io.management.cluster.vue +4 -1
  240. package/list/management.cattle.io.feature.vue +1 -0
  241. package/list/namespace.vue +3 -1
  242. package/list/provisioning.cattle.io.cluster.vue +20 -12
  243. package/list/workload.vue +7 -6
  244. package/machine-config/__tests__/vmwarevsphere.test.ts +48 -3
  245. package/machine-config/azure.vue +16 -4
  246. package/machine-config/vmwarevsphere.vue +16 -0
  247. package/mixins/resource-fetch.js +2 -1
  248. package/models/__tests__/logging.banzaicloud.io.flow.test.ts +88 -0
  249. package/models/__tests__/namespace.test.ts +25 -1
  250. package/models/cloudcredential.js +5 -0
  251. package/models/kontainerdriver.js +6 -3
  252. package/models/logging.banzaicloud.io.flow.js +2 -1
  253. package/models/management.cattle.io.node.js +3 -3
  254. package/models/management.cattle.io.setting.js +2 -1
  255. package/models/namespace.js +4 -5
  256. package/models/nodedriver.js +6 -3
  257. package/models/storage.k8s.io.storageclass.js +2 -2
  258. package/models/workload.js +4 -1
  259. package/package.json +1 -1
  260. package/pages/about.vue +16 -8
  261. package/pages/account/index.vue +80 -24
  262. package/pages/account/pri.vue +229 -0
  263. package/pages/auth/login.vue +195 -44
  264. package/pages/auth/logout.vue +4 -1
  265. package/pages/auth/setup.vue +144 -19
  266. package/pages/auth/verify.vue +13 -8
  267. package/pages/auth copy/login.vue +595 -0
  268. package/pages/auth copy/logout.vue +47 -0
  269. package/pages/auth copy/setup.vue +523 -0
  270. package/pages/auth copy/verify.vue +203 -0
  271. package/pages/c/_cluster/_product/namespaces.vue +5 -5
  272. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  273. package/pages/c/_cluster/apps/charts/install.vue +26 -26
  274. package/pages/c/_cluster/auth/config/index.vue +10 -12
  275. package/pages/c/_cluster/explorer/EventsTable.vue +38 -33
  276. package/pages/c/_cluster/explorer/index.vue +17 -15
  277. package/pages/c/_cluster/istio/index.vue +2 -2
  278. package/pages/c/_cluster/longhorn/index.vue +1 -1
  279. package/pages/c/_cluster/monitoring/index.vue +1 -1
  280. package/pages/c/_cluster/monitoring/monitor/_namespace/_id.vue +4 -2
  281. package/pages/c/_cluster/monitoring/monitor/create.vue +4 -2
  282. package/pages/c/_cluster/monitoring/monitor/index.vue +2 -2
  283. package/pages/c/_cluster/monitoring/route-receiver/_id.vue +4 -2
  284. package/pages/c/_cluster/monitoring/route-receiver/create.vue +5 -2
  285. package/pages/c/_cluster/neuvector/index.vue +1 -1
  286. package/pages/c/_cluster/settings/brand.vue +3 -3
  287. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +8 -10
  288. package/pages/diagnostic.vue +59 -11
  289. package/pages/fail-whale.vue +14 -8
  290. package/pages/home.vue +24 -18
  291. package/pages/prefs.vue +9 -7
  292. package/pages/support/index.vue +4 -1
  293. package/pkg/tsconfig.json +9 -9
  294. package/pkg/vue.config.js +1 -1
  295. package/plugins/dashboard-store/normalize.js +3 -1
  296. package/plugins/dashboard-store/resource-class.js +31 -29
  297. package/plugins/internal-api/index.ts +37 -0
  298. package/plugins/internal-api/shared/base-api.ts +13 -0
  299. package/plugins/internal-api/shell/shell.api.ts +108 -0
  300. package/promptRemove/management.cattle.io.fleetworkspace.vue +1 -1
  301. package/promptRemove/management.cattle.io.globalrole.vue +1 -1
  302. package/promptRemove/management.cattle.io.project.vue +2 -2
  303. package/promptRemove/management.cattle.io.roletemplate.vue +1 -1
  304. package/promptRemove/pod.vue +1 -1
  305. package/public/index.html +2 -1
  306. package/rancher-components/BadgeState/BadgeState.vue +5 -1
  307. package/rancher-components/Banner/Banner.vue +8 -2
  308. package/rancher-components/Card/Card.vue +3 -6
  309. package/rancher-components/Form/Checkbox/Checkbox.vue +4 -0
  310. package/rancher-components/Form/LabeledInput/LabeledInput.vue +5 -2
  311. package/rancher-components/Form/Radio/RadioButton.vue +3 -3
  312. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -5
  313. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
  314. package/rancher-components/RcDropdown/RcDropdownItem.vue +1 -2
  315. package/rancher-components/RcDropdown/RcDropdownMenu.vue +7 -3
  316. package/rancher-components/RcDropdown/types.ts +1 -0
  317. package/scripts/clean +0 -0
  318. package/scripts/extension/bundle +20 -0
  319. package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +2 -2
  320. package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -1
  321. package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
  322. package/scripts/extension/helm/scripts/package +0 -0
  323. package/scripts/extension/helm/scripts/patch +0 -0
  324. package/scripts/extension/helm/scripts/version +0 -0
  325. package/scripts/extension/helmpatch +44 -31
  326. package/scripts/extension/parse-tag-name +0 -0
  327. package/scripts/extension/publish +12 -12
  328. package/scripts/publish-shell.sh +18 -23
  329. package/scripts/serve-pkgs +0 -0
  330. package/scripts/sync-shell-deps +0 -0
  331. package/scripts/test-plugins-build.sh +4 -6
  332. package/scripts/typegen.sh +28 -46
  333. package/server/har-file.js +25 -3
  334. package/static/favicon.ico +0 -0
  335. package/static/favicon.png +0 -0
  336. package/static/loading-indicator.html +2 -2
  337. package/store/aws.js +9 -2
  338. package/store/features.js +2 -1
  339. package/store/i18n.js +3 -3
  340. package/store/modal.ts +71 -0
  341. package/store/slideInPanel.ts +47 -0
  342. package/store/type-map.js +2 -1
  343. package/types/cloud-shell/index.d.ts +11014 -0
  344. package/types/global-vue.d.ts +5 -0
  345. package/types/internal-api/shell/growl.d.ts +25 -0
  346. package/types/internal-api/shell/modal.d.ts +77 -0
  347. package/types/internal-api/shell/slideIn.d.ts +15 -0
  348. package/types/shell/index.d.ts +118 -128
  349. package/types/vue-shim.d.ts +4 -1
  350. package/utils/__tests__/object.test.ts +38 -4
  351. package/utils/__tests__/string.test.ts +2 -2
  352. package/utils/auth.js +1 -0
  353. package/utils/banners.js +0 -45
  354. package/utils/cluster.js +35 -0
  355. package/utils/color.js +9 -8
  356. package/utils/error.js +61 -3
  357. package/utils/errorTranslate.json +450 -30
  358. package/utils/object.js +46 -6
  359. package/utils/router.js +22 -1
  360. package/utils/select.js +26 -3
  361. package/utils/string.js +9 -8
  362. package/utils/title.ts +1 -1
  363. package/utils/validators/machine-pool.ts +20 -0
  364. package/vue.config.js +7 -2
  365. package/components/formatter/ExtensionCache.vue +0 -74
  366. package/components/formatter/Port.vue +0 -24
  367. package/components/formatter/SecretType.vue +0 -41
  368. package/types/resources/fleet.d.ts +0 -57
  369. package/types/resources/pod-security-admission.ts +0 -36
  370. package/types/resources/settings.d.ts +0 -93
  371. package/types/resources/userPreferences.d.ts +0 -13
  372. package/types/vue-shim.d +0 -20
@@ -1,6 +1,6 @@
1
1
  import { nextTick } from 'vue';
2
2
  /* eslint-disable jest/no-hooks */
3
- import { mount } from '@vue/test-utils';
3
+ import { mount, type VueWrapper } from '@vue/test-utils';
4
4
  import { _EDIT } from '@shell/config/query-params';
5
5
 
6
6
  import oidc from '@shell/edit/auth/oidc.vue';
@@ -32,120 +32,194 @@ const mockModel = {
32
32
  };
33
33
 
34
34
  describe('oidc.vue', () => {
35
- let wrapper: any;
36
- const requiredSetup = () => ({
37
- data() {
38
- return {
39
- isEnabling: false,
40
- editConfig: false,
41
- model: { ...mockModel },
42
- serverSetting: null,
43
- errors: [],
44
- originalModel: null,
45
- principals: [],
46
- authConfigName: 'oidc',
47
- };
48
- },
49
- global: {
50
- mocks: {
51
- $fetchState: { pending: false },
52
- $store: {
53
- getters: {
54
- currentStore: () => 'current_store',
55
- 'current_store/schemaFor': jest.fn(),
56
- 'current_store/all': jest.fn(),
57
- 'i18n/t': (val: string) => val,
58
- 'i18n/exists': jest.fn(),
35
+ describe('given default valid values', () => {
36
+ let wrapper: VueWrapper<any, any>;
37
+ const requiredSetup = () => ({
38
+ data() {
39
+ return {
40
+ isEnabling: false,
41
+ editConfig: false,
42
+ model: { ...mockModel },
43
+ serverSetting: null,
44
+ errors: [],
45
+ originalModel: null,
46
+ principals: [],
47
+ authConfigName: 'oidc',
48
+ } as any; // any is necessary as in pre-existing tests we are including inherited mixins values
49
+ },
50
+ global: {
51
+ mocks: {
52
+ $fetchState: { pending: false },
53
+ $store: {
54
+ getters: {
55
+ currentStore: () => 'current_store',
56
+ 'current_store/schemaFor': jest.fn(),
57
+ 'current_store/all': jest.fn(),
58
+ 'i18n/t': (val: string) => val,
59
+ 'i18n/exists': jest.fn(),
60
+ },
61
+ dispatch: jest.fn()
59
62
  },
60
- dispatch: jest.fn()
63
+ $route: { query: { AS: '' }, params: { id: 'oicd' } },
64
+ $router: { applyQuery: jest.fn() },
61
65
  },
62
- $route: { query: { AS: '' }, params: { id: 'oicd' } },
63
- $router: { applyQuery: jest.fn() },
64
66
  },
65
- },
66
- props: {
67
- value: { applicationSecret: '' },
68
- mode: _EDIT,
69
- },
70
- });
67
+ props: {
68
+ value: { applicationSecret: '' },
69
+ mode: _EDIT,
70
+ },
71
+ });
71
72
 
72
- beforeEach(() => {
73
- wrapper = mount(oidc, { ...requiredSetup() });
74
- });
75
- afterEach(() => {
76
- wrapper.unmount();
77
- });
73
+ beforeEach(() => {
74
+ wrapper = mount(oidc, { ...requiredSetup() });
75
+ });
78
76
 
79
- it('have "Create" button enabled when provider is enabled and not editing config', async() => {
80
- wrapper.setData({ model: { enabled: true }, editConfig: false });
81
- await nextTick();
77
+ afterEach(() => {
78
+ wrapper.unmount();
79
+ });
82
80
 
83
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
81
+ describe('have "Create" button disabled', () => {
82
+ it('given missing Auth endpoint URL', () => {
83
+ wrapper.vm.model.authEndpoint = '';
84
+ wrapper.vm.model.scopes = 'openid profile email'; // set scope to be sure
85
+ wrapper.vm.oidcScope = ['openid', 'profile', 'email']; // TODO #13457: this is duplicated due wrong format of scopes
84
86
 
85
- expect(saveButton.disabled).toBe(false);
86
- });
87
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
87
88
 
88
- it('have "Create" button disabled when provider is disabled and editing config before fields are filled in', async() => {
89
- wrapper.setData({ model: {}, editConfig: true });
90
- await nextTick();
89
+ expect(saveButton.disabled).toBe(true);
90
+ });
91
91
 
92
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
92
+ it('given missing required basic scopes', () => {
93
+ wrapper.vm.model.authEndpoint = 'whatever'; // set auth endpoint to be sure
94
+ wrapper.vm.model.scopes = 'something else'; // set wrong scope
95
+ wrapper.vm.oidcScope = ['something', 'else']; // TODO #13457: this is duplicated due wrong format of scopes
93
96
 
94
- expect(saveButton.disabled).toBe(true);
95
- });
97
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
96
98
 
97
- it('have "Create" button disabled when provider is disabled and editing config after required fields and scope is missing openid', async() => {
98
- wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm } });
99
- await nextTick();
99
+ expect(saveButton.disabled).toBe(true);
100
+ });
100
101
 
101
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
102
+ it('when provider is disabled and editing config before fields are filled in', async() => {
103
+ wrapper.setData({ model: {}, editConfig: true });
104
+ await nextTick();
102
105
 
103
- expect(saveButton.disabled).toBe(true);
104
- });
106
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
105
107
 
106
- it('have "Create" button enabled when customEndpoint is disabled and required fields are filled in', async() => {
107
- wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm }, oidcScope: validScope.split(' ') });
108
- await nextTick();
108
+ expect(saveButton.disabled).toBe(true);
109
+ });
109
110
 
110
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
111
+ it('when provider is disabled and editing config after required fields and scope is missing openid', async() => {
112
+ wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm } });
113
+ await nextTick();
111
114
 
112
- expect(saveButton.disabled).toBe(false);
113
- });
115
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
114
116
 
115
- it('have "Create" button enabled when customEndpoint is enabled and required fields are filled in', async() => {
116
- wrapper.setData({ customEndpoint: { value: true }, oidcScope: validScope.split(' ') });
117
- await nextTick();
117
+ expect(saveButton.disabled).toBe(true);
118
+ });
119
+ });
118
120
 
119
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
121
+ describe('have "Create" button enabled', () => {
122
+ it('when customEndpoint is disabled and required fields are filled in', async() => {
123
+ wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm }, oidcScope: validScope.split(' ') });
124
+ await nextTick();
120
125
 
121
- expect(saveButton.disabled).toBe(false);
122
- });
126
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
123
127
 
124
- it('updates issuer endpoint when oidcUrls.url and oidcUrls.realm changes', async() => {
125
- wrapper.setData({ oidcUrls: { url: validUrl } });
126
- await nextTick();
128
+ expect(saveButton.disabled).toBe(false);
129
+ });
127
130
 
128
- expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/`);
131
+ it('when customEndpoint is enabled and required fields are filled in', async() => {
132
+ wrapper.setData({ customEndpoint: { value: true }, oidcScope: validScope.split(' ') });
133
+ await nextTick();
129
134
 
130
- wrapper.setData({ oidcUrls: { realm: validRealm } });
131
- await nextTick();
135
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
132
136
 
133
- expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
134
- });
137
+ expect(saveButton.disabled).toBe(false);
138
+ });
135
139
 
136
- it('`groupSearchEnabled` defaults to false', async() => {
137
- const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
140
+ it('when provider is enabled and not editing config', async() => {
141
+ wrapper.setData({ model: { enabled: true }, editConfig: false });
142
+ await nextTick();
138
143
 
139
- expect(groupSearchCheckbox.isVisible()).toBe(true);
140
- expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
141
- });
144
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
145
+
146
+ expect(saveButton.disabled).toBe(false);
147
+ });
148
+ });
149
+
150
+ it('updates issuer endpoint when oidcUrls.url and oidcUrls.realm changes', async() => {
151
+ wrapper.setData({ oidcUrls: { url: validUrl } });
152
+ await nextTick();
153
+
154
+ expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/`);
155
+
156
+ wrapper.setData({ oidcUrls: { realm: validRealm } });
157
+ await nextTick();
158
+
159
+ expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
160
+ });
161
+
162
+ it('`groupSearchEnabled` defaults to false', async() => {
163
+ const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
164
+
165
+ expect(groupSearchCheckbox.isVisible()).toBe(true);
166
+ expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
167
+ });
168
+
169
+ it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
170
+ const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
171
+
172
+ await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
173
+
174
+ expect(groupSearchCheckbox.isVisible()).toBe(true);
175
+ expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
176
+ });
177
+
178
+ it('changing URL should update issuer and auth-endpoint if Keycloak', async() => {
179
+ wrapper.vm.model.id = 'keycloakoidc';
180
+ const newUrl = 'whatever';
181
+
182
+ await wrapper.find(`[data-testid="oidc-url"]`).setValue(newUrl);
183
+ await wrapper.vm.$nextTick();
184
+
185
+ const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
186
+ const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
187
+
188
+ expect(issuerValue).toBe(`${ newUrl }/realms/`);
189
+ expect(endpointValue).toBe(`${ newUrl }/realms//protocol/openid-connect/auth`);
190
+ });
191
+
192
+ it('changing realm should update issuer and auth-endpoint if Keycloak', async() => {
193
+ const newRealm = 'newRealm';
194
+ const oldUrl = 'oldUrl';
195
+
196
+ wrapper.vm.model.id = 'keycloakoidc';
197
+ wrapper.vm.oidcUrls.url = oldUrl;
198
+
199
+ await wrapper.find(`[data-testid="oidc-realm"]`).setValue(newRealm);
200
+ await wrapper.vm.$nextTick();
201
+
202
+ const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
203
+ const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
204
+
205
+ expect(issuerValue).toBe(`${ oldUrl }/realms/${ newRealm }`);
206
+ expect(endpointValue).toBe(`${ oldUrl }/realms/${ newRealm }/protocol/openid-connect/auth`);
207
+ });
142
208
 
143
- it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
144
- const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
209
+ it('clear URL should clear issuer and auth-endpoint if Keycloak', async() => {
210
+ wrapper.vm.model.id = 'keycloakoidc';
211
+ const newUrl = 'whatever';
212
+ const urlInput = wrapper.find(`[data-testid="oidc-url"]`);
145
213
 
146
- await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
214
+ await urlInput.setValue(newUrl);
215
+ await wrapper.vm.$nextTick();
216
+ await urlInput.setValue('');
217
+ await wrapper.vm.$nextTick();
218
+ const issuer = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
219
+ const endpoint = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
147
220
 
148
- expect(groupSearchCheckbox.isVisible()).toBe(true);
149
- expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
221
+ expect(issuer).toBe('');
222
+ expect(endpoint).toBe('');
223
+ });
150
224
  });
151
225
  });
@@ -363,7 +363,7 @@ export default {
363
363
  </template>
364
364
  </AuthBanner>
365
365
 
366
- <hr>
366
+ <hr role="none">
367
367
 
368
368
  <AllowedPrincipals
369
369
  provider="azuread"
@@ -388,6 +388,7 @@ export default {
388
388
  <label class="reply-url">{{ t('authConfig.azuread.reply.label') }} </label>
389
389
  <CopyToClipboardText
390
390
  :plain="true"
391
+ :aria-label="t('authConfig.azuread.reply.ariaLabel')"
391
392
  :text="replyUrl"
392
393
  />
393
394
  </InfoBox>
@@ -143,7 +143,7 @@ export default {
143
143
  </template>
144
144
  </AuthBanner>
145
145
 
146
- <hr>
146
+ <hr role="none">
147
147
 
148
148
  <AllowedPrincipals
149
149
  provider="github"
@@ -90,7 +90,7 @@ export default {
90
90
  </template>
91
91
  </AuthBanner>
92
92
 
93
- <hr>
93
+ <hr role="none">
94
94
 
95
95
  <AllowedPrincipals
96
96
  provider="googleoauth"
@@ -143,12 +143,14 @@ export default {
143
143
  <b>{{ t('authConfig.googleoauth.steps.1.body.2', {}, true) }}</b> {{ t('authConfig.googleoauth.steps.1.topPrivateDomain', {}, true) }} <CopyToClipboardText
144
144
  :plain="true"
145
145
  :text="tArgs.hostname"
146
+ :aria-label="t('authConfig.googleoauth.steps.1.ariaLabel.hostname')"
146
147
  />
147
148
  </li>
148
149
  <li>
149
150
  <b>{{ t('authConfig.googleoauth.steps.1.body.3', {}, true) }}</b> <CopyToClipboardText
150
151
  :plain="true"
151
152
  :text="serverUrl"
153
+ :aria-label="t('authConfig.googleoauth.steps.1.ariaLabel.serverUrl')"
152
154
  />
153
155
  </li>
154
156
  <li>{{ t('authConfig.googleoauth.steps.1.body.4', {}, true) }} </li>
@@ -170,12 +172,14 @@ export default {
170
172
  <b>{{ t('authConfig.googleoauth.steps.2.body.2', {}, true) }}</b> <CopyToClipboardText
171
173
  :plain="true"
172
174
  :text="serverUrl"
175
+ :aria-label="t('authConfig.googleoauth.steps.1.ariaLabel.serverUrl')"
173
176
  />
174
177
  </li>
175
178
  <li>
176
179
  <b>{{ t('authConfig.googleoauth.steps.2.body.3', {}, true) }}</b> <CopyToClipboardText
177
180
  :plain="true"
178
181
  :text="serverUrl+'/verify-auth'"
182
+ :aria-label="t('authConfig.googleoauth.steps.2.ariaLabel.serverUrlVerify')"
179
183
  />
180
184
  </li>
181
185
  <li>{{ t('authConfig.googleoauth.steps.2.body.4', {}, true) }} </li>
@@ -2,20 +2,6 @@ import { mount } from '@vue/test-utils';
2
2
  import LDAPConfig from '@shell/edit/auth/ldap/config.vue';
3
3
 
4
4
  describe('lDAP config', () => {
5
- it.each([
6
- 'openldap', 'freeipa'
7
- ])('should display searchUsingServiceAccount checkbox if type %p', (type) => {
8
- const wrapper = mount(LDAPConfig, {
9
- propsData: {
10
- value: {},
11
- type,
12
- }
13
- });
14
- const checkbox = wrapper.find('[data-testid="searchUsingServiceAccount"]');
15
-
16
- expect(checkbox).toBeDefined();
17
- });
18
-
19
5
  it('updates user login filter when value is entered', async() => {
20
6
  const wrapper = mount(
21
7
  LDAPConfig,
@@ -11,8 +11,6 @@ const DEFAULT_TLS_PORT = 636;
11
11
 
12
12
  export const SHIBBOLETH = 'shibboleth';
13
13
  export const OKTA = 'okta';
14
- export const OPEN_LDAP = 'openldap';
15
- export const FREE_IPA = 'freeipa';
16
14
 
17
15
  export default {
18
16
  emits: ['update:value'],
@@ -66,11 +64,6 @@ export default {
66
64
  // Does the auth provider support LDAP for search in addition to SAML?
67
65
  isSamlProvider() {
68
66
  return this.type === SHIBBOLETH || this.type === OKTA;
69
- },
70
-
71
- // Allow to enable user search just for these providers
72
- isSearchAllowed() {
73
- return this.type === OPEN_LDAP || this.type === FREE_IPA;
74
67
  }
75
68
  },
76
69
 
@@ -233,23 +226,6 @@ export default {
233
226
  />
234
227
  </div>
235
228
  </div>
236
-
237
- <div
238
- v-if="isSearchAllowed"
239
- class="row mb-20"
240
- >
241
- <div class="col">
242
- <Checkbox
243
- v-model:value="model.searchUsingServiceAccount"
244
- :mode="mode"
245
- data-testid="searchUsingServiceAccount"
246
- class="full-height"
247
- :label="t('authConfig.ldap.searchUsingServiceAccount.label')"
248
- :tooltip="t('authConfig.ldap.searchUsingServiceAccount.tip')"
249
- />
250
- </div>
251
- </div>
252
-
253
229
  <div class="row mb-20">
254
230
  <div class="col span-6">
255
231
  <LabeledInput
@@ -99,7 +99,7 @@ export default {
99
99
  </template>
100
100
  </AuthBanner>
101
101
 
102
- <hr>
102
+ <hr role="none">
103
103
 
104
104
  <AllowedPrincipals
105
105
  :provider="NAME"
@@ -12,6 +12,7 @@ import ArrayList from '@shell/components/form/ArrayList';
12
12
  import { LabeledInput } from '@components/Form/LabeledInput';
13
13
  import { RadioGroup } from '@components/Form/Radio';
14
14
  import { Checkbox } from '@components/Form/Checkbox';
15
+ import { BASE_SCOPES } from '@shell/store/auth';
15
16
 
16
17
  export default {
17
18
  components: {
@@ -50,6 +51,7 @@ export default {
50
51
  tokenEndpoint: null,
51
52
  userInfoEndpoint: null,
52
53
  },
54
+ // TODO #13457: this is duplicated due wrong format
53
55
  oidcScope: []
54
56
  };
55
57
  },
@@ -76,9 +78,10 @@ export default {
76
78
  }
77
79
 
78
80
  const { clientId, clientSecret } = this.model;
79
- const isValidScope = this.model.id === 'keycloakoidc' || this.oidcScope?.includes('openid');
81
+ const isMissingAuthEndpoint = (this.requiresAuthEndpoint && !this.model.authEndpoint);
82
+ const isMissingScopes = !this.requiredScopes.every((scope) => this.oidcScope.includes(scope));
80
83
 
81
- if ( !isValidScope ) {
84
+ if (isMissingAuthEndpoint || isMissingScopes) {
82
85
  return false;
83
86
  }
84
87
 
@@ -91,6 +94,19 @@ export default {
91
94
 
92
95
  return !!(clientId && clientSecret && rancherUrl && issuer);
93
96
  }
97
+ },
98
+
99
+ requiresAuthEndpoint() {
100
+ return ['genericoidc', 'keycloakoidc'].includes(this.model.id);
101
+ },
102
+
103
+ /**
104
+ * TODO #13457: Refactor scopes to be an array of terms
105
+ * Return valid scopes
106
+ * The scopes for given auth provider (model.id) have format of ['scope1 scope2 scope3']
107
+ */
108
+ requiredScopes() {
109
+ return this.model.id ? (BASE_SCOPES[this.model.id] || []) ? (BASE_SCOPES[this.model.id] || [])[0].split(' ') : [] : [];
94
110
  }
95
111
  },
96
112
 
@@ -104,6 +120,7 @@ export default {
104
120
  },
105
121
 
106
122
  'model.enabled'(neu) {
123
+ // TODO #13457: Refactor scopes to be an array of terms
107
124
  // Cover case where oidc gets disabled and we return to the edit screen with a reset model
108
125
  if (!neu) {
109
126
  this.oidcUrls = {
@@ -114,8 +131,10 @@ export default {
114
131
  userInfoEndpoint: null,
115
132
  };
116
133
  this.customEndpoint.value = false;
134
+ // TODO #13457: Refactor scopes to be an array of terms
117
135
  this.oidcScope = this.model?.scope?.split(' ');
118
136
  } else {
137
+ // TODO #13457: Refactor scopes to be an array of terms
119
138
  this.oidcScope = this.model?.scope?.split(' ');
120
139
  }
121
140
  },
@@ -130,13 +149,19 @@ export default {
130
149
 
131
150
  methods: {
132
151
  updateEndpoints() {
152
+ const isKeycloak = this.model.id === 'keycloakoidc';
153
+
133
154
  if (!this.oidcUrls.url) {
155
+ this.model.issuer = '';
156
+ if (isKeycloak) {
157
+ this.model.authEndpoint = '';
158
+ }
159
+
134
160
  return;
135
161
  }
136
- const isKeycloak = this.model.id === 'keycloakoidc';
137
162
 
138
163
  const url = this.oidcUrls.url.replaceAll(' ', '');
139
- const realmsPath = isKeycloak ? 'auth/realms' : 'realms';
164
+ const realmsPath = 'realms';
140
165
 
141
166
  this.model.issuer = `${ url }/${ realmsPath }/${ this.oidcUrls.realm || '' }`;
142
167
 
@@ -184,7 +209,7 @@ export default {
184
209
  </template>
185
210
  </AuthBanner>
186
211
 
187
- <hr>
212
+ <hr role="none">
188
213
 
189
214
  <AllowedPrincipals
190
215
  :provider="NAME"
@@ -201,6 +226,7 @@ export default {
201
226
 
202
227
  <h3>{{ t(`authConfig.oidc.${NAME}`) }}</h3>
203
228
 
229
+ <!-- Auth credentials -->
204
230
  <div class="row mb-20">
205
231
  <div class="col span-6">
206
232
  <LabeledInput
@@ -222,6 +248,7 @@ export default {
222
248
  </div>
223
249
  </div>
224
250
 
251
+ <!-- Key/Certificate -->
225
252
  <div class="row mb-20">
226
253
  <div class="col span-6">
227
254
  <LabeledInput
@@ -255,6 +282,7 @@ export default {
255
282
  </div>
256
283
  </div>
257
284
 
285
+ <!-- Allow group search -->
258
286
  <div class="row mb-20">
259
287
  <div class="col span-6">
260
288
  <Checkbox
@@ -267,6 +295,7 @@ export default {
267
295
  </div>
268
296
  </div>
269
297
 
298
+ <!-- Scopes -->
270
299
  <div class="row mb-20">
271
300
  <div class="col span-6">
272
301
  <ArrayList
@@ -280,6 +309,7 @@ export default {
280
309
  </div>
281
310
  </div>
282
311
 
312
+ <!-- Generated vs Specific Endpoints -->
283
313
  <div class="row mb-20">
284
314
  <div class="col span-6">
285
315
  <RadioGroup
@@ -297,6 +327,7 @@ export default {
297
327
  </div>
298
328
  </div>
299
329
 
330
+ <!-- Generated endpoints -->
300
331
  <div class="row mb-20">
301
332
  <div class="col span-6">
302
333
  <LabeledInput
@@ -320,6 +351,7 @@ export default {
320
351
  </div>
321
352
  </div>
322
353
 
354
+ <!-- Specific Endpoints -->
323
355
  <div class="row mb-20">
324
356
  <div class="col span-6">
325
357
  <LabeledInput
@@ -350,12 +382,13 @@ export default {
350
382
  :label="t(`authConfig.oidc.authEndpoint`)"
351
383
  :mode="mode"
352
384
  :disabled="!customEndpoint.value"
353
- :required="model.id === 'keycloakoidc'"
385
+ :required="requiresAuthEndpoint"
354
386
  data-testid="oidc-auth-endpoint"
355
387
  />
356
388
  </div>
357
389
  </div>
358
390
 
391
+ <!-- Advanced section -->
359
392
  <AdvancedSection :mode="mode">
360
393
  <div class="row mb-20">
361
394
  <div class="col span-6">
@@ -223,7 +223,7 @@ export default {
223
223
  </template>
224
224
  </AuthBanner>
225
225
 
226
- <hr>
226
+ <hr role="none">
227
227
 
228
228
  <AllowedPrincipals
229
229
  :provider="NAME"
@@ -65,14 +65,17 @@ export default {
65
65
  </div>
66
66
  <div class="row">
67
67
  <div class="col span-12">
68
- <h3>Metric Selector</h3>
69
68
  <MatchExpressions
70
69
  :mode="mode"
71
70
  :value="matchExpressions"
72
71
  :label="t('hpa.metricIdentifier.selector.label')"
73
72
  :show-remove="false"
74
73
  @input="matchChanged($event)"
75
- />
74
+ >
75
+ <template #header>
76
+ <h3>{{ t('hpa.metricIdentifier.selector.header') }}</h3>
77
+ </template>
78
+ </MatchExpressions>
76
79
  </div>
77
80
  </div>
78
81
  </div>