@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
@@ -1,4 +1,6 @@
1
- import { clone, get, getter, isEmpty } from '@shell/utils/object';
1
+ import {
2
+ clone, get, getter, isEmpty, toDictionary
3
+ } from '@shell/utils/object';
2
4
 
3
5
  describe('fx: get', () => {
4
6
  describe('should return value of an object', () => {
@@ -126,3 +128,17 @@ describe('fx: isEmpty', () => {
126
128
  expect(result).toBe(expected);
127
129
  });
128
130
  });
131
+
132
+ describe('fX: toDictionary', () => {
133
+ it('should return a dictionary from an array', () => {
134
+ const array = ['a', 'b', 'c'];
135
+ const asd = (value: string) => value.toUpperCase();
136
+ const expectation = {
137
+ a: 'A', b: 'B', c: 'C'
138
+ };
139
+
140
+ const result = toDictionary(array, asd);
141
+
142
+ expect(result).toStrictEqual(expectation);
143
+ });
144
+ });
@@ -0,0 +1,61 @@
1
+ import { PSA } from '@shell/types/pod-security-admission';
2
+ import { getPSATooltipsDescription } from '@shell/utils/pod-security-admission';
3
+
4
+ describe('fX: getPSATooltipsDescription', () => {
5
+ it('should return empty object if no labels', () => {
6
+ const resource = { metadata: { labels: {} } } as Partial<PSA> as PSA;
7
+
8
+ const result = getPSATooltipsDescription(resource);
9
+
10
+ expect(result).toStrictEqual({});
11
+ });
12
+
13
+ it('should return prettified dictionary of labels', () => {
14
+ const resource = { metadata: { labels: { 'pod-security.kubernetes.io/enforce': 'restricted' } } } as Partial<PSA> as PSA;
15
+
16
+ const result = getPSATooltipsDescription(resource);
17
+
18
+ expect(result).toStrictEqual({ 'pod-security.kubernetes.io/enforce': 'Enforce Restricted (latest)' });
19
+ });
20
+
21
+ it('should exclude non-PSA labels', () => {
22
+ const resource = {
23
+ metadata: {
24
+ labels: {
25
+ 'field.cattle.io/projectId': 'p-68z77',
26
+ 'kubernetes.io/metadata.name': 'psa-test-ns',
27
+ 'pod-security.kubernetes.io/enforce': 'privileged',
28
+ bananas: 'potatoes'
29
+ },
30
+ }
31
+ } as Partial<PSA> as PSA;
32
+
33
+ const result = getPSATooltipsDescription(resource);
34
+
35
+ expect(result).toStrictEqual({ 'pod-security.kubernetes.io/enforce': 'Enforce Privileged (latest)' });
36
+ });
37
+
38
+ it('should return prettified dictionary of labels with version', () => {
39
+ const version = '1.0.0';
40
+ const resource = {
41
+ metadata: {
42
+ labels: {
43
+ 'pod-security.kubernetes.io/enforce': 'privileged',
44
+ 'pod-security.kubernetes.io/enforce-version': version
45
+ }
46
+ }
47
+ } as Partial<PSA> as PSA;
48
+
49
+ const result = getPSATooltipsDescription(resource);
50
+
51
+ expect(result).toStrictEqual({ 'pod-security.kubernetes.io/enforce': `Enforce Privileged (${ version })` });
52
+ });
53
+
54
+ it(`should return prettified dictionary of labels with 'latest' as default version if none`, () => {
55
+ const resource = { metadata: { labels: { 'pod-security.kubernetes.io/enforce': 'privileged' } } } as Partial<PSA> as PSA;
56
+
57
+ const result = getPSATooltipsDescription(resource);
58
+
59
+ expect(result).toStrictEqual({ 'pod-security.kubernetes.io/enforce': `Enforce Privileged (latest)` });
60
+ });
61
+ });
package/utils/async.ts ADDED
@@ -0,0 +1,36 @@
1
+ export const waitFor = (testFn: Function, msg = '', timeoutMs = 3000000, intervalMs = 500, log = false) => {
2
+ gatedLog('Starting wait for', msg);
3
+
4
+ return new Promise((resolve, reject) => {
5
+ if (testFn()) {
6
+ gatedLog('Wait for', msg || 'unknown', 'done immediately');
7
+ resolve(this);
8
+ }
9
+ const timeout = setTimeout(() => {
10
+ gatedLog('Wait for', msg, 'timed out');
11
+ clearInterval(interval);
12
+ clearTimeout(timeout);
13
+ if (msg) {
14
+ reject(new Error(`Failed waiting for: ${ msg }`));
15
+ } else {
16
+ throw new Error(`waitFor timed out after ${ timeoutMs / 1000 } seconds`);
17
+ }
18
+ }, timeoutMs);
19
+ const interval = setInterval(() => {
20
+ if ( testFn() ) {
21
+ gatedLog('Wait for', msg, 'done');
22
+ clearInterval(interval);
23
+ clearTimeout(timeout);
24
+ resolve(this);
25
+ } else if (msg) {
26
+ gatedLog('Wait for', msg, 'not done yet');
27
+ }
28
+ }, intervalMs);
29
+ });
30
+
31
+ function gatedLog(...args: any[]) {
32
+ if (log) {
33
+ console.log(...args); // eslint-disable-line no-console
34
+ }
35
+ }
36
+ };
package/utils/color.js CHANGED
@@ -63,6 +63,11 @@ const DARK_CONTRAST_COLORS = {
63
63
 
64
64
  };
65
65
 
66
+ const STANDARD_COLORS = {
67
+ black: '#000000',
68
+ white: '#ffffff',
69
+ };
70
+
66
71
  // contrastColor(color, {light, dark}) returns which of 2 options is higher contrast with color
67
72
  export function contrastColor(color, contrastOptions = LIGHT_CONTRAST_COLORS) {
68
73
  let out = contrastOptions.light;
@@ -90,3 +95,43 @@ export function textColor(color) {
90
95
 
91
96
  return (brightness > 125) ? 'black' : 'white';
92
97
  }
98
+
99
+ export function hexToRgb(hex) {
100
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
101
+
102
+ return result ? {
103
+ r: parseInt(result[1], 16),
104
+ g: parseInt(result[2], 16),
105
+ b: parseInt(result[3], 16)
106
+ } : null;
107
+ }
108
+
109
+ export function mapStandardColors(color) {
110
+ return STANDARD_COLORS[color] || color;
111
+ }
112
+
113
+ export function rgbToRgb(rgb) {
114
+ const result = /^rgb\(([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})\)$/i.exec(rgb);
115
+
116
+ return result ? {
117
+ r: parseInt(result[1], 10),
118
+ g: parseInt(result[2], 10),
119
+ b: parseInt(result[3], 10)
120
+ } : null;
121
+ }
122
+
123
+ export function colorToRgb(color) {
124
+ let value;
125
+
126
+ if (color.startsWith('rgb(')) {
127
+ value = rgbToRgb(color);
128
+ } else if (color.startsWith('#')) {
129
+ value = hexToRgb(color);
130
+ } else {
131
+ console.warn(`Unable to parse color: ${ color }`); // eslint-disable-line no-console
132
+ }
133
+
134
+ return value || {
135
+ r: 0, g: 0, b: 0
136
+ };
137
+ }
@@ -1,5 +1,23 @@
1
1
  import { Buffer } from 'buffer';
2
2
 
3
+ function hashString(str) {
4
+ let hash = 0;
5
+
6
+ for (let i = 0; i < str.length; i++) {
7
+ const char = str.charCodeAt(i);
8
+
9
+ hash = (hash << 5) - hash + char;
10
+ hash &= hash;
11
+ }
12
+
13
+ return new Uint32Array([hash])[0].toString(36);
14
+ }
15
+
16
+ // Quick, simple hash function to generate hash for an object
17
+ export function hashObj(obj) {
18
+ return hashString(JSON.stringify(obj, null, 2));
19
+ }
20
+
3
21
  /**
4
22
  * @api private
5
23
  */
@@ -122,3 +122,11 @@ export function resolveDetail(key) {
122
122
  export function resolveWindowComponent(key) {
123
123
  return require.resolve(`@shell/components/nav/WindowManager/${ key }`);
124
124
  }
125
+
126
+ export function resolveMachineConfigComponent(key) {
127
+ return require.resolve(`@shell/machine-config/${ key }`);
128
+ }
129
+
130
+ export function resolveCloudCredentialComponent(key) {
131
+ return require.resolve(`@shell/cloud-credential/${ key }`);
132
+ }
@@ -26,7 +26,7 @@ export default function(product, chartName, defaultResourceOrRoute, install = tr
26
26
  } else if (install) {
27
27
  // The product is not installed, redirect to the details chart
28
28
 
29
- await store.dispatch('catalog/load');
29
+ await store.dispatch('catalog/load', { force: true });
30
30
 
31
31
  const chart = store.getters['catalog/chart']({ chartName });
32
32
 
package/utils/object.js CHANGED
@@ -353,3 +353,27 @@ export function applyChangeset(obj, changeset) {
353
353
 
354
354
  return obj;
355
355
  }
356
+
357
+ /**
358
+ * Creates an object composed of the `object` properties `predicate` returns
359
+ */
360
+ export function pickBy(obj = {}, predicate = (value, key) => false) {
361
+ return Object.entries(obj)
362
+ .reduce((res, [key, value]) => {
363
+ if (predicate(value, key)) {
364
+ res[key] = value;
365
+ }
366
+
367
+ return res;
368
+ }, {});
369
+ }
370
+
371
+ /**
372
+ * Convert list to dictionary from a given function
373
+ * @param {*} array
374
+ * @param {*} callback
375
+ * @returns
376
+ */
377
+ export const toDictionary = (array, callback) => Object.assign(
378
+ {}, ...array.map(item => ({ [item]: callback(item) }))
379
+ );
@@ -0,0 +1,39 @@
1
+ import { reduce, filter, keys } from 'lodash';
2
+ import { PSALabelPrefix, PSALabelsNamespaces } from '@shell/config/pod-security-admission';
3
+ import { camelToTitle } from '@shell/utils/string';
4
+ import { PSA } from '@shell/types/pod-security-admission';
5
+
6
+ /**
7
+ * Return PSA labels present in the resource
8
+ * @returns string[]
9
+ */
10
+ export const getPSALabels = (resource: PSA): string[] => filter(keys(resource?.metadata?.labels), key => PSALabelsNamespaces.includes(key));
11
+
12
+ /**
13
+ * Return boolean value if the label is a PSA label
14
+ * @returns Boolean
15
+ */
16
+ export const hasPSALabels = (resource: PSA): boolean => getPSALabels(resource).length > 0;
17
+
18
+ /**
19
+ * Generate tooltips dictionary from a given PSA namespaced label pair of key and values
20
+ */
21
+ export const getPSATooltipsDescription = (resource: PSA): Record<string, string> => reduce(
22
+ resource?.metadata?.labels,
23
+ (acc, value, key) => {
24
+ const isPSA = PSALabelsNamespaces.includes(key);
25
+
26
+ // Retrieve version from paired label ending with `-version`
27
+ const suffix = '-version';
28
+ const isVersionLabel = key.includes(suffix);
29
+ const versionLabel = resource?.metadata?.labels[`${ key }${ suffix }`];
30
+ const version = versionLabel || 'latest';
31
+
32
+ // Add SPA labels and discard paired version label
33
+ return isPSA && !isVersionLabel ? {
34
+ ...acc,
35
+ [key]: `${ camelToTitle(key.replace(PSALabelPrefix, '')) } ${ camelToTitle(value) } (${ version })`
36
+ } : acc;
37
+ },
38
+ { }
39
+ );
package/utils/socket.js CHANGED
@@ -10,8 +10,9 @@ const INSECURE = 'ws://';
10
10
  const SECURE = 'wss://';
11
11
 
12
12
  const STATE_DISCONNECTED = 'disconnected';
13
- const STATE_CONNECTING = 'connecting';
14
- const STATE_CONNECTED = 'connected';
13
+
14
+ export const STATE_CONNECTING = 'connecting';
15
+ export const STATE_CONNECTED = 'connected';
15
16
  const STATE_CLOSING = 'closing';
16
17
  const STATE_RECONNECTING = 'reconnecting';
17
18
 
@@ -23,6 +24,9 @@ export const EVENT_FRAME_TIMEOUT = 'frame_timeout';
23
24
  export const EVENT_CONNECT_ERROR = 'connect_error';
24
25
  export const EVENT_DISCONNECT_ERROR = 'disconnect_error';
25
26
 
27
+ export const NO_WATCH = 'NO_WATCH';
28
+ export const NO_SCHEMA = 'NO_SCHEMA';
29
+
26
30
  export default class Socket extends EventTarget {
27
31
  url;
28
32
  autoReconnect = true;
@@ -33,6 +37,7 @@ export default class Socket extends EventTarget {
33
37
  protocol = null;
34
38
  maxTries = null;
35
39
  tries = 0;
40
+ idAsTimestamp = false;
36
41
 
37
42
  // "Private"
38
43
  socket = null;
@@ -40,11 +45,11 @@ export default class Socket extends EventTarget {
40
45
  framesReceived = 0;
41
46
  frameTimer;
42
47
  reconnectTimer;
43
- disconnectCbs = [];
48
+ disconnectCallBacks = [];
44
49
  disconnectedAt = 0;
45
50
  closingId = 0;
46
51
 
47
- constructor(url, autoReconnect = true, frameTimeout = null, protocol = null, maxTries = null) {
52
+ constructor(url, autoReconnect = true, frameTimeout = null, protocol = null, maxTries = null, idAsTimestamp = false) {
48
53
  super();
49
54
 
50
55
  this.setUrl(url);
@@ -53,6 +58,7 @@ export default class Socket extends EventTarget {
53
58
  // maxTries = null === never stop trying to reconnect
54
59
  // allow maxTries to be defined on individual sockets bc not all will clearly warn the user that we've stopped trying
55
60
  this.maxTries = maxTries;
61
+ this.idAsTimestamp = idAsTimestamp;
56
62
 
57
63
  if ( frameTimeout !== null ) {
58
64
  this.frameTimeout = frameTimeout;
@@ -84,10 +90,10 @@ export default class Socket extends EventTarget {
84
90
 
85
91
  Object.assign(this.metadata, metadata);
86
92
 
87
- const id = sockId++;
93
+ const id = this.idAsTimestamp ? new Date().getTime() : sockId++;
88
94
  const url = addParam(this.url, 'sockId', id);
89
95
 
90
- console.log(`Socket connecting (id=${ id }, url=${ `${ url.replace(/\?.*/, '') }...` })`); // eslint-disable-line no-console
96
+ this._baseLog('connecting', { id, url: url.replace(/\?.*/, '') });
91
97
 
92
98
  let socket;
93
99
 
@@ -122,9 +128,9 @@ export default class Socket extends EventTarget {
122
128
  return false;
123
129
  }
124
130
 
125
- disconnect(cb) {
126
- if ( cb ) {
127
- this.disconnectCbs.push(cb);
131
+ disconnect(callBack) {
132
+ if ( callBack ) {
133
+ this.disconnectCallBacks.push(callBack);
128
134
  }
129
135
 
130
136
  const self = this;
@@ -140,7 +146,7 @@ export default class Socket extends EventTarget {
140
146
 
141
147
  this.addEventListener(EVENT_CONNECT_ERROR, onError);
142
148
 
143
- this.disconnectCbs.push(() => {
149
+ this.disconnectCallBacks.push(() => {
144
150
  this.removeEventListener(EVENT_CONNECT_ERROR, onError);
145
151
  resolve();
146
152
  });
@@ -208,7 +214,7 @@ export default class Socket extends EventTarget {
208
214
  socket.onmessage = null;
209
215
  socket.close();
210
216
  } catch (e) {
211
- this._log('Socket exception', e);
217
+ this._log('exception', { e: e.toString() });
212
218
  // Continue anyway...
213
219
  }
214
220
 
@@ -256,7 +262,7 @@ export default class Socket extends EventTarget {
256
262
 
257
263
  if ( timeout && this.state === STATE_CONNECTED) {
258
264
  this.frameTimer = setTimeout(() => {
259
- this._log('Socket watchdog expired after', timeout, 'closing');
265
+ this._log(`watchdog expired after${ timeout }. Closing`);
260
266
  this._close();
261
267
  this.dispatchEvent(new CustomEvent(EVENT_FRAME_TIMEOUT));
262
268
  }, timeout);
@@ -268,17 +274,22 @@ export default class Socket extends EventTarget {
268
274
  this._log('error');
269
275
  }
270
276
 
271
- _closed() {
272
- console.log(`Socket ${ this.closingId } closed`); // eslint-disable-line no-console
277
+ _closed(event) {
278
+ const { code, reason, wasClean } = event;
279
+
280
+ this._baseLog('closed', {
281
+ id: this.closingId || this.socket?.sockId || 'unknown', code, reason, clean: wasClean
282
+ });
283
+
273
284
  this.closingId = 0;
274
285
  this.socket = null;
275
286
  clearTimeout(this.reconnectTimer);
276
287
  clearTimeout(this.frameTimer);
277
288
 
278
- const cbs = this.disconnectCbs;
289
+ const callBacks = this.disconnectCallBacks;
279
290
 
280
- while ( cbs.length ) {
281
- const fn = cbs.pop();
291
+ while ( callBacks.length ) {
292
+ const fn = callBacks.pop();
282
293
 
283
294
  if ( fn ) {
284
295
  fn.apply(this);
@@ -305,17 +316,19 @@ export default class Socket extends EventTarget {
305
316
  this.state = STATE_RECONNECTING;
306
317
 
307
318
  if (this.maxTries && this.tries > 1 && this.tries <= this.maxTries) {
308
- // dispatch an event which will trigger a growl from steve-plugin sockets warning users that we've lost connection and are attemping to reconnect
319
+ // dispatch an event which will trigger a growl from steve-plugin sockets warning users that we've lost connection and are attempting to reconnect
309
320
  const e = new CustomEvent(EVENT_CONNECT_ERROR);
310
321
 
311
322
  this.dispatchEvent(e);
312
323
  }
313
324
 
314
325
  if (this.maxTries && this.tries > this.maxTries) {
326
+ this._log('closed. Will not reconnect (hit max attempts)');
315
327
  this.state = STATE_DISCONNECTED;
316
328
  // dispatch an event which will trigger a growl from steve-plugin sockets warning users that we've given up trying to reconnect
317
329
  this.dispatchEvent(new CustomEvent(EVENT_DISCONNECT_ERROR));
318
330
  } else {
331
+ this._log('closed. Attempting to reconnect');
319
332
  const delay = Math.max(1000, Math.min(1000 * this.tries, 30000));
320
333
 
321
334
  this.reconnectTimer = setTimeout(() => {
@@ -333,13 +346,37 @@ export default class Socket extends EventTarget {
333
346
  }
334
347
  }
335
348
 
336
- _log(...args) {
337
- const message = JSON.parse(JSON.stringify([...args]));
338
-
339
- message.unshift('Socket');
349
+ /**
350
+ * `console.log` the provided summary statement, with default information to identify the socket and the provided props
351
+ */
352
+ _log(summary, props) {
353
+ this._baseLog(summary, {
354
+ state: this.state, id: this.socket?.sockId || 0, ...props
355
+ });
356
+ }
340
357
 
341
- message.push(`(state=${ this.state }, id=${ this.socket ? this.socket.sockId : 0 })`);
358
+ /**
359
+ * `console.log` the provided summary statement and props
360
+ *
361
+ * This does not contain information to identify the socket and can be used in scenarios where it's not known or default
362
+ */
363
+ _baseLog(summary, props) {
364
+ const message = [summary];
365
+ const values = Object.entries(props || {});
366
+
367
+ message.unshift('Socket ');
368
+
369
+ if (values.length) {
370
+ message.push(' (');
371
+ values.forEach(([key, value], index) => {
372
+ if (index !== 0) {
373
+ message.push(`, `);
374
+ }
375
+ message.push(`${ key }=${ value }`);
376
+ });
377
+ message.push(')');
378
+ }
342
379
 
343
- console.log(message.join(' ')); // eslint-disable-line no-console
380
+ console.log(message.join('')); // eslint-disable-line no-console
344
381
  }
345
382
  }
package/utils/string.js CHANGED
@@ -129,6 +129,8 @@ export function formatPercent(value, maxPrecision = 2) {
129
129
  export function pluralize(str) {
130
130
  if ( str.match(/.*[^aeiou]y$/i) ) {
131
131
  return `${ str.substr(0, str.length - 1) }ies`;
132
+ } else if ( str.endsWith('ics') ) {
133
+ return str;
132
134
  } else if ( str.endsWith('s') ) {
133
135
  return `${ str }es`;
134
136
  } else {