@rancher/shell 0.3.0 → 0.3.1

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 (322) 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/_layout.scss +1 -2
  4. package/assets/styles/global/_select.scss +1 -4
  5. package/assets/styles/themes/_dark.scss +4 -4
  6. package/assets/styles/themes/_light.scss +4 -3
  7. package/assets/styles/themes/_suse.scss +1 -1
  8. package/assets/styles/vendor/vue-select.scss +4 -3
  9. package/assets/translations/en-us.yaml +669 -73
  10. package/assets/translations/zh-hans.yaml +547 -165
  11. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  12. package/cloud-credential/azure.vue +23 -0
  13. package/cloud-credential/harvester.vue +25 -62
  14. package/cloud-credential/pnap.vue +80 -0
  15. package/components/.DS_Store +0 -0
  16. package/components/AdvancedSection.vue +9 -2
  17. package/components/Alert.vue +2 -2
  18. package/components/ButtonDropdown.vue +0 -2
  19. package/components/ButtonGroup.vue +1 -0
  20. package/components/CollapsibleCard.vue +0 -1
  21. package/components/CruResource.vue +41 -4
  22. package/components/DetailTop.vue +58 -3
  23. package/components/DisableAuthProviderModal.vue +106 -0
  24. package/{rancher-components/components/Utils/DraggableZone → components}/DraggableZone.vue +0 -0
  25. package/components/ExplorerMembers.vue +253 -30
  26. package/components/ExplorerProjectsNamespaces.vue +77 -33
  27. package/components/GrowlManager.vue +3 -3
  28. package/components/IconOrSvg.vue +149 -0
  29. package/components/LogItem.vue +69 -0
  30. package/components/PodSecurityAdmission.vue +302 -0
  31. package/components/PromptModal.vue +1 -0
  32. package/components/ResourceDetail/Masthead.vue +54 -2
  33. package/components/ResourceDetail/index.vue +12 -5
  34. package/components/ResourceList/Masthead.vue +11 -1
  35. package/components/ResourceList/ResourceLoadingIndicator.vue +12 -2
  36. package/components/ResourceList/index.vue +53 -12
  37. package/components/ResourceList/resource-list.config.js +7 -0
  38. package/components/ResourceTable.vue +31 -6
  39. package/components/SimpleBox.vue +1 -1
  40. package/components/SortableTable/THead.vue +15 -5
  41. package/components/SortableTable/index.vue +21 -10
  42. package/components/Tabbed/index.vue +20 -15
  43. package/components/__tests__/.DS_Store +0 -0
  44. package/components/__tests__/AsyncButton.test.ts +140 -0
  45. package/components/__tests__/BackLink.test.ts +33 -0
  46. package/components/__tests__/ButtonGroup.test.ts +124 -0
  47. package/components/__tests__/ClusterBadge.test.ts +32 -0
  48. package/components/__tests__/CollapsibleCard.test.ts +64 -0
  49. package/components/__tests__/ConsumptionGauge.test.ts +88 -0
  50. package/components/__tests__/CruResource.test.ts +3 -2
  51. package/components/__tests__/FixedBanner.test.ts +129 -0
  52. package/components/__tests__/GrowlManager.test.ts +147 -0
  53. package/components/__tests__/NamespaceFilter.test.ts +33 -25
  54. package/components/__tests__/PercentageBar.test.ts +32 -0
  55. package/components/__tests__/PodSecurityAdmission.test.ts +398 -0
  56. package/components/auth/AuthBanner.vue +20 -10
  57. package/components/auth/RoleDetailEdit.vue +26 -17
  58. package/components/auth/SelectPrincipal.vue +36 -5
  59. package/components/form/ArrayList.vue +3 -35
  60. package/components/form/ArrayListGrouped.vue +13 -4
  61. package/components/form/ArrayListSelect.vue +5 -5
  62. package/components/form/Error.vue +8 -0
  63. package/components/form/KeyValue.vue +39 -7
  64. package/components/form/LabeledSelect.vue +5 -2
  65. package/components/form/Labels.vue +46 -16
  66. package/components/form/Members/ClusterPermissionsEditor.vue +17 -17
  67. package/components/form/Members/MembershipEditor.vue +12 -12
  68. package/components/form/NameNsDescription.vue +1 -1
  69. package/components/form/NodeScheduling.vue +1 -1
  70. package/components/form/Probe.vue +3 -3
  71. package/components/form/ResourceQuota/Project.vue +6 -6
  72. package/components/form/ResourceTabs/index.vue +1 -6
  73. package/components/form/Security.vue +7 -6
  74. package/components/form/Select.vue +3 -2
  75. package/components/form/SelectOrCreateAuthSecret.vue +22 -29
  76. package/components/form/ServicePorts.vue +8 -0
  77. package/components/form/WorkloadPorts.vue +7 -1
  78. package/components/form/__tests__/ArrayList.test.ts +74 -0
  79. package/components/form/__tests__/ArrayListGrouped.test.ts +6 -4
  80. package/components/formatter/Checked.vue +1 -1
  81. package/components/formatter/ClusterLink.vue +5 -0
  82. package/components/formatter/IconIsDefault.vue +2 -2
  83. package/components/formatter/InternalExternalIP.vue +11 -8
  84. package/components/formatter/LiveDuration.vue +78 -0
  85. package/components/formatter/WorkloadHealthScale.vue +5 -3
  86. package/components/nav/Header.vue +6 -3
  87. package/components/nav/NamespaceFilter.vue +146 -63
  88. package/components/nav/TopLevelMenu.vue +22 -19
  89. package/components/nav/WindowManager/ContainerLogs.vue +83 -126
  90. package/components/nav/WindowManager/ContainerShell.vue +9 -7
  91. package/components/nav/WindowManager/Window.vue +2 -0
  92. package/components/nav/WindowManager/index.vue +10 -0
  93. package/config/elemental-types.js +9 -0
  94. package/config/features.js +2 -0
  95. package/config/home-links.js +4 -1
  96. package/config/pod-security-admission.ts +82 -0
  97. package/config/product/apps.js +1 -1
  98. package/config/product/auth.js +6 -5
  99. package/config/product/explorer.js +6 -6
  100. package/config/product/fleet.js +1 -1
  101. package/config/product/manager.js +6 -2
  102. package/config/secret.js +0 -1
  103. package/config/settings.ts +26 -9
  104. package/config/table-headers.js +22 -11
  105. package/config/types.js +4 -1
  106. package/content/docs/zh-hans/getting-started.md +113 -137
  107. package/content/docs/zh-hans/whats-new.md +8 -46
  108. package/creators/pkg/package-lock.json +37 -0
  109. package/creators/pkg/package.json +1 -1
  110. package/detail/catalog.cattle.io.app.vue +1 -1
  111. package/detail/pod.vue +1 -1
  112. package/detail/provisioning.cattle.io.cluster.vue +35 -9
  113. package/detail/service.vue +2 -9
  114. package/detail/workload/index.vue +0 -1
  115. package/dialog/AddClusterMemberDialog.vue +22 -28
  116. package/dialog/AddProjectMemberDialog.vue +53 -9
  117. package/dialog/DiagnosticTimingsDialog.vue +8 -7
  118. package/dialog/DrainNode.vue +44 -48
  119. package/dialog/ForceMachineRemoveDialog.vue +5 -7
  120. package/dialog/GenericPrompt.vue +15 -20
  121. package/dialog/RollbackWorkloadDialog.vue +15 -46
  122. package/dialog/RotateCertificatesDialog.vue +5 -7
  123. package/dialog/RotateEncryptionKeyDialog.vue +5 -9
  124. package/dialog/SaveAsRKETemplateDialog.vue +5 -13
  125. package/dialog/ScaleMachineDownDialog.vue +1 -1
  126. package/dialog/ScalePoolDownDialog.vue +121 -0
  127. package/edit/__tests__/management.cattle.io.setting.test.ts +3 -3
  128. package/edit/auth/azuread.vue +16 -16
  129. package/edit/auth/github.vue +8 -0
  130. package/edit/auth/googleoauth.vue +10 -1
  131. package/edit/auth/ldap/index.vue +10 -0
  132. package/edit/auth/oidc.vue +10 -0
  133. package/edit/auth/saml.vue +10 -0
  134. package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -1
  135. package/edit/cloudcredential.vue +3 -7
  136. package/edit/logging-flow/Match.vue +39 -8
  137. package/edit/logging-flow/index.vue +27 -4
  138. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +107 -0
  139. package/edit/management.cattle.io.project.vue +8 -1
  140. package/edit/management.cattle.io.setting.vue +5 -2
  141. package/edit/management.cattle.io.user.vue +7 -1
  142. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +23 -7
  143. package/edit/monitoring.coreos.com.alertmanagerconfig/types/email.vue +2 -2
  144. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +14 -6
  145. package/edit/namespace.vue +18 -4
  146. package/edit/networking.k8s.io.ingress/Certificate.vue +1 -0
  147. package/edit/networking.k8s.io.ingress/IngressClass.vue +8 -6
  148. package/edit/networking.k8s.io.ingress/RulePath.vue +12 -6
  149. package/edit/networking.k8s.io.ingress/index.vue +8 -6
  150. package/edit/persistentvolume/index.vue +30 -27
  151. package/edit/persistentvolume/plugins/cephfs.vue +29 -29
  152. package/edit/persistentvolume/plugins/csi.vue +102 -62
  153. package/edit/persistentvolume/plugins/fc.vue +19 -19
  154. package/edit/persistentvolume/plugins/iscsi.vue +45 -45
  155. package/edit/persistentvolume/plugins/rbd.vue +39 -39
  156. package/edit/persistentvolumeclaim.vue +78 -75
  157. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +11 -7
  158. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +10 -1
  159. package/edit/provisioning.cattle.io.cluster/RegistryMirrors.vue +87 -27
  160. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -6
  161. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +93 -0
  162. package/edit/provisioning.cattle.io.cluster/import.vue +1 -1
  163. package/edit/provisioning.cattle.io.cluster/index.vue +29 -6
  164. package/edit/provisioning.cattle.io.cluster/rke2.vue +440 -152
  165. package/edit/secret/index.vue +3 -7
  166. package/edit/service.vue +3 -1
  167. package/edit/storage.k8s.io.storageclass/index.vue +100 -16
  168. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +114 -0
  169. package/edit/workload/__tests__/index.test.ts +98 -0
  170. package/edit/workload/index.vue +58 -8
  171. package/edit/workload/mixins/workload.js +107 -70
  172. package/edit/workload/storage/ContainerMountPaths.vue +0 -10
  173. package/edit/workload/storage/emptyDir.vue +88 -0
  174. package/edit/workload/storage/ephemeralVolume/index.vue +1 -1
  175. package/edit/workload/storage/index.vue +8 -0
  176. package/edit/workload/storage/persistentVolumeClaim/index.vue +1 -1
  177. package/layouts/default.vue +57 -44
  178. package/list/__tests__/workload.test.ts +5 -2
  179. package/list/catalog.cattle.io.app.vue +1 -0
  180. package/list/cis.cattle.io.clusterscan.vue +1 -0
  181. package/list/fleet.cattle.io.bundle.vue +5 -6
  182. package/list/fleet.cattle.io.cluster.vue +6 -3
  183. package/list/fleet.cattle.io.clusterregistrationtoken.vue +5 -6
  184. package/list/fleet.cattle.io.gitrepo.vue +4 -9
  185. package/list/helm.cattle.io.projecthelmchart.vue +1 -5
  186. package/list/logging.banzaicloud.io.clusterflow.vue +4 -1
  187. package/list/logging.banzaicloud.io.flow.vue +6 -5
  188. package/list/management.cattle.io.cluster.vue +1 -0
  189. package/list/management.cattle.io.feature.vue +3 -4
  190. package/list/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +47 -0
  191. package/list/management.cattle.io.setting.vue +2 -2
  192. package/list/management.cattle.io.user.vue +4 -10
  193. package/list/monitoring.coreos.com.alertmanagerconfig.vue +2 -7
  194. package/list/node.vue +8 -5
  195. package/list/persistentvolume.vue +3 -3
  196. package/list/persistentvolumeclaim.vue +3 -4
  197. package/list/provisioning.cattle.io.cluster.vue +18 -19
  198. package/list/service.vue +6 -14
  199. package/list/workload.vue +43 -38
  200. package/machine-config/azure.vue +429 -60
  201. package/machine-config/pnap.vue +288 -0
  202. package/mixins/auth-config.js +1 -3
  203. package/mixins/browser-tab-visibility.js +8 -14
  204. package/mixins/chart.js +1 -1
  205. package/mixins/create-edit-view/impl.js +4 -0
  206. package/mixins/create-edit-view/index.js +4 -2
  207. package/mixins/resource-fetch-namespaced.js +98 -0
  208. package/mixins/resource-fetch.js +79 -45
  209. package/mixins/resource-manager.js +1 -23
  210. package/models/apps.controllerrevision.js +7 -0
  211. package/models/apps.daemonset.js +18 -0
  212. package/models/apps.deployment.js +44 -0
  213. package/models/apps.replicaset.js +7 -0
  214. package/models/apps.statefulset.js +18 -0
  215. package/models/batch.job.js +7 -14
  216. package/models/cluster/node.js +10 -2
  217. package/models/cluster.x-k8s.io.machine.js +26 -4
  218. package/models/cluster.x-k8s.io.machinedeployment.js +12 -2
  219. package/models/event.js +7 -0
  220. package/models/logging.banzaicloud.io.flow.js +4 -0
  221. package/models/management.cattle.io.cluster.js +1 -1
  222. package/models/management.cattle.io.clusterroletemplatebinding.js +1 -1
  223. package/models/management.cattle.io.globalrole.js +2 -2
  224. package/models/management.cattle.io.node.js +37 -2
  225. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +4 -0
  226. package/models/management.cattle.io.project.js +30 -11
  227. package/models/management.cattle.io.setting.js +1 -1
  228. package/models/management.cattle.io.user.js +37 -1
  229. package/models/namespace.js +42 -5
  230. package/models/persistentvolume.js +14 -2
  231. package/models/pod.js +15 -0
  232. package/models/projectroletemplatebinding.js +7 -0
  233. package/models/provisioning.cattle.io.cluster.js +61 -10
  234. package/models/rke-machine.cattle.io.pnapmachinetemplate.js +15 -0
  235. package/models/service.js +14 -13
  236. package/models/storage.k8s.io.storageclass.js +33 -18
  237. package/models/workload.js +38 -7
  238. package/nuxt.config.js +27 -17
  239. package/package.json +7 -7
  240. package/pages/about.vue +14 -2
  241. package/pages/c/_cluster/apps/charts/index.vue +4 -3
  242. package/pages/c/_cluster/apps/charts/install.vue +59 -22
  243. package/pages/c/_cluster/auth/config/_id.vue +6 -0
  244. package/pages/c/_cluster/auth/config/index.vue +8 -6
  245. package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
  246. package/pages/c/_cluster/auth/roles/index.vue +1 -1
  247. package/pages/c/_cluster/explorer/index.vue +12 -6
  248. package/pages/c/_cluster/longhorn/index.vue +1 -1
  249. package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +15 -4
  250. package/pages/c/_cluster/monitoring/index.vue +1 -1
  251. package/pages/c/_cluster/neuvector/index.vue +1 -1
  252. package/pages/c/_cluster/settings/performance.vue +48 -2
  253. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +34 -1
  254. package/pages/c/_cluster/uiplugins/index.vue +28 -2
  255. package/pages/diagnostic.vue +5 -4
  256. package/pages/home.vue +105 -30
  257. package/pages/prefs.vue +23 -12
  258. package/pages/rio/mesh.vue +1 -1
  259. package/pkg/dynamic-importer.lib.js +8 -0
  260. package/pkg/vue.config.js +4 -0
  261. package/plugins/dashboard-store/__tests__/mutations.spec.js +406 -0
  262. package/plugins/dashboard-store/actions.js +32 -25
  263. package/plugins/dashboard-store/getters.js +50 -33
  264. package/plugins/dashboard-store/mutations.js +134 -28
  265. package/plugins/dashboard-store/resource-class.js +21 -41
  266. package/plugins/steve/actions.js +30 -0
  267. package/plugins/steve/caches/resourceCache.js +60 -0
  268. package/plugins/steve/getters.js +44 -1
  269. package/plugins/steve/mutations.js +97 -36
  270. package/plugins/steve/resourceWatcher.js +277 -0
  271. package/plugins/steve/schema.utils.js +25 -0
  272. package/plugins/steve/subscribe.js +288 -115
  273. package/plugins/steve/worker/index.js +17 -0
  274. package/plugins/steve/worker/web-worker.advanced.js +302 -0
  275. package/plugins/steve/{web-worker.steve-sub-worker.js → worker/web-worker.basic.js} +3 -44
  276. package/rancher-components/Card/Card.vue +3 -3
  277. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +1 -0
  278. package/rancher-components/StringList/StringList.test.ts +45 -420
  279. package/rancher-components/StringList/StringList.vue +1 -10
  280. package/rancher-components/components/Banner/Banner.test.ts +44 -0
  281. package/rancher-components/components/Banner/Banner.vue +129 -61
  282. package/rancher-components/components/Form/Checkbox/Checkbox.test.ts +13 -22
  283. package/rancher-components/components/Form/Checkbox/Checkbox.vue +8 -6
  284. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.test.ts +9 -9
  285. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +0 -1
  286. package/rancher-components/components/StringList/StringList.test.ts +7 -7
  287. package/rancher-components/components/StringList/StringList.vue +21 -15
  288. package/scripts/test-plugins-build.sh +8 -0
  289. package/static/loading-indicator.html +1 -1
  290. package/store/index.js +54 -3
  291. package/store/plugins.js +0 -17
  292. package/store/pnap.js +128 -0
  293. package/store/prefs.js +4 -2
  294. package/store/type-map.js +55 -13
  295. package/types/pod-security-admission.ts +36 -0
  296. package/types/shell/index.d.ts +496 -396
  297. package/utils/__tests__/object.test.ts +17 -1
  298. package/utils/__tests__/pod-security-admission.test.ts +61 -0
  299. package/utils/async.ts +36 -0
  300. package/utils/color.js +45 -0
  301. package/utils/crypto/browserHashUtils.js +18 -0
  302. package/utils/dynamic-importer.js +8 -0
  303. package/utils/install-redirect.js +1 -1
  304. package/utils/object.js +24 -0
  305. package/utils/pod-security-admission.ts +39 -0
  306. package/utils/socket.js +61 -24
  307. package/utils/string.js +2 -0
  308. package/utils/svg-filter.js +301 -0
  309. package/utils/time.js +49 -0
  310. package/utils/validators/cidr.js +4 -0
  311. package/utils/validators/formRules/__tests__/index.test.ts +23 -3
  312. package/utils/validators/formRules/index.ts +14 -0
  313. package/config/product/harvester-manager.js +0 -162
  314. package/edit/harvesterhci.io.management.cluster.vue +0 -153
  315. package/list/harvesterhci.io.management.cluster.vue +0 -241
  316. package/machine-config/harvester.vue +0 -693
  317. package/models/harvesterhci.io.management.cluster.js +0 -228
  318. package/pages/c/_cluster/harvesterManager/index.vue +0 -24
  319. package/rancher-components/Card/Card.test.ts +0 -39
  320. package/rancher-components/Utils/DraggableZone/DraggableZone.vue +0 -181
  321. package/rancher-components/Utils/DraggableZone/index.ts +0 -1
  322. package/rancher-components/components/Utils/DraggableZone/index.ts +0 -1
@@ -0,0 +1,69 @@
1
+ <script>
2
+ import day from 'dayjs';
3
+ import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs';
4
+ import { escapeHtml } from '@shell/utils/string';
5
+
6
+ export default {
7
+ props: {
8
+ source: {
9
+ type: Object,
10
+ default: () => {}
11
+ }
12
+ },
13
+
14
+ computed: {
15
+ timeFormatStr() {
16
+ const dateFormat = escapeHtml( this.$store.getters['prefs/get'](DATE_FORMAT));
17
+ const timeFormat = escapeHtml( this.$store.getters['prefs/get'](TIME_FORMAT));
18
+
19
+ return `${ dateFormat } ${ timeFormat }`;
20
+ },
21
+ },
22
+
23
+ methods: {
24
+ format(time) {
25
+ if ( !time ) {
26
+ return '';
27
+ }
28
+
29
+ return day(time).format(this.timeFormatStr);
30
+ }
31
+ }
32
+ };
33
+ </script>
34
+
35
+ <template>
36
+ <div class="line">
37
+ <span class="time">{{ format(source.time) }}</span>
38
+ <span
39
+ class="msg"
40
+ v-html="source.msg"
41
+ />
42
+ </div>
43
+ </template>
44
+
45
+ <style lang='scss' scoped>
46
+ .line {
47
+ font-family: Menlo,Consolas,monospace;
48
+ color: var(--logs-text);
49
+ display:flex;
50
+ }
51
+
52
+ .time {
53
+ white-space: nowrap;
54
+ display: none;
55
+ width: 0;
56
+ padding-right: 15px;
57
+ user-select: none;
58
+ }
59
+
60
+ .msg {
61
+ white-space: pre;
62
+
63
+ .highlight {
64
+ color: var(--logs-highlight);
65
+ background-color: var(--logs-highlight-bg);
66
+ }
67
+ }
68
+
69
+ </style>
@@ -0,0 +1,302 @@
1
+ <script lang="ts">
2
+ import Vue from 'vue';
3
+ import { _VIEW, _CREATE } from '@shell/config/query-params';
4
+ import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
5
+ import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
6
+ import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
7
+ import { PSADimension, PSAMode } from '@shell/types/pod-security-admission';
8
+ import {
9
+ PSADefaultLevel,
10
+ PSADefaultVersion, PSADimensions, PSALevels, PSAModes
11
+ } from '@shell/config/pod-security-admission';
12
+ import { pickBy, toDictionary } from '@shell/utils/object';
13
+
14
+ interface PSAControl { active: boolean, level: string, version: string }
15
+ const getPsaControl = (): PSAControl => ({
16
+ active: false,
17
+ level: PSADefaultLevel,
18
+ version: ''
19
+ });
20
+
21
+ // Type and function for exemptions form builder
22
+ interface PSAExemptionControl { active: boolean, value: string }
23
+ const getExemptionControl = (): PSAExemptionControl => ({
24
+ active: false,
25
+ value: ''
26
+ });
27
+
28
+ export default Vue.extend({
29
+ components: {
30
+ Checkbox, LabeledSelect, LabeledInput
31
+ },
32
+ props: {
33
+ /**
34
+ * List of labels used for the resource
35
+ * Note: PSA labels are always paired
36
+ */
37
+ labels: {
38
+ type: Object as () => Record<string, string>,
39
+ default: () => ({})
40
+ },
41
+
42
+ labelsAlwaysActive: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+
47
+ /**
48
+ * Map editing capabilities to the component
49
+ */
50
+ mode: {
51
+ type: String,
52
+ required: true
53
+ },
54
+
55
+ /**
56
+ * List of exemptions used for the resource
57
+ */
58
+ exemptions: {
59
+ type: Object as () => Record<PSADimension, string[]>,
60
+ default: () => ({} as Record<PSADimension, string[]>)
61
+ },
62
+
63
+ /**
64
+ * Prefix used for setting labels
65
+ */
66
+ labelsPrefix: {
67
+ type: String,
68
+ default: ''
69
+ },
70
+
71
+ /**
72
+ * Inherited global identifier prefix for tests
73
+ * Define a term based on the parent component to avoid conflicts on multiple components
74
+ */
75
+ componentTestid: {
76
+ type: String,
77
+ default: 'pod-security-admission'
78
+ }
79
+ },
80
+
81
+ data() {
82
+ return {
83
+ // Generate PSA form controls
84
+ psaControls: toDictionary(PSAModes, getPsaControl) as Record<PSAMode, PSAControl>,
85
+ psaExemptionsControls: toDictionary(PSADimensions, getExemptionControl) as Record<PSADimension, PSAExemptionControl>,
86
+ options: PSALevels.map(level => ({
87
+ value: level,
88
+ label: this.t(`podSecurityAdmission.labels.${ level }`)
89
+ })),
90
+ };
91
+ },
92
+
93
+ watch: {},
94
+
95
+ computed: {
96
+ isView(): boolean {
97
+ return this.mode === _VIEW;
98
+ },
99
+
100
+ /**
101
+ * Enable exemption form if any
102
+ */
103
+ hasExemptions(): boolean {
104
+ return Object.keys(this.exemptions).length > 0;
105
+ },
106
+ },
107
+
108
+ created() {
109
+ // Assign values to the form, overriding existing values
110
+ this.psaControls = {
111
+ ...this.psaControls,
112
+ ...this.getPsaControls()
113
+ };
114
+
115
+ this.psaExemptionsControls = this.getPsaExemptions();
116
+
117
+ // Emit initial value on creation if labels always active, as default predefined values are required
118
+ if (this.mode === _CREATE && this.labelsAlwaysActive) {
119
+ this.updateLabels();
120
+ this.updateExemptions();
121
+ }
122
+ },
123
+
124
+ methods: {
125
+ /**
126
+ * Filter out existing PSA labels and emit existing labels with new PSA ones
127
+ */
128
+ updateLabels(): void {
129
+ const nonPSALabels = pickBy(this.labels, (_, key) => !key.includes(this.labelsPrefix));
130
+ const labels = PSAModes.reduce((acc, mode) => {
131
+ return this.psaControls[mode].active || this.labelsAlwaysActive ? {
132
+ ...acc,
133
+ // Set default level if none
134
+ [`${ this.labelsPrefix }${ mode }`]: this.psaControls[mode].level || PSADefaultLevel,
135
+ // Set default version if none
136
+ [`${ this.labelsPrefix }${ mode }-version`]: this.psaControls[mode].version || PSADefaultVersion
137
+ } : acc;
138
+ }, nonPSALabels);
139
+
140
+ this.$emit('updateLabels', labels);
141
+ },
142
+
143
+ /**
144
+ * Emit active exemptions in required format
145
+ */
146
+ updateExemptions(): void {
147
+ const exemptions = PSADimensions.reduce((acc, dimension) => {
148
+ const value = this.psaExemptionsControls[dimension].value.split(',').map(value => value.trim());
149
+ const active = this.psaExemptionsControls[dimension].active;
150
+
151
+ return {
152
+ ...acc,
153
+ [dimension]: active && value ? value : []
154
+ };
155
+ }, {});
156
+
157
+ this.$emit('updateExemptions', exemptions);
158
+ },
159
+
160
+ /**
161
+ * Generate form controls based on PSA labels in the provided dictionary
162
+ */
163
+ getPsaControls(): Record<PSAMode, PSAControl> {
164
+ return PSAModes.reduce((acc, mode) => {
165
+ const level = this.labels[`${ this.labelsPrefix }${ mode }`];
166
+ // Retrieve version, hiding the value 'latest' from the user
167
+ const version = (this.labels[`${ this.labelsPrefix }${ mode }-version`] || '').replace(PSADefaultVersion, '');
168
+
169
+ return level ? {
170
+ ...acc,
171
+ [mode]: {
172
+ active: true,
173
+ level,
174
+ version
175
+ }
176
+ } : acc;
177
+ }, {} as Record<PSAMode, PSAControl>);
178
+ },
179
+
180
+ /**
181
+ * Generate form exemptions based on PSA exemptions provided dictionary
182
+ */
183
+ getPsaExemptions(): Record<PSADimension, PSAExemptionControl> {
184
+ return PSADimensions.reduce((acc, dimension) => {
185
+ const values = (this.exemptions[dimension] || []).map(value => value.trim()).join(',');
186
+
187
+ return {
188
+ ...acc,
189
+ [dimension]: {
190
+ active: !!values.length,
191
+ value: values
192
+ }
193
+ };
194
+ }, {}) as Record<PSADimension, PSAExemptionControl>;
195
+ },
196
+
197
+ /**
198
+ * Add checks on input for PSA controls to be active or not, allowing white cases
199
+ */
200
+ isPsaControlDisabled(active: boolean): boolean {
201
+ return !this.labelsAlwaysActive && (!active || this.isView);
202
+ }
203
+ }
204
+ });
205
+ </script>
206
+
207
+ <template>
208
+ <div class="psa">
209
+ <!-- PSA -->
210
+ <p class="mb-30">
211
+ <t k="podSecurityAdmission.description" />
212
+ </p>
213
+
214
+ <div
215
+ v-for="(psaControl, level, i) in psaControls"
216
+ :key="'psaControl-' + i"
217
+ class="row row--y-center mb-20"
218
+ >
219
+ <span class="col span-2">
220
+ <Checkbox
221
+ v-if="!labelsAlwaysActive"
222
+ v-model="psaControl.active"
223
+ :data-testid="componentTestid + '--psaControl-' + i + '-active'"
224
+ :label="level"
225
+ :label-key="`podSecurityAdmission.labels.${ level }`"
226
+ :disabled="isView"
227
+ @input="updateLabels()"
228
+ />
229
+ <p v-else>
230
+ <t :k="`podSecurityAdmission.labels.${level}`" />
231
+ </p>
232
+ </span>
233
+
234
+ <span
235
+ class="
236
+ col
237
+ span-4"
238
+ >
239
+ <LabeledSelect
240
+ v-model="psaControl.level"
241
+ :data-testid="componentTestid + '--psaControl-' + i + '-level'"
242
+ :disabled="isPsaControlDisabled(psaControl.active)"
243
+ :options="options"
244
+ :mode="mode"
245
+ @input="updateLabels()"
246
+ />
247
+ </span>
248
+
249
+ <span class="col span-4">
250
+ <LabeledInput
251
+ v-model="psaControl.version"
252
+ :data-testid="componentTestid + '--psaControl-' + i + '-version'"
253
+ :disabled="isPsaControlDisabled(psaControl.active)"
254
+ :options="options"
255
+ :placeholder="t('podSecurityAdmission.version.placeholder', { psaControl: mode })"
256
+ :mode="mode"
257
+ @input="updateLabels()"
258
+ />
259
+ </span>
260
+ </div>
261
+
262
+ <!-- Exemptions -->
263
+ <template v-if="hasExemptions">
264
+ <slot name="title">
265
+ <h3>
266
+ <t k="podSecurityAdmission.exemptions.title" />
267
+ </h3>
268
+ </slot>
269
+ <p class="mb-30">
270
+ <t k="podSecurityAdmission.exemptions.description" />
271
+ </p>
272
+
273
+ <div
274
+ v-for="(psaExemptionsControl, dimension, i) in psaExemptionsControls"
275
+ :key="'psaExemptionsControl-' + i"
276
+ class="row row--y-center mb-20"
277
+ >
278
+ <span class="col span-2">
279
+ <Checkbox
280
+ v-model="psaExemptionsControl.active"
281
+ :data-testid="componentTestid + '--psaExemptionsControl-' + i + '-active'"
282
+ :label="dimension"
283
+ :label-key="`podSecurityAdmission.labels.${ dimension }`"
284
+ :disabled="isView"
285
+ @input="updateExemptions()"
286
+ />
287
+ </span>
288
+ <span class="col span-8">
289
+ <LabeledInput
290
+ v-model="psaExemptionsControl.value"
291
+ :data-testid="componentTestid + '--psaExemptionsControl-' + i + '-value'"
292
+ :disabled="(isView || !psaExemptionsControl.active)"
293
+ :options="options"
294
+ :placeholder="t('podSecurityAdmission.exemptions.placeholder', { psaExemptionsControl: dimension })"
295
+ :mode="mode"
296
+ @input="updateExemptions()"
297
+ />
298
+ </span>
299
+ </div>
300
+ </template>
301
+ </div>
302
+ </template>
@@ -88,6 +88,7 @@ export default {
88
88
  @closed="close()"
89
89
  >
90
90
  <component
91
+ v-bind="modalData.componentProps || {}"
91
92
  :is="component"
92
93
  v-if="opened && component"
93
94
  :resources="resources"
@@ -82,6 +82,10 @@ export default {
82
82
  },
83
83
  },
84
84
 
85
+ data() {
86
+ return { DETAIL_VIEW: _DETAIL };
87
+ },
88
+
85
89
  computed: {
86
90
  schema() {
87
91
  const inStore = this.storeOverride || this.$store.getters['currentStore'](this.resource);
@@ -125,6 +129,10 @@ export default {
125
129
  return null;
126
130
  },
127
131
 
132
+ detailsAction() {
133
+ return this.value?.detailsAction;
134
+ },
135
+
128
136
  shouldHifenize() {
129
137
  return (this.mode === 'view' || this.mode === 'edit') && this.resourceSubtype?.length && this.value?.nameDisplay?.length;
130
138
  },
@@ -354,6 +362,10 @@ export default {
354
362
 
355
363
  return parent?.location;
356
364
  },
365
+
366
+ hideNamespaceLocation() {
367
+ return this.$store.getters['currentProduct'].hideNamespaceLocation;
368
+ },
357
369
  },
358
370
 
359
371
  methods: {
@@ -368,6 +380,18 @@ export default {
368
380
 
369
381
  toggleSensitiveData(e) {
370
382
  this.$store.dispatch('prefs/set', { key: HIDE_SENSITIVE, value: !!e });
383
+ },
384
+
385
+ invokeDetailsAction() {
386
+ const action = this.detailsAction;
387
+
388
+ if (action) {
389
+ const fn = this.value[action.action];
390
+
391
+ if (fn) {
392
+ fn.apply(this.value, []);
393
+ }
394
+ }
371
395
  }
372
396
  }
373
397
  };
@@ -375,7 +399,7 @@ export default {
375
399
 
376
400
  <template>
377
401
  <div class="masthead">
378
- <header class="header-layout">
402
+ <header>
379
403
  <div class="title">
380
404
  <div class="primaryheader">
381
405
  <h1>
@@ -407,7 +431,18 @@ export default {
407
431
  >
408
432
  <span v-if="isNamespace && project">{{ t("resourceDetail.masthead.project") }}: <nuxt-link :to="project.detailLocation">{{ project.nameDisplay }}</nuxt-link></span>
409
433
  <span v-else-if="isWorkspace">{{ t("resourceDetail.masthead.workspace") }}: <nuxt-link :to="workspaceLocation">{{ namespace }}</nuxt-link></span>
410
- <span v-else-if="namespace && !hasMultipleNamespaces">{{ t("resourceDetail.masthead.namespace") }}: <nuxt-link :to="namespaceLocation">{{ namespace }}</nuxt-link></span>
434
+ <span v-else-if="namespace && !hasMultipleNamespaces">
435
+ {{ t("resourceDetail.masthead.namespace") }}:
436
+ <nuxt-link
437
+ v-if="!hideNamespaceLocation"
438
+ :to="namespaceLocation"
439
+ >
440
+ {{ namespace }}
441
+ </nuxt-link>
442
+ <span v-else>
443
+ {{ namespace }}
444
+ </span>
445
+ </span>
411
446
  <span v-if="parent.showAge">{{ t("resourceDetail.masthead.age") }}: <LiveDate
412
447
  class="live-date"
413
448
  :value="value.creationTimestamp"
@@ -418,11 +453,21 @@ export default {
418
453
  <slot name="right">
419
454
  <div class="actions-container">
420
455
  <div class="actions">
456
+ <button
457
+ v-if="detailsAction && currentView === DETAIL_VIEW && isView"
458
+ type="button"
459
+ class="btn role-primary actions mr-10"
460
+ :disabled="!detailsAction.enabled"
461
+ @click="invokeDetailsAction"
462
+ >
463
+ {{ detailsAction.label }}
464
+ </button>
421
465
  <ButtonGroup
422
466
  v-if="showSensitiveToggle"
423
467
  :value="!!hideSensitiveData"
424
468
  icon-size="lg"
425
469
  :options="sensitiveOptions"
470
+ class="mr-10"
426
471
  @input="toggleSensitiveData"
427
472
  />
428
473
 
@@ -430,6 +475,7 @@ export default {
430
475
  v-if="viewOptions && isView"
431
476
  v-model="currentView"
432
477
  :options="viewOptions"
478
+ class="mr-10"
433
479
  />
434
480
 
435
481
  <button
@@ -522,4 +568,10 @@ export default {
522
568
  }
523
569
  }
524
570
 
571
+ div.actions-container > div.actions {
572
+ display: flex;
573
+ flex-direction: row;
574
+ justify-content: flex-end;
575
+ }
576
+
525
577
  </style>
@@ -26,7 +26,8 @@ function modeFor(route) {
26
26
  }
27
27
  }
28
28
 
29
- async function getYaml(model) {
29
+ async function getYaml(store, model) {
30
+ const inStore = store.getters['currentStore'](model.type);
30
31
  let yaml;
31
32
  const opt = { headers: { accept: 'application/yaml' } };
32
33
 
@@ -34,7 +35,9 @@ async function getYaml(model) {
34
35
  yaml = (await model.followLink('view', opt)).data;
35
36
  }
36
37
 
37
- return yaml;
38
+ const cleanedYaml = await store.dispatch(`${ inStore }/cleanForDownload`, yaml);
39
+
40
+ return cleanedYaml;
38
41
  }
39
42
 
40
43
  export default {
@@ -146,6 +149,11 @@ export default {
146
149
  initialModel = await store.dispatch(`${ inStore }/clone`, { resource: liveModel });
147
150
  model = await store.dispatch(`${ inStore }/clone`, { resource: liveModel });
148
151
 
152
+ if (model.forceYaml === true) {
153
+ as = _YAML;
154
+ this.as = as;
155
+ }
156
+
149
157
  if ( as === _YAML ) {
150
158
  yaml = createYaml(schemas, resource, data);
151
159
  }
@@ -182,7 +190,7 @@ export default {
182
190
  initialModel = await store.dispatch(`${ inStore }/clone`, { resource: liveModel });
183
191
 
184
192
  if ( as === _YAML ) {
185
- yaml = await getYaml(liveModel);
193
+ yaml = await getYaml(this.$store, liveModel);
186
194
  }
187
195
 
188
196
  if ( as === _GRAPH ) {
@@ -222,7 +230,6 @@ export default {
222
230
  this.value.applyDefaults(this, realMode);
223
231
  }
224
232
  },
225
-
226
233
  data() {
227
234
  return {
228
235
  chartData: null,
@@ -306,7 +313,7 @@ export default {
306
313
  // Auto refresh YAML when the model changes
307
314
  async 'value.metadata.resourceVersion'(a, b) {
308
315
  if ( this.mode === _VIEW && this.as === _YAML && a && b && a !== b) {
309
- this.yaml = await getYaml(this.liveModel);
316
+ this.yaml = await getYaml(this.$store, this.liveModel);
310
317
  }
311
318
  }
312
319
  },
@@ -65,6 +65,11 @@ export default {
65
65
  default: false
66
66
  },
67
67
 
68
+ loadNamespace: {
69
+ type: String,
70
+ default: null
71
+ },
72
+
68
73
  showIncrementalLoadingIndicator: {
69
74
  type: Boolean,
70
75
  default: false
@@ -163,7 +168,7 @@ export default {
163
168
  </script>
164
169
 
165
170
  <template>
166
- <header class="header-layout">
171
+ <header>
167
172
  <slot name="typeDescription">
168
173
  <TypeDescription :resource="resource" />
169
174
  </slot>
@@ -178,6 +183,7 @@ export default {
178
183
  v-if="showIncrementalLoadingIndicator"
179
184
  :resources="loadResources"
180
185
  :indeterminate="loadIndeterminate"
186
+ :namespace="loadNamespace"
181
187
  />
182
188
  </div>
183
189
  <div class="actions-container">
@@ -217,4 +223,8 @@ export default {
217
223
  margin: 0;
218
224
  }
219
225
  }
226
+
227
+ header {
228
+ margin-bottom: 20px;
229
+ }
220
230
  </style>
@@ -16,7 +16,11 @@ export default {
16
16
  indeterminate: {
17
17
  type: Boolean,
18
18
  default: false,
19
- }
19
+ },
20
+ namespace: {
21
+ type: String,
22
+ default: undefined
23
+ },
20
24
  },
21
25
 
22
26
  data() {
@@ -40,6 +44,10 @@ export default {
40
44
  // Have we loaded all resources for the types that are needed
41
45
  haveAll() {
42
46
  return this.resources.reduce((acc, r) => {
47
+ if (this.namespace) {
48
+ return acc && this.$store.getters[`${ this.inStore }/haveAllNamespace`](r, this.namespace);
49
+ }
50
+
43
51
  return acc && this.$store.getters[`${ this.inStore }/haveAll`](r);
44
52
  }, true);
45
53
  },
@@ -49,7 +57,9 @@ export default {
49
57
  const clusterCounts = this.$store.getters[`${ this.inStore }/all`](COUNT);
50
58
 
51
59
  return this.resources.reduce((acc, r) => {
52
- const count = clusterCounts?.[0]?.counts?.[r]?.summary?.count || 0;
60
+ const resourceCounts = clusterCounts?.[0]?.counts?.[r];
61
+ const resourceCount = this.namespace ? resourceCounts?.namespaces?.[this.namespace]?.count : resourceCounts?.summary?.count;
62
+ const count = resourceCount || 0;
53
63
 
54
64
  return acc + count;
55
65
  }, 0);