@rancher/shell 0.5.3 → 2.0.0

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 (581) hide show
  1. package/assets/data/aws-regions.json +9 -0
  2. package/assets/images/vendor/openid.svg +18 -0
  3. package/assets/styles/app.scss +1 -2
  4. package/assets/styles/fonts/_icons.scss +3 -3
  5. package/assets/styles/global/_columns.scss +1 -1
  6. package/assets/styles/global/_labeled-input.scss +2 -0
  7. package/assets/styles/themes/_csp.scss +2 -2
  8. package/assets/styles/themes/_dark.scss +8 -2
  9. package/assets/styles/themes/_light.scss +2 -1
  10. package/assets/styles/themes/_suse.scss +1 -1
  11. package/assets/styles/vendor/vue-select.scss +5 -0
  12. package/assets/translations/en-us.yaml +296 -58
  13. package/assets/translations/zh-hans.yaml +5 -27
  14. package/babel.config.js +1 -1
  15. package/chart/__tests__/S3.test.ts +9 -2
  16. package/chart/monitoring/grafana/index.vue +6 -2
  17. package/chart/monitoring/prometheus/index.vue +2 -2
  18. package/chart/rancher-backup/S3.vue +11 -9
  19. package/chart/rancher-backup/index.vue +15 -5
  20. package/cloud-credential/__tests__/harvester.test.ts +18 -0
  21. package/cloud-credential/generic.vue +18 -9
  22. package/cloud-credential/harvester.vue +11 -3
  23. package/components/AppModal.vue +167 -0
  24. package/components/AssignTo.vue +7 -4
  25. package/components/AsyncButton.vue +18 -5
  26. package/components/BackLink.vue +4 -4
  27. package/components/BannerGraphic.vue +1 -0
  28. package/components/BrandImage.vue +47 -1
  29. package/components/Carousel.vue +14 -8
  30. package/components/Certificates.vue +8 -11
  31. package/components/ClusterBadge.vue +12 -3
  32. package/components/ClusterIconMenu.vue +44 -16
  33. package/components/ClusterProviderIcon.vue +14 -3
  34. package/components/CodeMirror.vue +73 -38
  35. package/components/CommunityLinks.vue +12 -8
  36. package/components/CreateDriver.vue +81 -0
  37. package/components/CruResource.vue +51 -27
  38. package/components/DetailTop.vue +2 -2
  39. package/components/Dialog.vue +6 -5
  40. package/components/DisableAuthProviderModal.vue +14 -8
  41. package/components/DraggableZone.vue +2 -2
  42. package/components/ExplorerMembers.vue +3 -3
  43. package/components/ExplorerProjectsNamespaces.vue +6 -6
  44. package/components/FixedBanner.vue +47 -36
  45. package/components/GlobalRoleBindings.vue +26 -0
  46. package/components/Import.vue +10 -6
  47. package/components/Inactivity.vue +1 -5
  48. package/components/KeyValueView.vue +14 -10
  49. package/components/MessageLink.vue +2 -2
  50. package/components/ModalWithCard.vue +5 -8
  51. package/components/MoveModal.vue +35 -33
  52. package/components/PodSecurityAdmission.vue +3 -3
  53. package/components/PromptChangePassword.vue +33 -33
  54. package/components/PromptModal.vue +11 -21
  55. package/components/PromptRemove.vue +11 -17
  56. package/components/PromptRestore.vue +18 -16
  57. package/components/Questions/__tests__/Boolean.test.ts +9 -19
  58. package/components/Questions/__tests__/Float.test.ts +9 -19
  59. package/components/Questions/__tests__/Int.test.ts +9 -19
  60. package/components/Questions/__tests__/String.test.ts +9 -19
  61. package/components/Questions/__tests__/Yaml.test.ts +9 -20
  62. package/components/Questions/__tests__/utils/questions-defaults.ts +20 -0
  63. package/components/Questions/index.vue +18 -2
  64. package/components/ResourceCancelModal.vue +34 -29
  65. package/components/ResourceDetail/Masthead.vue +23 -7
  66. package/components/ResourceDetail/index.vue +5 -0
  67. package/components/ResourceList/Masthead.vue +28 -10
  68. package/components/ResourceList/index.vue +65 -14
  69. package/components/ResourceTable.vue +73 -19
  70. package/components/ResourceYaml.vue +1 -0
  71. package/components/SelectIconGrid.vue +3 -3
  72. package/components/SideNav.vue +15 -37
  73. package/components/SingleClusterInfo.vue +4 -4
  74. package/components/SortableTable/THead.vue +26 -12
  75. package/components/SortableTable/filtering.js +9 -1
  76. package/components/SortableTable/grouping.js +8 -1
  77. package/components/SortableTable/index.vue +142 -42
  78. package/components/SortableTable/paging.js +36 -7
  79. package/components/SortableTable/selection.js +2 -1
  80. package/components/SortableTable/sorting.js +24 -7
  81. package/components/TabTitle.vue +84 -0
  82. package/components/Tabbed/index.vue +6 -1
  83. package/components/TableDataUserIcon.vue +47 -0
  84. package/components/TypeDescription.vue +1 -0
  85. package/components/Wizard.vue +1 -0
  86. package/components/__tests__/AppModal.test.ts +98 -0
  87. package/components/__tests__/AsyncButton.test.ts +1 -3
  88. package/components/__tests__/BackLink.test.ts +1 -1
  89. package/components/__tests__/ButtonGroup.test.ts +3 -6
  90. package/components/__tests__/Carousel.test.ts +43 -0
  91. package/components/__tests__/Certificates.test.ts +29 -0
  92. package/components/__tests__/{CodeMirror.spec.ts → CodeMirror.test.ts} +5 -17
  93. package/components/__tests__/CruResource.test.ts +10 -9
  94. package/components/__tests__/EtcdInfoBanner.test.ts +37 -0
  95. package/components/__tests__/FixedBanner.test.ts +5 -20
  96. package/components/__tests__/NamespaceFilter.test.ts +9 -18
  97. package/components/__tests__/TabTitle.test.ts +129 -0
  98. package/components/auth/AzureWarning.vue +2 -2
  99. package/components/auth/RoleDetailEdit.vue +10 -0
  100. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  101. package/components/auth/login/oidc.vue +7 -1
  102. package/components/fleet/FleetClusters.vue +9 -9
  103. package/components/fleet/FleetIntro.vue +11 -17
  104. package/components/fleet/FleetNoWorkspaces.vue +2 -2
  105. package/components/fleet/FleetRepos.vue +1 -0
  106. package/components/fleet/ForceDirectedTreeChart/index.vue +9 -3
  107. package/components/form/ArrayList.vue +30 -19
  108. package/components/form/ArrayListSelect.vue +9 -4
  109. package/components/form/ClusterAppearance.vue +132 -0
  110. package/components/form/ColorInput.vue +1 -0
  111. package/components/form/Error.vue +3 -3
  112. package/components/form/Footer.vue +2 -2
  113. package/components/form/GitPicker.vue +83 -38
  114. package/components/form/KeyValue.vue +67 -48
  115. package/components/form/LabeledSelect.vue +143 -43
  116. package/components/form/Labels.vue +3 -1
  117. package/components/form/NameNsDescription.vue +26 -9
  118. package/components/form/ResourceLabeledSelect.vue +187 -0
  119. package/components/form/ResourceTabs/index.vue +31 -15
  120. package/components/form/SecretSelector.vue +93 -18
  121. package/components/form/Select.vue +1 -1
  122. package/components/form/SelectOrCreateAuthSecret.vue +135 -62
  123. package/components/form/SimpleSecretSelector.vue +88 -28
  124. package/components/form/__tests__/BannerSettings.test.ts +53 -0
  125. package/components/form/__tests__/KeyValue.test.ts +121 -12
  126. package/components/form/__tests__/LabeledSelect.test.ts +0 -18
  127. package/components/form/__tests__/NameNsDescription.test.ts +25 -15
  128. package/components/form/labeled-select-utils/labeled-select-pagination.ts +151 -0
  129. package/components/form/labeled-select-utils/labeled-select.utils.ts +122 -0
  130. package/components/formatter/AppSummaryGraph.vue +2 -2
  131. package/components/formatter/CloudCredPublicData.vue +30 -0
  132. package/components/formatter/ClusterLink.vue +2 -2
  133. package/components/formatter/FleetSummaryGraph.vue +2 -1
  134. package/components/formatter/ImagePercentageBar.vue +0 -4
  135. package/components/formatter/IngressTarget.vue +18 -7
  136. package/components/formatter/Link.vue +2 -2
  137. package/components/formatter/LinkDetail.vue +2 -2
  138. package/components/formatter/LinkDetailImage.vue +2 -2
  139. package/components/formatter/LinkName.vue +2 -2
  140. package/components/formatter/LiveDate.vue +16 -0
  141. package/components/formatter/PrincipalGroupBindings.vue +2 -2
  142. package/components/formatter/SecretType.vue +2 -2
  143. package/components/formatter/VirtualServiceGateways.vue +2 -2
  144. package/components/formatter/__tests__/LinkDetail.test.ts +5 -5
  145. package/components/nav/Group.vue +7 -5
  146. package/components/nav/Header.vue +82 -43
  147. package/components/nav/NamespaceFilter.vue +8 -1
  148. package/components/nav/TopLevelMenu.vue +336 -125
  149. package/components/nav/Type.vue +58 -102
  150. package/components/nav/__tests__/TopLevelMenu.test.ts +370 -9
  151. package/components/nav/__tests__/Type.test.ts +321 -126
  152. package/components/nuxt/nuxt-child.js +0 -5
  153. package/components/nuxt/nuxt-error.vue +1 -1
  154. package/components/nuxt/nuxt-link.client.js +13 -95
  155. package/components/templates/default.vue +3 -3
  156. package/components/templates/error.vue +6 -10
  157. package/components/templates/standalone.vue +0 -4
  158. package/components/templates/unauthenticated.vue +1 -2
  159. package/components/user.retention/user-retention-header.vue +34 -0
  160. package/composables/useCompactInput.test.ts +36 -0
  161. package/composables/useCompactInput.ts +2 -2
  162. package/composables/useI18n.ts +26 -0
  163. package/composables/useLabeledFormElement.test.ts +135 -0
  164. package/composables/useStore.ts +16 -0
  165. package/config/home-links.js +32 -1
  166. package/config/labels-annotations.js +2 -1
  167. package/config/middleware.js +0 -6
  168. package/config/pagination-table-headers.js +57 -0
  169. package/config/pod-security-admission.ts +1 -1
  170. package/config/private-label.js +1 -3
  171. package/config/product/auth.js +1 -0
  172. package/config/product/explorer.js +167 -46
  173. package/config/product/legacy.js +3 -95
  174. package/config/product/manager.js +44 -11
  175. package/config/query-params.js +1 -0
  176. package/config/roles.ts +23 -0
  177. package/config/router/index.js +23 -0
  178. package/config/router/navigation-guards/attempt-first-login.js +73 -0
  179. package/config/router/navigation-guards/authentication.js +63 -0
  180. package/config/router/navigation-guards/index.js +15 -0
  181. package/config/router/navigation-guards/load-initial-settings.js +15 -0
  182. package/config/router/routes.js +487 -0
  183. package/config/settings.ts +38 -2
  184. package/config/store.js +7 -3
  185. package/config/table-headers.js +46 -1
  186. package/config/types.js +36 -16
  187. package/config/uiplugins.js +10 -5
  188. package/core/plugin-helpers.js +1 -1
  189. package/core/plugin.ts +2 -1
  190. package/core/plugins.js +289 -282
  191. package/creators/app/files/.eslintignore +0 -2
  192. package/creators/app/files/.vscode/settings.json +0 -1
  193. package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +2 -6
  194. package/creators/pkg/files/.github/workflows/build-extension-charts.yml +2 -6
  195. package/creators/pkg/init +32 -0
  196. package/detail/__tests__/service.test.ts +62 -0
  197. package/detail/catalog.cattle.io.app.vue +1 -1
  198. package/detail/cis.cattle.io.clusterscan.vue +14 -3
  199. package/detail/fleet.cattle.io.gitrepo.vue +15 -9
  200. package/detail/namespace.vue +2 -2
  201. package/detail/networking.k8s.io.ingress.vue +52 -19
  202. package/detail/node.vue +20 -43
  203. package/detail/pod.vue +1 -68
  204. package/detail/provisioning.cattle.io.cluster.vue +2 -1
  205. package/detail/service.vue +1 -1
  206. package/detail/workload/index.vue +2 -15
  207. package/dialog/AddCustomBadgeDialog.vue +318 -161
  208. package/dialog/DeactivateDriverDialog.vue +118 -0
  209. package/dialog/RollbackWorkloadDialog.vue +2 -2
  210. package/dialog/RotateCertificatesDialog.vue +0 -21
  211. package/directives/clean-html.js +15 -0
  212. package/directives/clean-tooltip.js +32 -0
  213. package/directives/focus.js +41 -0
  214. package/directives/int-number.js +21 -0
  215. package/directives/positive-int-number.js +19 -0
  216. package/directives/trim-whitespace.js +19 -0
  217. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +3 -2
  218. package/edit/__tests__/kontainerDriver.test.ts +107 -0
  219. package/edit/__tests__/management.cattle.io.clusterroletemplatebinding.test.ts +12 -1
  220. package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
  221. package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +2 -3
  222. package/edit/__tests__/nodeDriver.test.ts +107 -0
  223. package/edit/__tests__/service.test.ts +1 -5
  224. package/edit/__tests__/ui.cattle.io.navlink.test.ts +3 -1
  225. package/edit/auth/AuthProviderWarningBanners.vue +34 -0
  226. package/edit/auth/__tests__/AuthProviderWarningBanners.test.ts +19 -0
  227. package/edit/auth/__tests__/azuread.test.ts +241 -0
  228. package/edit/auth/__tests__/oidc.test.ts +137 -0
  229. package/edit/auth/azuread.vue +133 -31
  230. package/edit/auth/github.vue +5 -17
  231. package/edit/auth/googleoauth.vue +5 -18
  232. package/edit/auth/ldap/index.vue +5 -17
  233. package/edit/auth/oidc.vue +143 -42
  234. package/edit/auth/saml.vue +5 -14
  235. package/edit/catalog.cattle.io.clusterrepo.vue +175 -20
  236. package/edit/cis.cattle.io.clusterscan.vue +5 -2
  237. package/edit/cis.cattle.io.clusterscanbenchmark.vue +41 -9
  238. package/edit/cloudcredential.vue +26 -4
  239. package/edit/configmap.vue +10 -4
  240. package/edit/fleet.cattle.io.gitrepo.vue +7 -4
  241. package/edit/helm.cattle.io.projecthelmchart.vue +29 -19
  242. package/edit/kontainerDriver.vue +65 -0
  243. package/edit/logging-flow/Match.vue +10 -9
  244. package/edit/logging-flow/index.vue +4 -19
  245. package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +232 -2
  246. package/edit/logging.banzaicloud.io.output/index.vue +43 -26
  247. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +3 -3
  248. package/edit/management.cattle.io.project.vue +2 -1
  249. package/edit/management.cattle.io.setting.vue +20 -0
  250. package/edit/management.cattle.io.user.vue +2 -1
  251. package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +10 -7
  252. package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +21 -16
  253. package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +1 -0
  254. package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +3 -0
  255. package/edit/monitoring.coreos.com.prometheusrule/GroupRules.vue +2 -0
  256. package/edit/monitoring.coreos.com.prometheusrule/RecordingRule.vue +2 -0
  257. package/edit/monitoring.coreos.com.prometheusrule/index.vue +2 -0
  258. package/edit/networking.k8s.io.ingress/Rules.vue +8 -3
  259. package/edit/networking.k8s.io.ingress/index.vue +64 -8
  260. package/edit/networking.k8s.io.networkpolicy/PolicyRule.vue +1 -0
  261. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +6 -2
  262. package/edit/networking.k8s.io.networkpolicy/__tests__/{PolicyRuleTarget.spec.ts → PolicyRuleTarget.test.ts} +45 -6
  263. package/edit/networking.k8s.io.networkpolicy/__tests__/utils/selectors.test.ts +1 -1
  264. package/edit/networking.k8s.io.networkpolicy/index.vue +2 -0
  265. package/edit/nodeDriver.vue +65 -0
  266. package/edit/persistentvolume/index.vue +2 -2
  267. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +18 -9
  268. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +165 -1
  269. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +1 -1
  270. package/edit/provisioning.cattle.io.cluster/__tests__/CustomCommand.test.ts +0 -3
  271. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +228 -0
  272. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +70 -12
  273. package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +5 -0
  274. package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
  275. package/edit/provisioning.cattle.io.cluster/index.vue +21 -15
  276. package/edit/provisioning.cattle.io.cluster/rke2.vue +185 -114
  277. package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +67 -7
  278. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +19 -6
  279. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +132 -0
  280. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +7 -0
  281. package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
  282. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +1 -0
  283. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +3 -0
  284. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +1 -0
  285. package/edit/resources.cattle.io.backup.vue +139 -124
  286. package/edit/resources.cattle.io.restore.vue +146 -126
  287. package/edit/service.vue +1 -0
  288. package/edit/serviceaccount.vue +46 -4
  289. package/edit/workload/__tests__/Job.test.ts +1 -3
  290. package/edit/workload/__tests__/Upgrading.test.ts +2 -2
  291. package/edit/workload/mixins/workload.js +34 -1
  292. package/edit/workload/storage/emptyDir.vue +2 -2
  293. package/initialize/App.vue +75 -0
  294. package/initialize/app-extended.js +128 -0
  295. package/initialize/entry-helpers.js +549 -0
  296. package/initialize/entry.js +32 -0
  297. package/initialize/install-components.js +23 -0
  298. package/initialize/install-directives.js +59 -0
  299. package/initialize/install-plugins.js +123 -0
  300. package/list/__tests__/workload.test.ts +1 -1
  301. package/list/cis.cattle.io.clusterscan.vue +16 -10
  302. package/list/group.principal.vue +2 -2
  303. package/list/management.cattle.io.feature.vue +11 -7
  304. package/list/management.cattle.io.user.vue +36 -3
  305. package/list/networking.k8s.io.ingress.vue +36 -0
  306. package/list/node.vue +211 -73
  307. package/list/provisioning.cattle.io.cluster.vue +17 -4
  308. package/list/ui.cattle.io.navlink.vue +2 -2
  309. package/list/workload.vue +22 -0
  310. package/machine-config/__tests__/vmwarevsphere-pool-config-merge.test.ts +30 -0
  311. package/machine-config/__tests__/vmwarevsphere.test.ts +162 -59
  312. package/machine-config/amazonec2.vue +1 -1
  313. package/machine-config/azure.vue +38 -21
  314. package/machine-config/generic.vue +11 -15
  315. package/machine-config/vmwarevsphere-pool-config-merge.ts +25 -0
  316. package/machine-config/vmwarevsphere.vue +20 -11
  317. package/middleware/authenticated.js +9 -361
  318. package/mixins/__tests__/chart.test.ts +48 -6
  319. package/mixins/__tests__/create-edit-view.test.ts +2 -3
  320. package/mixins/auth-config.js +3 -2
  321. package/mixins/brand.js +75 -57
  322. package/mixins/chart.js +27 -13
  323. package/mixins/create-edit-view/index.js +2 -2
  324. package/mixins/fetch.client.js +42 -48
  325. package/mixins/labeled-form-element.ts +21 -1
  326. package/mixins/page-actions.js +7 -5
  327. package/mixins/resource-fetch-api-pagination.js +304 -0
  328. package/mixins/resource-fetch-namespaced.js +1 -1
  329. package/mixins/resource-fetch.js +46 -5
  330. package/models/__tests__/cluster.test.ts +44 -0
  331. package/models/__tests__/fleet.cattle.io.cluster.test.ts +36 -0
  332. package/models/__tests__/schema.tests.ts +24 -0
  333. package/models/__tests__/steve-schema.test.ts +73 -0
  334. package/models/__tests__/workload.test.ts +1 -1
  335. package/models/catalog.cattle.io.app.js +8 -0
  336. package/models/catalog.cattle.io.clusterrepo.js +9 -1
  337. package/models/catalog.cattle.io.uiplugin.js +7 -8
  338. package/models/cis.cattle.io.clusterscan.js +29 -8
  339. package/models/cloudcredential.js +9 -1
  340. package/models/cluster/node.js +4 -0
  341. package/models/cluster/schema.js +6 -0
  342. package/models/cluster.js +33 -0
  343. package/models/driver.js +62 -0
  344. package/models/fleet.cattle.io.cluster.js +23 -11
  345. package/models/fleet.cattle.io.gitrepo.js +10 -0
  346. package/models/helm.cattle.io.projecthelmchart.js +1 -1
  347. package/models/kontainerdriver.js +68 -0
  348. package/models/management/schema.js +6 -0
  349. package/models/management.cattle.io.authconfig.js +3 -2
  350. package/models/management.cattle.io.cluster.js +5 -4
  351. package/models/management.cattle.io.globalrole.js +2 -0
  352. package/models/management.cattle.io.user.js +67 -2
  353. package/models/monitoring.coreos.com.receiver.js +3 -1
  354. package/models/monitoring.coreos.com.route.js +1 -1
  355. package/models/networking.k8s.io.ingress.js +2 -1
  356. package/models/nodedriver.js +68 -0
  357. package/models/provisioning.cattle.io.cluster.js +34 -1
  358. package/models/schema.js +28 -7
  359. package/models/service.js +2 -0
  360. package/models/steve-schema.ts +254 -0
  361. package/models/workload.js +1 -0
  362. package/package.json +6 -5
  363. package/pages/about.vue +12 -5
  364. package/pages/account/index.vue +7 -2
  365. package/pages/auth/login.vue +106 -102
  366. package/pages/auth/logout.vue +2 -2
  367. package/pages/auth/setup.vue +57 -64
  368. package/pages/auth/verify.vue +17 -17
  369. package/pages/c/_cluster/apps/charts/chart.vue +54 -9
  370. package/pages/c/_cluster/apps/charts/index.vue +37 -13
  371. package/pages/c/_cluster/apps/charts/install.vue +4 -4
  372. package/pages/c/_cluster/auth/config/_id.vue +0 -6
  373. package/pages/c/_cluster/auth/config/index.vue +15 -9
  374. package/pages/c/_cluster/auth/roles/index.vue +8 -10
  375. package/pages/c/_cluster/auth/user.retention/index.vue +384 -0
  376. package/pages/c/_cluster/explorer/ConfigBadge.vue +13 -8
  377. package/pages/c/_cluster/explorer/EventsTable.vue +18 -0
  378. package/pages/c/_cluster/explorer/__tests__/index.test.ts +181 -0
  379. package/pages/c/_cluster/explorer/index.vue +231 -72
  380. package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +69 -0
  381. package/pages/c/_cluster/explorer/tools/index.vue +12 -176
  382. package/pages/c/_cluster/fleet/index.vue +88 -93
  383. package/pages/c/_cluster/longhorn/__tests__/longhorn.index.test.ts +89 -0
  384. package/pages/c/_cluster/longhorn/index.vue +52 -17
  385. package/pages/c/_cluster/manager/cloudCredential/index.vue +18 -25
  386. package/pages/c/_cluster/manager/drivers/kontainerDriver/_id.vue +12 -0
  387. package/pages/c/_cluster/manager/drivers/kontainerDriver/create.vue +15 -0
  388. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +94 -0
  389. package/pages/c/_cluster/manager/drivers/nodeDriver/_id.vue +12 -0
  390. package/pages/c/_cluster/manager/drivers/nodeDriver/create.vue +15 -0
  391. package/pages/c/_cluster/manager/drivers/nodeDriver/index.vue +63 -0
  392. package/pages/c/_cluster/manager/jwt.authentication/index.vue +235 -0
  393. package/pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue +4 -0
  394. package/pages/c/_cluster/monitoring/index.vue +1 -17
  395. package/pages/c/_cluster/monitoring/route-receiver/index.vue +2 -2
  396. package/pages/c/_cluster/neuvector/index.vue +1 -0
  397. package/pages/c/_cluster/settings/DefaultLinksEditor.vue +1 -0
  398. package/pages/c/_cluster/settings/banners.vue +86 -8
  399. package/pages/c/_cluster/settings/brand.vue +258 -36
  400. package/pages/c/_cluster/settings/index.vue +4 -4
  401. package/pages/c/_cluster/settings/links.vue +5 -3
  402. package/pages/c/_cluster/settings/performance.vue +71 -2
  403. package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +5 -2
  404. package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +10 -7
  405. package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +9 -6
  406. package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +11 -5
  407. package/pages/c/_cluster/uiplugins/InstallDialog.vue +53 -18
  408. package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +36 -301
  409. package/pages/c/_cluster/uiplugins/UninstallDialog.vue +14 -6
  410. package/pages/c/_cluster/uiplugins/__tests__/SetupUIPlugins.test.ts +52 -106
  411. package/pages/c/_cluster/uiplugins/index.vue +38 -52
  412. package/pages/diagnostic.vue +1 -0
  413. package/pages/fail-whale.vue +103 -41
  414. package/pages/home.vue +81 -24
  415. package/pages/prefs.vue +8 -3
  416. package/pages/support/index.vue +12 -2
  417. package/plugins/clean-html-directive.js +5 -12
  418. package/plugins/clean-tooltip-directive.js +6 -31
  419. package/plugins/codemirror.js +0 -9
  420. package/plugins/dashboard-store/__tests__/mutations.test.ts +296 -313
  421. package/plugins/dashboard-store/actions.js +140 -32
  422. package/plugins/dashboard-store/getters.js +86 -39
  423. package/plugins/dashboard-store/index.js +0 -99
  424. package/plugins/dashboard-store/mutations.js +150 -48
  425. package/plugins/dashboard-store/resource-class.js +14 -109
  426. package/plugins/directives.js +6 -39
  427. package/plugins/ember-cookie.js +13 -0
  428. package/plugins/global-formatters.js +26 -5
  429. package/plugins/i18n.js +90 -56
  430. package/plugins/int-number.js +6 -20
  431. package/plugins/plugin.js +3 -3
  432. package/plugins/positive-int-number.js +6 -17
  433. package/plugins/steve/__tests__/{getters.spec.ts → getters.test.ts} +124 -31
  434. package/plugins/steve/__tests__/mutations.test.ts +49 -0
  435. package/plugins/steve/__tests__/subscribe.spec.ts +109 -0
  436. package/plugins/steve/__tests__/utils/mutation.test.helpers.ts +105 -0
  437. package/plugins/steve/accept-or-reject-socket-message.ts +103 -0
  438. package/plugins/steve/actions.js +0 -1
  439. package/plugins/steve/getters.js +183 -63
  440. package/plugins/steve/hybrid-class.js +5 -1
  441. package/plugins/steve/mutations.js +29 -5
  442. package/plugins/steve/norman-class.js +123 -2
  443. package/{utils → plugins/steve}/projectAndNamespaceFiltering.utils.ts +28 -10
  444. package/plugins/steve/schema.d.ts +22 -0
  445. package/plugins/steve/steve-pagination-utils.ts +368 -0
  446. package/plugins/steve/subscribe.js +37 -75
  447. package/plugins/trim-whitespace.js +6 -34
  448. package/plugins/vue-js-modal.js +1 -1
  449. package/public/index.html +1 -0
  450. package/rancher-components/Accordion/Accordion.vue +3 -2
  451. package/rancher-components/BadgeState/BadgeState.vue +3 -3
  452. package/rancher-components/Banner/Banner.test.ts +1 -5
  453. package/rancher-components/Banner/Banner.vue +2 -2
  454. package/rancher-components/Card/Card.vue +4 -4
  455. package/rancher-components/Form/Checkbox/Checkbox.vue +4 -3
  456. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +1 -1
  457. package/rancher-components/Form/LabeledInput/LabeledInput.vue +66 -30
  458. package/rancher-components/Form/Radio/RadioButton.test.ts +1 -3
  459. package/rancher-components/Form/Radio/RadioButton.vue +13 -7
  460. package/rancher-components/Form/Radio/RadioGroup.vue +4 -3
  461. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -5
  462. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  463. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
  464. package/rancher-components/StringList/StringList.vue +8 -8
  465. package/rancher-components/components/Accordion/Accordion.vue +3 -2
  466. package/rancher-components/components/BadgeState/BadgeState.vue +3 -3
  467. package/rancher-components/components/Banner/Banner.test.ts +1 -5
  468. package/rancher-components/components/Banner/Banner.vue +2 -2
  469. package/rancher-components/components/Card/Card.vue +4 -4
  470. package/rancher-components/components/Form/Checkbox/Checkbox.vue +4 -3
  471. package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +1 -1
  472. package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +66 -30
  473. package/rancher-components/components/Form/Radio/RadioButton.test.ts +1 -3
  474. package/rancher-components/components/Form/Radio/RadioButton.vue +13 -7
  475. package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -3
  476. package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +7 -5
  477. package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
  478. package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +9 -4
  479. package/rancher-components/components/StringList/StringList.vue +8 -8
  480. package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +27 -8
  481. package/scripts/clean +1 -1
  482. package/scripts/extension/helm/charts/ui-plugin-server/templates/_helpers.tpl +11 -0
  483. package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -0
  484. package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
  485. package/scripts/extension/helm/package/Dockerfile +1 -1
  486. package/scripts/extension/helm/scripts/patch +27 -0
  487. package/scripts/extension/publish +6 -6
  488. package/scripts/serve-pkgs +0 -2
  489. package/scripts/test-plugins-build.sh +6 -6
  490. package/scripts/vue-migrate.js +683 -0
  491. package/store/__tests__/catalog.test.ts +224 -0
  492. package/store/auth.js +23 -4
  493. package/store/aws.js +53 -6
  494. package/store/catalog.js +21 -5
  495. package/store/cru-resource.ts +26 -0
  496. package/store/customisation.js +35 -0
  497. package/store/features.js +6 -4
  498. package/store/index.js +132 -39
  499. package/store/plugins.js +8 -4
  500. package/store/type-map.js +143 -143
  501. package/store/type-map.utils.ts +226 -0
  502. package/tsconfig.json +0 -1
  503. package/tsconfig.paths.json +4 -1
  504. package/types/components/labeledSelect.ts +50 -0
  505. package/types/resources/settings.d.ts +32 -0
  506. package/types/{userPreferences.d.ts → resources/userPreferences.d.ts} +0 -1
  507. package/types/shell/index.d.ts +996 -782
  508. package/types/store/dashboard-store.types.ts +42 -0
  509. package/types/store/pagination.types.ts +457 -0
  510. package/types/store/type-map.ts +30 -0
  511. package/types/store/vuex.d.ts +9 -0
  512. package/types/vue-shim.d.ts +51 -0
  513. package/utils/__tests__/cluster.test.ts +20 -18
  514. package/utils/__tests__/create-yaml.test.ts +359 -2
  515. package/utils/__tests__/kontainer.test.ts +92 -0
  516. package/utils/__tests__/pod-security-admission.test.ts +1 -1
  517. package/utils/alertmanagerconfig.js +19 -0
  518. package/utils/array.ts +40 -1
  519. package/utils/async.ts +2 -0
  520. package/utils/auth.js +152 -4
  521. package/utils/axios.js +2 -2
  522. package/utils/banners.js +103 -0
  523. package/utils/cluster.js +1 -1
  524. package/utils/config.js +4 -0
  525. package/utils/create-yaml.js +54 -27
  526. package/utils/error.js +25 -0
  527. package/utils/formatter.js +5 -3
  528. package/utils/git.ts +1 -1
  529. package/utils/install-redirect.js +1 -1
  530. package/utils/kontainer.ts +186 -0
  531. package/utils/monitoring.js +2 -37
  532. package/utils/pagination-utils.ts +154 -0
  533. package/utils/pod-security-admission.ts +1 -1
  534. package/utils/router.js +86 -0
  535. package/utils/settings.ts +46 -0
  536. package/utils/socket.js +1 -0
  537. package/utils/time.js +1 -0
  538. package/utils/title.ts +3 -0
  539. package/utils/unit-tests/ChildRenderingRouterLinkStub.ts +36 -0
  540. package/utils/validators/formRules/__tests__/index.test.ts +21 -0
  541. package/utils/validators/formRules/index.ts +3 -0
  542. package/utils/validators/index.js +1 -0
  543. package/vue.config.js +376 -421
  544. package/assets/styles/vendor/vue-js-modal.scss +0 -16
  545. package/chart/monitoring/steps/uninstall-v1.vue +0 -135
  546. package/components/EventsTable.vue +0 -67
  547. package/components/TabbedLinks/index.vue +0 -94
  548. package/components/nuxt/nuxt-link.server.js +0 -16
  549. package/components/nuxt/nuxt.js +0 -101
  550. package/config/router.js +0 -425
  551. package/initialize/App.js +0 -152
  552. package/initialize/client.js +0 -734
  553. package/initialize/index.js +0 -287
  554. package/middleware/i18n.js +0 -10
  555. package/middleware/unauthenticated.js +0 -22
  556. package/mixins/v1-workload-metrics.js +0 -43
  557. package/pages/c/_cluster/apps/index.vue +0 -15
  558. package/pages/c/_cluster/auth/index.vue +0 -17
  559. package/pages/c/_cluster/index.vue +0 -15
  560. package/pages/c/_cluster/legacy/index.vue +0 -22
  561. package/pages/c/_cluster/manager/index.vue +0 -22
  562. package/pages/c/_cluster/mcapps/index.vue +0 -21
  563. package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +0 -232
  564. package/plugins/dashboard-store/rehydrate-all.js +0 -44
  565. package/plugins/index.js +0 -11
  566. package/plugins/portal-vue.js +0 -4
  567. package/plugins/portal.js +0 -4
  568. package/plugins/resize.js +0 -5
  569. package/plugins/shortkey.js +0 -4
  570. package/plugins/tooltip.js +0 -4
  571. package/plugins/v-select.js +0 -4
  572. package/utils/group.js +0 -70
  573. package/utils/nuxt.js +0 -638
  574. package/utils/router.scrollBehavior.js +0 -78
  575. /package/components/__tests__/{Collapse.spec.ts → Collapse.test.ts} +0 -0
  576. /package/models/__tests__/{node.ts → node.test.ts} +0 -0
  577. /package/plugins/steve/__tests__/{header-warnings.spec.ts → header-warnings.test.ts} +0 -0
  578. /package/plugins/steve/__tests__/{steve-class.spec.ts → steve-class.test.ts} +0 -0
  579. /package/rancher-components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
  580. /package/rancher-components/components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
  581. /package/types/{pod-security-admission.ts → resources/pod-security-admission.ts} +0 -0
@@ -0,0 +1,186 @@
1
+ import { isArray } from '@shell/utils/array';
2
+ import { set, get, isEmpty } from '@shell/utils/object';
3
+
4
+ /**
5
+ * This function accepts a v3 cluster object and mutates its config field to sync values that were set outside Rancher (eg, when an imported cluster is created in its respective cloud provider).
6
+ * Values configured outside of rancher are not automatically propagated to the config field that the UI edits; they are reflected in the aksStatus/eksStatus/gkeStatus.upstreamSpec field.
7
+ * This function works in tandem with diffUpstreamSpec: the former runs when the edit form is initialized and the latter runs when the cluster is saved.
8
+ * @param configPrefix one of aks, eks, gke
9
+ * @param normanCluster v3 cluster object
10
+ */
11
+ export function syncUpstreamConfig(configPrefix: string, normanCluster: {[key: string]: any}): void {
12
+ const configKey = `${ configPrefix }Config`;
13
+ const statusKey = `${ configPrefix }Status`;
14
+
15
+ const rancherConfig = normanCluster[configKey] || {};
16
+ const upstreamConfig = normanCluster?.[statusKey]?.upstreamSpec || {};
17
+
18
+ if (!isEmpty(upstreamConfig)) {
19
+ Object.keys(upstreamConfig).forEach((key) => {
20
+ if (isEmpty(rancherConfig[key]) && !isEmpty(upstreamConfig[key])) {
21
+ set(rancherConfig, key, upstreamConfig[key]);
22
+ }
23
+ });
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Hosted provider (aks gke eks) edit functionality differs from other k8s resources
29
+ * see ui issue: https://github.com/rancher/rancher/issues/28541
30
+ * backend issue: https://github.com/rancher/rancher/issues/28422
31
+ * The below code is taken from the rancher/ui implementation https://github.com/rancher/ui/blob/master/app/models/cluster.js#L1368
32
+ */
33
+
34
+ function isEmptyObject(object: any) {
35
+ return Object.keys(object).length === 0;
36
+ }
37
+
38
+ function isObject(val: any) {
39
+ return Object.prototype.toString.call(val) === '[object Object]';
40
+ }
41
+
42
+ function isEmptyStringOrArray(val: any) {
43
+ return val === null || val === undefined || val === '' || (isArray(val) && val.length === 0);
44
+ }
45
+
46
+ /**
47
+ * this is NOT a generic object diff.
48
+ * It tries to be as generic as possible but it does make certain assumptions regarding nulls and emtpy arrays/objects
49
+ * if upstream is null and local aks config is empty we do not count this as a change
50
+ * additionally null values on the RHS will be ignored as null cant be sent in this case
51
+ * nodeGroups, nodePools, tags, and labels are not diffed
52
+ * @param upstream aksStatus.upstreamSpec
53
+ * @param local aksConfig
54
+ * @returns aksConfig containing only values which differ from upstream spec, excluding null values
55
+ */
56
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
57
+ export function diffUpstreamSpec(upstream: any, local: any): any {
58
+ const delta = {};
59
+ const localKeys = Object.keys(local);
60
+
61
+ localKeys.forEach((key) => {
62
+ if (key === 'type') {
63
+ return;
64
+ }
65
+
66
+ const upstreamMatch = get(upstream, key);
67
+ const localMatch = get(local, key);
68
+
69
+ if (key !== 'nodeGroups' && key !== 'nodePools') {
70
+ try {
71
+ if (JSON.stringify(upstreamMatch) === JSON.stringify(localMatch)) {
72
+ return;
73
+ }
74
+ } catch (e) {}
75
+ }
76
+
77
+ if (key === 'nodeGroups' || key === 'nodePools' || key === 'tags' || key === 'labels') {
78
+ // Node Groups and Node Pools do not require a sync, we can safely send the entire object
79
+ // Tags and Labels (maps) are also included by default because what is present in the config is exactly what should be used on save and any equal maps would have been caught by the JSON isEqual comparison above
80
+ if (!isEmptyStringOrArray(localMatch)) {
81
+ // node groups need ALL data so short circut and send it all
82
+ set(delta, key, localMatch);
83
+ } else {
84
+ // all node groups were deleted
85
+ set(delta, key, []);
86
+ }
87
+
88
+ return;
89
+ }
90
+
91
+ if (isEmptyStringOrArray(upstreamMatch) || isEmptyObject(upstreamMatch)) {
92
+ if (isEmptyStringOrArray(localMatch) || isEmptyObject(localMatch)) {
93
+ if (upstreamMatch !== null && (isArray(localMatch) || isObject(localMatch))) {
94
+ // Empty Arrays and Empty Maps must be sent as such unless the upstream value is null, then the empty array or obj is just an init value
95
+ set(delta, key, localMatch);
96
+ }
97
+ } else {
98
+ // upstream is empty, local is not, just set
99
+ set(delta, key, localMatch);
100
+ }
101
+ } else {
102
+ if (localMatch !== null) {
103
+ // entry in og obj
104
+ if (isArray(upstreamMatch)) {
105
+ if (isArray(localMatch)) {
106
+ if (!isEmptyStringOrArray(localMatch) && localMatch.every((m: any) => isObject(m))) {
107
+ // You have more diffing to do
108
+ localMatch.forEach((match: any) => {
109
+ // our most likely candiate for a match is node group name, but lets check the others just incase.
110
+ const matchId = get(match, 'name') || get(match, 'id') || false;
111
+
112
+ if (matchId) {
113
+ let lmatchIdx = 0;
114
+
115
+ // we have soime kind of identifier to find a match in the upstream, so we can diff and insert to new array
116
+ const lMatch = upstreamMatch.find((l: any, idx: number) => {
117
+ const lmatchId = get(l, 'name') || get(l, 'id');
118
+
119
+ if (lmatchId === matchId) {
120
+ lmatchIdx = idx;
121
+
122
+ return l;
123
+ }
124
+ });
125
+
126
+ if (lMatch) {
127
+ // we have a match in the upstream, meaning we've probably made updates to the object itself
128
+ const diffedMatch = diffUpstreamSpec(lMatch, match);
129
+
130
+ if (!isArray(get(delta, key))) {
131
+ set(delta, key, [diffedMatch]);
132
+ } else {
133
+ const target: any[] = delta[key as keyof typeof delta];
134
+
135
+ // diff and push into new array
136
+ target.splice(lmatchIdx, 0, diffedMatch);
137
+ }
138
+ } else {
139
+ // no match in upstream, new entry
140
+ if (!isArray(get(delta, key))) {
141
+ set(delta, key, [match]);
142
+ } else {
143
+ const target: any = delta[key as keyof typeof delta];
144
+
145
+ target.push(match);
146
+ }
147
+ }
148
+ } else {
149
+ // no match id, all we can do is dumb add
150
+ if (!isArray(get(delta, key))) {
151
+ set(delta, key, [match]);
152
+ } else {
153
+ const target: any = delta[key as keyof typeof delta];
154
+
155
+ target.push(match);
156
+ }
157
+ }
158
+ });
159
+ } else {
160
+ set(delta, key, localMatch);
161
+ }
162
+ } else {
163
+ set(delta, key, localMatch);
164
+ }
165
+ } else if (isObject(upstreamMatch)) {
166
+ if (!isEmptyStringOrArray(localMatch) && !isEmptyObject(localMatch)) {
167
+ if ((Object.keys(upstreamMatch) || []).length > 0) {
168
+ // You have more diffing to do
169
+ set(delta, key, diffUpstreamSpec(upstreamMatch, localMatch));
170
+ } else if (isEmptyObject(upstreamMatch)) {
171
+ // we had a map now we have an empty map
172
+ set(delta, key, {});
173
+ }
174
+ } else if (!isEmptyObject(upstreamMatch) && isEmptyObject(localMatch)) {
175
+ // we had a map now we have an empty map
176
+ set(delta, key, {});
177
+ }
178
+ } else { // upstreamMatch not an array or object
179
+ set(delta, key, localMatch);
180
+ }
181
+ }
182
+ }
183
+ });
184
+
185
+ return delta;
186
+ }
@@ -1,6 +1,6 @@
1
1
  // Helpers for determining if V2 or v1 Monitoring are installed
2
2
 
3
- import { SCHEMA, MONITORING, WORKLOAD_TYPES, ENDPOINTS } from '@shell/config/types';
3
+ import { SCHEMA, MONITORING, ENDPOINTS } from '@shell/config/types';
4
4
  import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
5
5
  import { findBy } from '@shell/utils/array';
6
6
  import { isEmpty } from '@shell/utils/object';
@@ -9,10 +9,7 @@ import { isEmpty } from '@shell/utils/object';
9
9
  export function monitoringStatus() {
10
10
  return {
11
11
  monitoringStatus() {
12
- const status = {
13
- v1: haveV1Monitoring(this.$store.getters),
14
- v2: haveV2Monitoring(this.$store.getters),
15
- };
12
+ const status = { v2: haveV2Monitoring(this.$store.getters) };
16
13
 
17
14
  status.installed = status.v1 || status.v2;
18
15
 
@@ -22,10 +19,6 @@ export function monitoringStatus() {
22
19
  }
23
20
 
24
21
  export function haveV2Monitoring(getters) {
25
- // Can't have V2 and V1 monitoring installed, so if V1 is installed we know v2 is not
26
- if (haveV1Monitoring(getters)) {
27
- return false;
28
- }
29
22
  const inStore = getters['getStoreNameByProductId'];
30
23
 
31
24
  // Just check for the pod monitors CRD
@@ -35,36 +28,8 @@ export function haveV2Monitoring(getters) {
35
28
  return !!exists;
36
29
  }
37
30
 
38
- // For v1 Monitoring, the cluster object indicates presence via status.monitoringStatus
39
- export function haveV1Monitoring(getters) {
40
- const cluster = getters['currentCluster'];
41
-
42
- return !!cluster?.status?.monitoringStatus;
43
- }
44
-
45
31
  export const CATTLE_MONITORING_NAMESPACE = 'cattle-monitoring-system';
46
32
 
47
- export async function haveV1MonitoringWorkloads(store) {
48
- const workloadsByType = await Promise.all(
49
- Object.values(WORKLOAD_TYPES).map((type) => store.dispatch('cluster/findAll', { type })
50
- )
51
- );
52
- const workloads = workloadsByType.flat();
53
-
54
- for (let i = 0; i < workloads.length; i++) {
55
- const workload = workloads[i];
56
-
57
- if (!isEmpty(workload?.spec?.template?.spec?.containers) &&
58
- workload.spec.template.spec.containers.find((c) => c.image?.includes('quay.io/coreos/prometheus-operator') ||
59
- c.image?.includes('rancher/coreos-prometheus-operator')) &&
60
- workload?.metadata?.namespace !== CATTLE_MONITORING_NAMESPACE) {
61
- return Promise.resolve(true);
62
- }
63
-
64
- return Promise.resolve(false);
65
- }
66
- }
67
-
68
33
  async function hasEndpointSubsets(store, id) {
69
34
  if (store.getters['cluster/schemaFor'](ENDPOINTS)) {
70
35
  const endpoints = await store.dispatch('cluster/findAll', { type: ENDPOINTS }) || [];
@@ -0,0 +1,154 @@
1
+ import { PaginationSettings } from '@shell/types/resources/settings';
2
+ import {
3
+ NAMESPACE_FILTER_ALL_USER as ALL_USER,
4
+ NAMESPACE_FILTER_ALL as ALL,
5
+ NAMESPACE_FILTER_ALL_SYSTEM as ALL_SYSTEM,
6
+ NAMESPACE_FILTER_NAMESPACED_YES as NAMESPACED_YES,
7
+ NAMESPACE_FILTER_NAMESPACED_NO as NAMESPACED_NO,
8
+ NAMESPACE_FILTER_KINDS,
9
+ NAMESPACE_FILTER_NS_FULL_PREFIX,
10
+ NAMESPACE_FILTER_P_FULL_PREFIX,
11
+ } from '@shell/utils/namespace-filter';
12
+ import { PaginationArgs, PaginationParam, PaginationSort } from '@shell/types/store/pagination.types';
13
+ import { sameArrayObjects } from '@shell/utils/array';
14
+ import { isEqual } from '@shell/utils/object';
15
+ import { STEVE_CACHE } from '@shell/store/features';
16
+ import { getPerformanceSetting } from '@shell/utils/settings';
17
+
18
+ /**
19
+ * Helper functions for server side pagination
20
+ */
21
+ class PaginationUtils {
22
+ /**
23
+ * When a ns filter isn't one or more projects/namespaces... what are the valid values?
24
+ *
25
+ * This basically blocks 'Not in a Project'.. which would involve a projectsornamespaces param with every ns not in a project.
26
+ */
27
+ validNsProjectFilters = [ALL, ALL_SYSTEM, ALL_USER, ALL_SYSTEM, NAMESPACE_FILTER_KINDS.NAMESPACE, NAMESPACE_FILTER_KINDS.PROJECT, NAMESPACED_YES, NAMESPACED_NO];
28
+
29
+ private getSettings({ rootGetters }: any): PaginationSettings {
30
+ const perf = getPerformanceSetting(rootGetters);
31
+
32
+ return perf.serverPagination;
33
+ }
34
+
35
+ isSteveCacheEnabled({ rootGetters }: any): boolean {
36
+ // We always get Feature flags as part of start up (see `dispatch('features/loadServer')` in loadManagement)
37
+ return rootGetters['features/get']?.(STEVE_CACHE);
38
+ }
39
+
40
+ /**
41
+ * Is pagination enabled at a global level or for a specific resource
42
+ */
43
+ isEnabled({ rootGetters }: any, enabledFor: {
44
+ store: string,
45
+ resource?: {
46
+ id: string,
47
+ }
48
+ }) {
49
+ // Cache must be enabled to support pagination api
50
+ if (!this.isSteveCacheEnabled({ rootGetters })) {
51
+ return false;
52
+ }
53
+
54
+ const settings = this.getSettings({ rootGetters });
55
+
56
+ // No setting, not enabled
57
+ if (!settings?.enabled) {
58
+ return false;
59
+ }
60
+
61
+ // Missing required params, not enabled
62
+ if (!enabledFor) {
63
+ return false;
64
+ }
65
+
66
+ const storeSettings = settings.stores?.[enabledFor.store];
67
+
68
+ // No pagination setting for target store, not enabled
69
+ if (!storeSettings) {
70
+ return false;
71
+ }
72
+
73
+ // Not interested in a resource, so just top level settings are checked
74
+ if (!enabledFor.resource) {
75
+ return true;
76
+ }
77
+
78
+ // Store says all resources are enabled
79
+ if (storeSettings.resources.enableAll) {
80
+ return true;
81
+ }
82
+
83
+ // given a resource... but no id... invalid
84
+ if (!enabledFor.resource.id) {
85
+ return false;
86
+ }
87
+
88
+ // Store says only some (those that have pagination columns not from schema and no custom list)
89
+ const isGeneric =
90
+ !rootGetters['type-map/configuredHeaders'](enabledFor.resource.id) &&
91
+ !rootGetters['type-map/configuredPaginationHeaders'](enabledFor.resource.id) &&
92
+ !rootGetters['type-map/hasCustomList'](enabledFor.resource.id);
93
+
94
+ if (storeSettings.resources.enableSome.generic && isGeneric) {
95
+ return true;
96
+ }
97
+
98
+ if (storeSettings.resources.enableSome.enabled.includes(enabledFor.resource.id)) {
99
+ return true;
100
+ }
101
+
102
+ return false;
103
+ }
104
+
105
+ validateNsProjectFilters(nsProjectFilters: string[]) {
106
+ return nsProjectFilters?.every((f) => this.validateNsProjectFilter(f));
107
+ }
108
+
109
+ validateNsProjectFilter(nsProjectFilter: string) {
110
+ if (nsProjectFilter.startsWith(NAMESPACE_FILTER_NS_FULL_PREFIX) || nsProjectFilter.startsWith(NAMESPACE_FILTER_P_FULL_PREFIX)) {
111
+ return true;
112
+ }
113
+
114
+ return this.validNsProjectFilters.includes(nsProjectFilter);
115
+ }
116
+
117
+ paginationFilterEqual(a: PaginationParam, b: PaginationParam): boolean {
118
+ if (a.param !== b.param || a.equals !== b.equals) {
119
+ return false;
120
+ }
121
+
122
+ return sameArrayObjects(a.fields, b.fields, true);
123
+ }
124
+
125
+ paginationFiltersEqual(a: PaginationParam[], b: PaginationParam[]): boolean {
126
+ if (!!a && a?.length !== b?.length) {
127
+ return false;
128
+ }
129
+
130
+ for (let i = 0; i < a.length; i++) {
131
+ if (!this.paginationFilterEqual(a[i], b[i])) {
132
+ return false;
133
+ }
134
+ }
135
+
136
+ return true;
137
+ }
138
+
139
+ paginationEqual(a?: PaginationArgs, b?: PaginationArgs): boolean {
140
+ const {
141
+ filters: aFilter = [], sort: aSort = [], projectsOrNamespaces: aPN = [], ...aPrimitiveTypes
142
+ } = a || {};
143
+ const {
144
+ filters: bFilter = [], sort: bSort = [], projectsOrNamespaces: bPN = [], ...bPrimitiveTypes
145
+ } = b || {};
146
+
147
+ return isEqual(aPrimitiveTypes, bPrimitiveTypes) &&
148
+ this.paginationFiltersEqual(aFilter, bFilter) &&
149
+ this.paginationFiltersEqual(aPN, bPN) &&
150
+ sameArrayObjects<PaginationSort>(aSort, bSort, true);
151
+ }
152
+ }
153
+
154
+ export default new PaginationUtils();
@@ -1,7 +1,7 @@
1
1
  import { reduce, filter, keys } from 'lodash';
2
2
  import { PSALabelPrefix, PSALabelsNamespaces } from '@shell/config/pod-security-admission';
3
3
  import { camelToTitle } from '@shell/utils/string';
4
- import { PSA } from '@shell/types/pod-security-admission';
4
+ import { PSA } from '@shell/types/resources/pod-security-admission';
5
5
 
6
6
  /**
7
7
  * Return PSA labels present in the resource
package/utils/router.js CHANGED
@@ -25,3 +25,89 @@ export function queryParamsFor(current, qp, defaults = {}) {
25
25
 
26
26
  return query;
27
27
  }
28
+
29
+ export function getClusterFromRoute(to) {
30
+ let cluster = to.params?.cluster;
31
+
32
+ if (!cluster) {
33
+ cluster = findMeta(to, 'cluster');
34
+ }
35
+
36
+ return cluster;
37
+ }
38
+
39
+ export function getProductFromRoute(to) {
40
+ let product = to.params?.product;
41
+
42
+ if ( !product ) {
43
+ const match = to.name?.match(/^c-cluster-([^-]+)/);
44
+
45
+ if ( match ) {
46
+ product = match[1];
47
+ }
48
+ }
49
+
50
+ // If still no product, see if the route indicates the product via route metadata
51
+ if (!product) {
52
+ product = findMeta(to, 'product');
53
+ }
54
+
55
+ return product;
56
+ }
57
+
58
+ export const getPackageFromRoute = (route) => {
59
+ if (!route?.meta) {
60
+ return;
61
+ }
62
+ // Sometimes meta is an array... sometimes not
63
+ const arraySafe = Array.isArray(route.meta) ? route.meta : [route.meta];
64
+
65
+ return arraySafe.find((m) => !!m.pkg)?.pkg;
66
+ };
67
+
68
+ export const getResourceFromRoute = (to) => {
69
+ let resource = to.params?.resource;
70
+
71
+ if (!resource) {
72
+ resource = findMeta(to, 'resource');
73
+ }
74
+
75
+ return resource;
76
+ };
77
+
78
+ /**
79
+ * Given a route it will look through the matching parent routes to see if any match the fn (predicate) criteria
80
+ *
81
+ * @param {*} to a VueRouter Route object
82
+ * @param {*} fn fn is a predicate which is passed a matched route. It will return true to indicate there was a matching route and false otherwise
83
+ * @returns true if a matching route was found, false otherwise
84
+ */
85
+ export const routeMatched = (to, fn) => {
86
+ const matched = to?.matched || [];
87
+
88
+ return !!matched.find(fn);
89
+ };
90
+
91
+ /**
92
+ * Checks to see if the route requires authentication by taking a look at the route and it's parents 'meta' to see if it
93
+ * contains { requiresAuthentication: true }
94
+ * @param {*} to a VueRouter Route object
95
+ * @returns true if the route requires authentication, false otherwise
96
+ */
97
+ export const routeRequiresAuthentication = (to) => {
98
+ return routeMatched(to, (matched) => matched.meta?.requiresAuthentication);
99
+ };
100
+
101
+ function findMeta(route, key) {
102
+ if (route?.meta) {
103
+ const meta = Array.isArray(route.meta) ? route.meta : [route.meta];
104
+
105
+ for (let i = 0; i < meta.length; i++) {
106
+ if (meta[i][key]) {
107
+ return meta[i][key];
108
+ }
109
+ }
110
+ }
111
+
112
+ return undefined;
113
+ }
package/utils/settings.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { MANAGEMENT } from '@shell/config/types';
2
2
  import { Store } from 'vuex';
3
3
  import { DEFAULT_PERF_SETTING, PerfSettings, SETTING } from '@shell/config/settings';
4
+ import { pluralize } from '@shell/utils/string';
5
+ import { _MULTI } from '@shell/plugins/dashboard-store/actions';
4
6
 
5
7
  export const fetchOrCreateSetting = async(store: Store<any>, id: string, val: string, save = true): Promise<any> => {
6
8
  let setting;
@@ -34,6 +36,50 @@ export const fetchSetting = async(store: Store<any>, id: string): Promise<any> =
34
36
  return setting;
35
37
  };
36
38
 
39
+ /**
40
+ * Carefully fetch mgmt settings
41
+ *
42
+ * Ensures that
43
+ * - Concurrent calls to this function will only result in a single http request
44
+ * - Subsequent calls, when either logged in or logged out, will only result in a single http request
45
+ * - Logged out call will fetch partial settings, after logging in another call will fetch all settings
46
+ *
47
+ * Will be used in many places, particularly multiple times when loading the dashboard
48
+ *
49
+ * Note - We need to specify the url for cases where it can't be determined (i.e. we haven't fetched schemas)
50
+ */
51
+ export const fetchInitialSettings = async(store: Store<any>): Promise<any> => {
52
+ const generation = store.getters['management/generation'](MANAGEMENT.SETTING);
53
+ // We use this as it copies the previous mechanism this was based on (in findAll)
54
+ // There is the getter `auth/loggedInAs` (which is set given `fromHeader`), but that's initialised after the first call to here (see `authenticated`)
55
+ const header = store.getters['auth/fromHeader'];
56
+ const authed = `${ header }` === 'true' || `${ header }` === 'none';
57
+
58
+ if (authed) {
59
+ // We're authed, we will always get the full list
60
+ return await store.dispatch('management/findAll', {
61
+ type: MANAGEMENT.SETTING,
62
+ opt: { url: `/v1/${ pluralize(MANAGEMENT.SETTING) }` }
63
+ } );
64
+ }
65
+
66
+ if (!generation) {
67
+ // We're not authed, and haven't previously fetched settings (no generation)
68
+ // Fetch settings, put them in the store, but don't say we've got all yet (so subsequent calls will run)
69
+ return await store.dispatch('management/findAll', {
70
+ type: MANAGEMENT.SETTING,
71
+ opt: {
72
+ url: `/v1/${ pluralize(MANAGEMENT.SETTING) }`,
73
+ load: _MULTI,
74
+ redirectUnauthorized: false
75
+ }
76
+ });
77
+ }
78
+
79
+ // We're not authed, but have a previous value, no need to make a http request to fetch again
80
+ return store.getters['management/all'](MANAGEMENT.SETTING);
81
+ };
82
+
37
83
  export const setSetting = async(store: Store<any>, id: string, val: string): Promise<any> => {
38
84
  const setting = await fetchOrCreateSetting(store, id, val, false);
39
85
 
package/utils/socket.js CHANGED
@@ -27,6 +27,7 @@ export const EVENT_DISCONNECT_ERROR = 'disconnect_error';
27
27
 
28
28
  export const NO_WATCH = 'NO_WATCH';
29
29
  export const NO_SCHEMA = 'NO_SCHEMA';
30
+ export const NO_PERMS = 'NO_PERMS';
30
31
  export const REVISION_TOO_OLD = 'TOO_OLD';
31
32
 
32
33
  export default class Socket extends EventTarget {
package/utils/time.js CHANGED
@@ -34,6 +34,7 @@ export function diffFrom(value, from, t) {
34
34
  diff,
35
35
  absDiff,
36
36
  label,
37
+ // i18n-uses unit.day, unit.hour, unit.min, unit.sec
37
38
  unitsKey: `unit.${ LABELS[i] }`,
38
39
  units: LABELS[i],
39
40
  next,
package/utils/title.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function updatePageTitle(...breadcrumb: (string | null | undefined | false)[]): void {
2
+ document.title = breadcrumb.filter((s) => s).join(' - ');
3
+ }
@@ -0,0 +1,36 @@
1
+ import { RouterLinkStub } from '@vue/test-utils';
2
+ import { NavigationFailure, Route } from 'vue-router';
3
+
4
+ /**
5
+ * See {@link RouterLinkSlotArgument} in vue-router
6
+ */
7
+ export interface RouterLinkSlotArgumentOptional {
8
+ href?: string;
9
+ route?: Route;
10
+ navigate?: (e?: MouseEvent) => Promise<undefined | NavigationFailure>;
11
+ isActive?: boolean;
12
+ isExactActive?: boolean;
13
+ }
14
+
15
+ /**
16
+ * This is a workaround because VueUtils RouterLinkStub doesn't currently support the slot api.
17
+ *
18
+ * See @link https://github.com/vuejs/vue-test-utils/issues/1803#issuecomment-940884170
19
+ *
20
+ * @param slotProps Provide arguments that you want passed to the child rendered by router-link
21
+ * @returns A stub
22
+ */
23
+ export function createChildRenderingRouterLinkStub(slotProps?: RouterLinkSlotArgumentOptional): typeof RouterLinkStub | any {
24
+ return {
25
+ ...RouterLinkStub,
26
+ render() {
27
+ return this.$scopedSlots.default({
28
+ href: slotProps?.href || '',
29
+ route: slotProps?.route || ({} as any),
30
+ navigate: slotProps?.navigate || (() => {}),
31
+ isActive: slotProps?.isActive || false,
32
+ isExactActive: slotProps?.isExactActive || false,
33
+ });
34
+ }
35
+ };
36
+ }
@@ -103,6 +103,27 @@ describe('formRules', () => {
103
103
  );
104
104
  });
105
105
 
106
+ describe('alphanumeric', () => {
107
+ const message = JSON.stringify({ message: 'validation.alphanumeric', key: 'testDisplayKey' });
108
+ const testCases = [
109
+ ['', undefined],
110
+ ['aaaAAAA111', undefined],
111
+ ['aaaAAAA111//', message],
112
+ ['/', message],
113
+ ['+1', message],
114
+ [undefined, undefined]
115
+ ];
116
+
117
+ it.each(testCases)(
118
+ 'should return undefined or correct message based on the provided url',
119
+ (val, expected) => {
120
+ const formRuleResult = formRules.alphanumeric(val);
121
+
122
+ expect(formRuleResult).toStrictEqual(expected);
123
+ }
124
+ );
125
+ });
126
+
106
127
  it('"interval" : returns undefined when valid hour interval value is supplied', () => {
107
128
  const testValue = '5h';
108
129
  const formRuleResult = formRules.interval(testValue);
@@ -145,6 +145,8 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
145
145
 
146
146
  const url: Validator = (val: string) => val && !isUrl(val) ? t('validation.setting.serverUrl.url') : undefined;
147
147
 
148
+ const alphanumeric: Validator = (val: string) => val && !/^[a-zA-Z0-9]+$/.test(val) ? t('validation.alphanumeric', { key }) : undefined;
149
+
148
150
  const interval: Validator = (val: string) => !/^\d+[hms]$/.test(val) ? t('validation.monitoring.route.interval', { key }) : undefined;
149
151
 
150
152
  const containerImage: Validator = (val: any) => !val?.image ? t('workload.validation.containerImage', { name: val.name }) : undefined;
@@ -458,6 +460,7 @@ export default function(t: Translation, { key = 'Value' }: ValidationOptions): {
458
460
 
459
461
  return {
460
462
  absolutePath,
463
+ alphanumeric,
461
464
  backupTarget,
462
465
  betweenLengths,
463
466
  betweenValues,
@@ -47,6 +47,7 @@ export function validateLength(val, field, displayKey, getters, errors = []) {
47
47
  return errors;
48
48
  }
49
49
 
50
+ // i18n-uses validation.*.exactly, validation.*.between, validation.*.min, validation.*.max
50
51
  const lengthKey = (type.indexOf('array[') === 0 ? 'arrayLength' : 'stringLength');
51
52
 
52
53
  // String and array length: