@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
@@ -0,0 +1,398 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import PodSecurityAdmission from '@shell/components/PodSecurityAdmission.vue';
3
+
4
+ describe('component: PodSecurityAdmission', () => {
5
+ it.each([
6
+ ['updateLabels', {
7
+ audit: 'privileged',
8
+ 'audit-version': 'latest',
9
+ enforce: 'privileged',
10
+ 'enforce-version': 'latest',
11
+ warn: 'privileged',
12
+ 'warn-version': 'latest',
13
+ }],
14
+ ['updateExemptions', {
15
+ namespaces: [], runtimeClasses: [], usernames: []
16
+ }]
17
+ ])('should emit %p and exemptions on creation if labels always active', (emission, value) => {
18
+ const wrapper = mount(PodSecurityAdmission, { propsData: { mode: 'create', labelsAlwaysActive: true } });
19
+
20
+ expect(wrapper.emitted(emission)![0][0]).toStrictEqual(value);
21
+ });
22
+
23
+ describe('handling labels', () => {
24
+ it.each([
25
+ ['true', 'active'],
26
+ ['', 'level'],
27
+ ['', 'version'],
28
+ ])('should display default value %p for input %p', (value, inputId) => {
29
+ const wrapper = mount(PodSecurityAdmission, { propsData: { mode: 'edit' } });
30
+
31
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
32
+
33
+ expect(input.value).toStrictEqual(value);
34
+ });
35
+
36
+ describe.each([
37
+ 'pod-security.kubernetes.io/',
38
+ ''
39
+ ])('given prefix %p', (prefix) => {
40
+ it('should map labels to the form control', () => {
41
+ const labels = {
42
+ [`${ prefix }enforce`]: 'baseline',
43
+ [`${ prefix }enforce-version`]: '123'
44
+ };
45
+ const psaControls = {
46
+ audit: {
47
+ active: false,
48
+ level: 'privileged',
49
+ version: ''
50
+ },
51
+ enforce: {
52
+ active: true,
53
+ level: 'baseline',
54
+ version: '123'
55
+ },
56
+ warn: {
57
+ active: false,
58
+ level: 'privileged',
59
+ version: ''
60
+ },
61
+ };
62
+
63
+ const wrapper = mount(PodSecurityAdmission, {
64
+ propsData: {
65
+ mode: 'edit',
66
+ labels,
67
+ labelsPrefix: prefix
68
+ }
69
+ });
70
+
71
+ expect(wrapper.vm.psaControls).toStrictEqual(psaControls);
72
+ });
73
+
74
+ it.each([
75
+ // ['true', 'active'],
76
+ // ['baseline', 'level'],
77
+ ['123', 'version'],
78
+ ])('should map labels to the form, with value %p for input %p', (value, inputId) => {
79
+ const labels = {
80
+ [`${ prefix }enforce`]: 'baseline',
81
+ [`${ prefix }enforce-version`]: '123'
82
+ };
83
+
84
+ const wrapper = mount(PodSecurityAdmission, {
85
+ propsData: {
86
+ mode: 'edit',
87
+ labels,
88
+ labelsPrefix: prefix
89
+ }
90
+ });
91
+
92
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
93
+
94
+ expect(input.value).toStrictEqual(value);
95
+ });
96
+
97
+ it.each([
98
+ // ['true', 'active'],
99
+ // ['privileged', 'level'],
100
+ ['', 'version'],
101
+ ])('should map labels to the form, using default values if none, with value %p for input %p', (value, inputId) => {
102
+ const labels = {
103
+ [`${ prefix }enforce`]: '',
104
+ [`${ prefix }enforce-version`]: ''
105
+ };
106
+
107
+ const wrapper = mount(PodSecurityAdmission, {
108
+ propsData: {
109
+ mode: 'edit',
110
+ labels,
111
+ labelsPrefix: prefix
112
+ }
113
+ });
114
+
115
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
116
+
117
+ expect(input.value).toStrictEqual(value);
118
+ });
119
+
120
+ describe('changing input values', () => {
121
+ it('should add labels if active', () => {
122
+ const version = '123';
123
+ const newLabels = {
124
+ [`${ prefix }enforce`]: 'privileged',
125
+ [`${ prefix }enforce-version`]: version
126
+ };
127
+ const wrapper = mount(PodSecurityAdmission, {
128
+ propsData: {
129
+ mode: 'edit',
130
+ labels: {},
131
+ labelsPrefix: prefix
132
+ },
133
+ // Unable to toggle the checkbox, so we enforce the data
134
+ data: () => ({
135
+ psaControls: {
136
+ enforce: {
137
+ active: true,
138
+ level: '',
139
+ version: ''
140
+ }
141
+ }
142
+ }),
143
+ });
144
+
145
+ // Unable to toggle the checkbox, so we use the input
146
+ wrapper.find(`[data-testid="pod-security-admission--psaControl-0-version"]`).find('input').setValue(version);
147
+
148
+ expect(wrapper.emitted('updateLabels')![0][0]).toStrictEqual(newLabels);
149
+ });
150
+
151
+ it('should remove other labels if not active', () => {
152
+ const labels = {
153
+ [`${ prefix }audit`]: 'privileged',
154
+ [`${ prefix }audit-version`]: 'latest'
155
+ };
156
+ const newLabels = {
157
+ [`${ prefix }enforce`]: 'privileged',
158
+ [`${ prefix }enforce-version`]: 'latest',
159
+ };
160
+ const wrapper = mount(PodSecurityAdmission, {
161
+ propsData: {
162
+ mode: 'edit',
163
+ labels,
164
+ labelsPrefix: prefix
165
+ },
166
+ // Unable to toggle the checkbox, so we enforce the data
167
+ data: () => ({
168
+ psaControls: {
169
+ enforce: {
170
+ active: true,
171
+ level: '',
172
+ version: ''
173
+ }
174
+ }
175
+ }),
176
+ });
177
+
178
+ // Unable to toggle the checkbox, so we enforce the data
179
+ wrapper.setData({
180
+ psaControls: {
181
+ audit: {
182
+ active: false,
183
+ level: '',
184
+ version: ''
185
+ }
186
+ }
187
+ });
188
+
189
+ // Unable to toggle the checkbox, so we use the input
190
+ wrapper.find(`[data-testid="pod-security-admission--psaControl-0-version"]`).find('input').setValue('');
191
+
192
+ expect(wrapper.emitted('updateLabels')![0][0]).toStrictEqual(newLabels);
193
+ });
194
+
195
+ it('should assign default version and level if missing', () => {
196
+ const wrapper = mount(PodSecurityAdmission, {
197
+ propsData: {
198
+ mode: 'edit',
199
+ labels: {},
200
+ labelsPrefix: prefix
201
+ },
202
+ // Unable to toggle the checkbox, so we enforce the data
203
+ data: () => ({
204
+ psaControls: {
205
+ enforce: {
206
+ active: true,
207
+ level: '',
208
+ version: ''
209
+ }
210
+ }
211
+ }),
212
+ });
213
+ const newLabels = {
214
+ [`${ prefix }enforce`]: 'privileged',
215
+ [`${ prefix }enforce-version`]: 'latest'
216
+ };
217
+
218
+ // Unable to toggle the checkbox, so we use the input
219
+ wrapper.find(`[data-testid="pod-security-admission--psaControl-0-version"]`).find('input').setValue('');
220
+
221
+ expect(wrapper.emitted('updateLabels')![0][0]).toStrictEqual(newLabels);
222
+ });
223
+ });
224
+ });
225
+
226
+ describe.each(['level', 'version'])('should keep always %p enabled', (inputId) => {
227
+ it('given labelsAlwaysActive true and no labels', () => {
228
+ const wrapper = mount(PodSecurityAdmission, {
229
+ propsData: {
230
+ mode: 'edit',
231
+ labelsAlwaysActive: true,
232
+ labels: {}
233
+ },
234
+ });
235
+
236
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
237
+
238
+ expect(input.disabled).toBe(false);
239
+ });
240
+
241
+ it('given existing values', () => {
242
+ const wrapper = mount(PodSecurityAdmission, {
243
+ propsData: {
244
+ mode: 'edit',
245
+ labels: {
246
+ [`enforce`]: 'baseline',
247
+ [`enforce-version`]: '123'
248
+ }
249
+ },
250
+ });
251
+
252
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
253
+
254
+ expect(input.disabled).toBe(false);
255
+ });
256
+ });
257
+
258
+ describe.each(['level', 'version'])('should keep always %p disabled', (inputId) => {
259
+ it('given labelsAlwaysActive false and no labels', () => {
260
+ const wrapper = mount(PodSecurityAdmission, {
261
+ propsData: {
262
+ mode: 'edit',
263
+ labelsAlwaysActive: false,
264
+ labels: {}
265
+ },
266
+ });
267
+
268
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
269
+
270
+ expect(input.disabled).toBe(true);
271
+ });
272
+
273
+ it('given disabled active status', () => {
274
+ const wrapper = mount(PodSecurityAdmission, {
275
+ propsData: { mode: 'edit' },
276
+ data: () => ({
277
+ psaControls: {
278
+ enforce: {
279
+ active: false,
280
+ level: '',
281
+ version: ''
282
+ }
283
+ }
284
+ }),
285
+ });
286
+
287
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
288
+
289
+ expect(input.disabled).toBe(true);
290
+ });
291
+
292
+ it('given view mode and provided labels', () => {
293
+ const wrapper = mount(PodSecurityAdmission, {
294
+ propsData: {
295
+ mode: 'view',
296
+ labels: {
297
+ [`enforce`]: 'baseline',
298
+ [`enforce-version`]: '123'
299
+ }
300
+ },
301
+ });
302
+
303
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
304
+
305
+ expect(input.disabled).toBe(true);
306
+ });
307
+ });
308
+
309
+ it.each([
310
+ [true, false],
311
+ ])('should display the checkbox %p', (value) => {
312
+ const wrapper = mount(PodSecurityAdmission, {
313
+ propsData: {
314
+ mode: 'edit',
315
+ labelsAlwaysActive: value
316
+ }
317
+ });
318
+
319
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaControl-0-active"]`).element as HTMLInputElement;
320
+
321
+ expect(!input).toBe(value);
322
+ });
323
+ });
324
+
325
+ describe('handling exemptions', () => {
326
+ it.each([
327
+ [['namespace1', 'namespace2'], 'namespace1,namespace2'],
328
+ ])('should map %p to the form control as %p', (exemption, control) => {
329
+ const exemptions = { namespaces: exemption };
330
+ const result = {
331
+ namespaces: {
332
+ active: true,
333
+ value: control
334
+ },
335
+ runtimeClasses: {
336
+ active: false,
337
+ value: ''
338
+ },
339
+ usernames: {
340
+ active: false,
341
+ value: ''
342
+ },
343
+ };
344
+
345
+ const wrapper = mount(PodSecurityAdmission, {
346
+ propsData: {
347
+ mode: 'edit',
348
+ exemptions,
349
+ }
350
+ });
351
+
352
+ expect(wrapper.vm.psaExemptionsControls).toStrictEqual(result);
353
+ });
354
+
355
+ it.each([
356
+ // ['true', 'active'],
357
+ ['username', 'value'],
358
+ ])('should map to the form, with value %p for input %p', (value, inputId) => {
359
+ const exemptions = { usernames: [value] };
360
+ const wrapper = mount(PodSecurityAdmission, {
361
+ propsData: {
362
+ mode: 'edit',
363
+ exemptions
364
+ }
365
+ });
366
+
367
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaExemptionsControl-0-${ inputId }"]`).find('input').element as HTMLInputElement;
368
+
369
+ expect(input.value).toStrictEqual(value);
370
+ });
371
+
372
+ describe('changing input values', () => {
373
+ it.each([
374
+ ['username1', ['username1']],
375
+ ['username1, username2', ['username1', 'username2']],
376
+ ['username1,username2', ['username1', 'username2']],
377
+ ])('should emit exemption input value %p as %p', (value, exemption) => {
378
+ const exemptions = {
379
+ usernames: exemption,
380
+ namespaces: [],
381
+ runtimeClasses: []
382
+ };
383
+ const wrapper = mount(PodSecurityAdmission, {
384
+ propsData: {
385
+ mode: 'edit',
386
+ exemptions
387
+ },
388
+ });
389
+ // Unable to toggle the checkbox, so we use the input
390
+ const input = wrapper.find(`[data-testid="pod-security-admission--psaExemptionsControl-0-value"]`).find('input');
391
+
392
+ input.setValue(value);
393
+
394
+ expect(wrapper.emitted('updateExemptions')![0][0]).toStrictEqual(exemptions);
395
+ });
396
+ });
397
+ });
398
+ });
@@ -1,12 +1,12 @@
1
1
 
2
2
  <script>
3
3
  import { Banner } from '@components/Banner';
4
- import AsyncButton from '@shell/components/AsyncButton';
4
+ import DisableAuthProviderModal from '@shell/components/DisableAuthProviderModal';
5
5
 
6
6
  export default {
7
7
  components: {
8
- AsyncButton,
9
- Banner
8
+ Banner,
9
+ DisableAuthProviderModal
10
10
  },
11
11
 
12
12
  props: {
@@ -32,6 +32,12 @@ export default {
32
32
  return Object.entries(this.table);
33
33
  }
34
34
  },
35
+
36
+ methods: {
37
+ showDisableModal() {
38
+ this.$refs.disableAuthProviderModal.show();
39
+ }
40
+ },
35
41
  };
36
42
  </script>
37
43
 
@@ -52,13 +58,13 @@ export default {
52
58
  >
53
59
  {{ t('action.edit') }}
54
60
  </button>
55
- <AsyncButton
56
- class="ml-10"
57
- mode="disable"
58
- size="sm"
59
- action-color="bg-error"
60
- @click="disable"
61
- />
61
+ <button
62
+ type="button"
63
+ class="ml-10 btn-sm role-primary bg-error"
64
+ @click="showDisableModal"
65
+ >
66
+ {{ t('generic.disable') }}
67
+ </button>
62
68
  </Banner>
63
69
 
64
70
  <table
@@ -67,6 +73,10 @@ export default {
67
73
  >
68
74
  <slot name="rows" />
69
75
  </table>
76
+ <DisableAuthProviderModal
77
+ ref="disableAuthProviderModal"
78
+ @disable="disable"
79
+ />
70
80
  </div>
71
81
  </template>
72
82
 
@@ -380,28 +380,27 @@ export default {
380
380
  // - resourceNames
381
381
  // - resources
382
382
  // - verbs
383
- const value = event.label ? event.label : event;
384
383
 
385
384
  switch (key) {
386
385
  case 'apiGroups':
387
386
 
388
- if (value || (value === '')) {
389
- this.$set(rule, 'apiGroups', [value]);
387
+ if (event || (event === '')) {
388
+ this.$set(rule, 'apiGroups', [event]);
390
389
  }
391
390
 
392
391
  break;
393
392
 
394
393
  case 'verbs':
395
394
 
396
- if (value) {
397
- this.$set(rule, 'verbs', [value]);
395
+ if (event) {
396
+ this.$set(rule, 'verbs', [event]);
398
397
  } else {
399
398
  this.$set(rule, 'verbs', []);
400
399
  }
401
400
  break;
402
401
 
403
402
  case 'resources':
404
- if (event.resourceName) {
403
+ if (event?.resourceName) {
405
404
  // If we are updating the resources defined in a rule,
406
405
  // the event will be an object with the
407
406
  // properties apiGroupValue and resourceName.
@@ -409,7 +408,7 @@ export default {
409
408
  // Automatically fill in the API group of the
410
409
  // selected resource.
411
410
  this.$set(rule, 'apiGroups', [event.apiGroupValue]);
412
- } else if (event.label) {
411
+ } else if (event?.label) {
413
412
  // When the user creates a new resource name in the resource
414
413
  // field instead of selecting an existing one,
415
414
  // we have to treat that differently because the incoming event
@@ -424,8 +423,8 @@ export default {
424
423
  break;
425
424
 
426
425
  case 'nonResourceURLs':
427
- if (value) {
428
- this.$set(rule, 'nonResourceURLs', [value]);
426
+ if (event) {
427
+ this.$set(rule, 'nonResourceURLs', [event]);
429
428
  } else {
430
429
  this.$set(rule, 'nonResourceURLs', []);
431
430
  }
@@ -447,6 +446,21 @@ export default {
447
446
  this.done();
448
447
  },
449
448
  async actuallySave(url) {
449
+ // Go through all of the grules and replace double quote apiGroups
450
+ // k8S documentation shows using empty rules as "" - we change this to empty string when used
451
+ this.value.rules?.forEach((rule) => {
452
+ if (rule.apiGroups) {
453
+ rule.apiGroups = rule.apiGroups.map((group) => {
454
+ // If the group is two double quotes ("") replace if with empty string
455
+ if (group.trim() === '\"\"') {
456
+ group = '';
457
+ }
458
+
459
+ return group;
460
+ });
461
+ }
462
+ });
463
+
450
464
  if ( this.isCreate ) {
451
465
  url = url || this.schema.linkFor('collection');
452
466
  await this.value.save({ url, redirectUnauthorized: false });
@@ -623,12 +637,7 @@ export default {
623
637
  </span>
624
638
  </div>
625
639
  <div :class="ruleClass">
626
- <span class="text-label">{{ t('rbac.roletemplate.tabs.grantResources.tableHeaders.apiGroups') }}
627
- <span
628
- v-if="isNamespaced"
629
- class="required"
630
- >*</span>
631
- </span>
640
+ <span class="text-label">{{ t('rbac.roletemplate.tabs.grantResources.tableHeaders.apiGroups') }}</span>
632
641
  </div>
633
642
  <div
634
643
  v-if="!isNamespaced"
@@ -670,7 +679,7 @@ export default {
670
679
  :value="getRule('apiGroups', props.row.value)"
671
680
  :disabled="isBuiltin"
672
681
  :mode="mode"
673
- @input="setRule('apiGroups', props.row.value, $event)"
682
+ @input="setRule('apiGroups', props.row.value, $event.target.value)"
674
683
  >
675
684
  </div>
676
685
  <div
@@ -681,7 +690,7 @@ export default {
681
690
  :value="getRule('nonResourceURLs', props.row.value)"
682
691
  :disabled="isBuiltin"
683
692
  :mode="mode"
684
- @input="setRule('nonResourceURLs', props.row.value, $event)"
693
+ @input="setRule('nonResourceURLs', props.row.value, $event.target.value)"
685
694
  >
686
695
  </div>
687
696
  </div>
@@ -40,7 +40,7 @@ export default {
40
40
  project: {
41
41
  type: Boolean,
42
42
  default: false
43
- },
43
+ }
44
44
  },
45
45
 
46
46
  async fetch() {
@@ -54,10 +54,11 @@ export default {
54
54
 
55
55
  data() {
56
56
  return {
57
- principals: null,
58
- searchStr: '',
59
- options: [],
60
- newValue: '',
57
+ principals: null,
58
+ searchStr: '',
59
+ options: [],
60
+ newValue: '',
61
+ tooltipContent: null,
61
62
  };
62
63
  },
63
64
 
@@ -94,6 +95,24 @@ export default {
94
95
  },
95
96
 
96
97
  methods: {
98
+ setTooltipContent() {
99
+ if (!this.retainSelection) {
100
+ return;
101
+ }
102
+ if (this.principals) {
103
+ const selected = this.principals.find(p => p.id === this.newValue);
104
+
105
+ this.tooltipContent = selected?.name;
106
+ } else {
107
+ this.tooltipContent = null;
108
+ }
109
+ },
110
+ resetTooltipContent() {
111
+ if (!this.retainSelection) {
112
+ return;
113
+ }
114
+ this.tooltipContent = null;
115
+ },
97
116
  add(id) {
98
117
  if (!id) {
99
118
  // Ignore attempts to select an invalid principal
@@ -156,6 +175,11 @@ export default {
156
175
  <LabeledSelect
157
176
  ref="labeled-select"
158
177
  v-model="newValue"
178
+ v-tooltip="{
179
+ content: tooltipContent,
180
+ placement: 'bottom',
181
+ classes: ['select-principal-tooltip']
182
+ }"
159
183
  :mode="mode"
160
184
  :label="label"
161
185
  :placeholder="placeholder"
@@ -166,6 +190,8 @@ export default {
166
190
  :class="{'retain-selection': retainSelection}"
167
191
  @input="add"
168
192
  @search="onSearch"
193
+ @on-open="resetTooltipContent()"
194
+ @on-close="setTooltipContent()"
169
195
  >
170
196
  <template v-slot:no-options="{ searching }">
171
197
  <template v-if="searching">
@@ -226,4 +252,9 @@ export default {
226
252
  text-overflow: ellipsis;
227
253
  }
228
254
  }
255
+
256
+ .select-principal-tooltip {
257
+ max-width: 580px;
258
+ word-wrap: break-word;
259
+ }
229
260
  </style>