@rancher/shell 3.0.12-rc.2 → 3.0.12-rc.4

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 (473) hide show
  1. package/apis/impl/apis.ts +6 -0
  2. package/apis/index.ts +26 -0
  3. package/apis/intf/resources-api/cluster-api.ts +18 -0
  4. package/apis/intf/resources-api/mgmt-api.ts +15 -0
  5. package/apis/intf/resources-api/resource-base.ts +107 -0
  6. package/apis/intf/resources-api/resource-constants.ts +147 -0
  7. package/apis/intf/resources-api/resources-api.ts +143 -0
  8. package/apis/intf/resources.ts +49 -0
  9. package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
  10. package/apis/intf/shell-api/proxy.ts +216 -0
  11. package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
  12. package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
  13. package/apis/intf/shell.ts +12 -6
  14. package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
  15. package/apis/resources/index.ts +22 -0
  16. package/apis/resources/resources-api-class.ts +187 -0
  17. package/apis/shell/__tests__/proxy.test.ts +369 -0
  18. package/apis/shell/index.ts +8 -1
  19. package/apis/shell/modal.ts +4 -1
  20. package/apis/shell/notifications.ts +9 -6
  21. package/apis/shell/proxy.ts +256 -0
  22. package/apis/shell/slide-in.ts +4 -1
  23. package/apis/vue-shim.d.ts +2 -1
  24. package/assets/data/aws-regions.json +4 -0
  25. package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
  26. package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
  27. package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
  28. package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
  29. package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
  30. package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
  31. package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
  32. package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
  33. package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
  34. package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
  35. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
  36. package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
  37. package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
  38. package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
  39. package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
  40. package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
  41. package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
  42. package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
  43. package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
  44. package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
  45. package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
  46. package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
  47. package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
  48. package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
  49. package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
  50. package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
  51. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
  52. package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
  53. package/assets/styles/base/_variables.scss +2 -0
  54. package/assets/styles/fonts/_fontstack.scss +132 -8
  55. package/assets/styles/global/_layout.scss +4 -0
  56. package/assets/translations/en-us.yaml +165 -45
  57. package/assets/translations/zh-hans.yaml +1 -7
  58. package/chart/monitoring/ClusterSelector.vue +0 -21
  59. package/chart/monitoring/index.vue +10 -1
  60. package/chart/monitoring/prometheus/index.vue +6 -3
  61. package/components/ActionDropdownShell.vue +2 -1
  62. package/components/CruResource.vue +161 -14
  63. package/components/CruResourceFooter.vue +9 -5
  64. package/components/ExplorerMembers.vue +8 -4
  65. package/components/ExplorerProjectsNamespaces.vue +11 -7
  66. package/components/GrowlManager.vue +4 -0
  67. package/components/InstallHelmCharts.vue +2 -2
  68. package/components/LandingPagePreference.vue +14 -5
  69. package/components/MgmtNodeList.vue +184 -0
  70. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  71. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  72. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  73. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  74. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +17 -1
  75. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  76. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  77. package/components/Resource/Detail/Metadata/index.vue +6 -0
  78. package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
  79. package/components/Resource/Detail/SpacedRow.vue +3 -1
  80. package/components/Resource/Detail/TitleBar/index.vue +10 -11
  81. package/components/ResourceDetail/index.vue +1 -1
  82. package/components/ResourceList/Masthead.vue +19 -9
  83. package/components/ResourceList/index.vue +82 -1
  84. package/components/RichTranslation.vue +5 -2
  85. package/components/SelectIconGrid.vue +0 -10
  86. package/components/Setting.vue +1 -0
  87. package/components/SingleClusterInfo.vue +1 -0
  88. package/components/SortableTable/__tests__/sorting.test.ts +126 -0
  89. package/components/SortableTable/index.vue +6 -9
  90. package/components/SortableTable/selection.js +23 -5
  91. package/components/SortableTable/sorting.js +6 -3
  92. package/components/SubtleLink.vue +31 -6
  93. package/components/Tabbed/Tab.vue +29 -3
  94. package/components/Tabbed/index.vue +25 -3
  95. package/components/TableOfContents/TableOfContents.vue +109 -0
  96. package/components/TableOfContents/composables.ts +258 -0
  97. package/components/Window/ContainerShell.vue +21 -11
  98. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  99. package/components/Wizard.vue +23 -17
  100. package/components/fleet/AppCoChartGrid.vue +401 -0
  101. package/components/fleet/AppCoEmptyState.vue +127 -0
  102. package/components/fleet/AppCoPageHeader.vue +119 -0
  103. package/components/fleet/AppCoVersionSelect.vue +70 -0
  104. package/components/fleet/FleetBundles.vue +100 -12
  105. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  106. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  107. package/components/fleet/FleetClusterTargets/index.vue +226 -161
  108. package/components/fleet/FleetIntro.vue +7 -3
  109. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  110. package/components/fleet/FleetSecretSelector.vue +5 -3
  111. package/components/fleet/FleetValuesFrom.vue +8 -2
  112. package/components/fleet/GitRepoTargetTab.vue +0 -2
  113. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  114. package/components/fleet/HelmOpAppCoConfigTab.vue +593 -0
  115. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  116. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  117. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  118. package/components/fleet/HelmOpTargetTab.vue +64 -60
  119. package/components/fleet/HelmOpValuesTab.vue +129 -105
  120. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  121. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  122. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  123. package/components/fleet/__tests__/FleetClusterTargets.test.ts +402 -115
  124. package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
  125. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  126. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  127. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  128. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  129. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  130. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  131. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  132. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  133. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  134. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  135. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  136. package/components/fleet/dashboard/Empty.vue +8 -4
  137. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  138. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  139. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  140. package/components/form/ArrayList.vue +61 -4
  141. package/components/form/KeyValue.vue +23 -2
  142. package/components/form/LabeledSelect.vue +59 -4
  143. package/components/form/Labels.vue +22 -3
  144. package/components/form/NameNsDescription.vue +24 -5
  145. package/components/form/ResourceTabs/index.vue +1 -0
  146. package/components/form/Security.vue +6 -2
  147. package/components/form/WorkloadPorts.vue +2 -7
  148. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  149. package/components/form/__tests__/Security.test.ts +76 -0
  150. package/components/formatter/Autoscaler.vue +4 -4
  151. package/components/formatter/ClusterKubeVersion.vue +27 -0
  152. package/components/formatter/ClusterLink.vue +1 -7
  153. package/components/formatter/ClusterProvider.vue +6 -10
  154. package/components/formatter/FleetSummaryGraph.vue +0 -3
  155. package/components/formatter/InternalExternalIP.vue +10 -4
  156. package/components/formatter/MachineSummaryGraph.vue +1 -1
  157. package/components/formatter/PodsUsage.vue +2 -2
  158. package/components/formatter/ServiceTargets.vue +26 -7
  159. package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
  160. package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
  161. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  162. package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
  163. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  164. package/components/nav/Header.vue +4 -0
  165. package/components/nav/NamespaceFilter.vue +2 -2
  166. package/components/nav/TopLevelMenu.helper.ts +15 -3
  167. package/components/nav/TopLevelMenu.vue +22 -6
  168. package/components/nav/__tests__/Header.test.ts +15 -0
  169. package/components/nav/__tests__/TopLevelMenu.test.ts +263 -21
  170. package/components/templates/default.vue +9 -4
  171. package/components/templates/home.vue +23 -0
  172. package/components/templates/plain.vue +23 -0
  173. package/components/templates/standalone.vue +17 -0
  174. package/composables/useFormValidation.ts +93 -0
  175. package/composables/useHelmOpResources.test.ts +56 -0
  176. package/composables/useHelmOpResources.ts +32 -0
  177. package/composables/useStateColor.test.ts +325 -0
  178. package/composables/useStateColor.ts +128 -0
  179. package/composables/useVeeValidateField.test.ts +159 -0
  180. package/composables/useVeeValidateField.ts +67 -0
  181. package/config/home-links.js +1 -1
  182. package/config/labels-annotations.js +1 -0
  183. package/config/pagination-table-headers.js +18 -1
  184. package/config/product/explorer.js +17 -4
  185. package/config/product/manager.js +84 -21
  186. package/config/router/index.js +16 -0
  187. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  188. package/config/router/navigation-guards/authentication.js +10 -4
  189. package/config/router/routes.js +26 -6
  190. package/config/settings.ts +0 -2
  191. package/config/table-headers.js +23 -5
  192. package/config/types.js +11 -1
  193. package/core/__tests__/plugin-products.test.ts +904 -20
  194. package/core/plugin-products-base.ts +110 -10
  195. package/core/plugin-products.ts +4 -0
  196. package/core/plugin-types.ts +194 -31
  197. package/core/plugin.ts +18 -7
  198. package/core/productDebugger.js +9 -4
  199. package/core/types-provisioning.ts +77 -31
  200. package/core/types.ts +72 -22
  201. package/detail/__tests__/pod.test.ts +41 -0
  202. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  203. package/detail/__tests__/workload.test.ts +3 -152
  204. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  205. package/detail/harvesterhci.io.management.cluster.vue +6 -2
  206. package/detail/pod.vue +1 -1
  207. package/detail/provisioning.cattle.io.cluster.vue +34 -14
  208. package/detail/workload/index.vue +12 -55
  209. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  210. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +105 -0
  211. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  212. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  213. package/edit/auth/__tests__/azuread.test.ts +247 -39
  214. package/edit/auth/__tests__/github.test.ts +234 -0
  215. package/edit/auth/__tests__/oidc.test.ts +26 -6
  216. package/edit/auth/__tests__/saml.test.ts +196 -0
  217. package/edit/auth/azuread.vue +197 -56
  218. package/edit/auth/github.vue +72 -13
  219. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  220. package/edit/auth/ldap/config.vue +8 -0
  221. package/edit/auth/ldap/index.vue +75 -1
  222. package/edit/auth/oidc.vue +119 -73
  223. package/edit/auth/saml.vue +76 -12
  224. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  225. package/edit/fleet.cattle.io.helmop.vue +491 -136
  226. package/edit/management.cattle.io.user.vue +5 -2
  227. package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
  228. package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
  229. package/edit/networking.k8s.io.ingress/index.vue +75 -20
  230. package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
  231. package/edit/provisioning.cattle.io.cluster/index.vue +11 -7
  232. package/edit/provisioning.cattle.io.cluster/rke2.vue +92 -14
  233. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +22 -0
  234. package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
  235. package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
  236. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
  237. package/edit/secret/__tests__/ssh.test.ts +5 -6
  238. package/edit/secret/basic.vue +31 -0
  239. package/edit/secret/index.vue +68 -17
  240. package/edit/secret/registry.vue +38 -0
  241. package/edit/secret/ssh.vue +29 -0
  242. package/edit/secret/tls.vue +30 -0
  243. package/edit/service.vue +4 -4
  244. package/edit/workload/Upgrading.vue +3 -3
  245. package/edit/workload/__tests__/Upgrading.test.ts +6 -9
  246. package/edit/workload/mixins/workload.js +2 -1
  247. package/list/fleet.cattle.io.bundle.vue +7 -104
  248. package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
  249. package/list/group.principal.vue +5 -4
  250. package/list/harvesterhci.io.management.cluster.vue +8 -9
  251. package/list/management.cattle.io.user.vue +12 -9
  252. package/list/provisioning.cattle.io.cluster.vue +268 -180
  253. package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
  254. package/mixins/__tests__/auth-config.test.ts +90 -0
  255. package/mixins/__tests__/chart.test.ts +206 -0
  256. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  257. package/mixins/auth-config.js +7 -0
  258. package/mixins/brand.js +2 -1
  259. package/mixins/chart.js +22 -9
  260. package/mixins/child-hook.js +12 -6
  261. package/mixins/create-edit-view/impl.js +5 -3
  262. package/mixins/resource-fetch-api-pagination.js +62 -6
  263. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  264. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  265. package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
  266. package/models/__tests__/fleet-application.test.ts +175 -0
  267. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  268. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  269. package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
  270. package/models/__tests__/management.cattle.io.node.ts +28 -5
  271. package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
  272. package/models/__tests__/namespace.test.ts +36 -0
  273. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +81 -11
  274. package/models/__tests__/workload.test.ts +401 -26
  275. package/models/base-cluster.x-k8s.io.js +26 -0
  276. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  277. package/models/cluster.js +1 -1
  278. package/models/cluster.x-k8s.io.machine.js +4 -22
  279. package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
  280. package/models/cluster.x-k8s.io.machineset.js +2 -20
  281. package/models/compliance.cattle.io.clusterscan.js +165 -2
  282. package/models/ext.cattle.io.kubeconfig.ts +4 -7
  283. package/models/fleet-application.js +7 -1
  284. package/models/fleet.cattle.io.helmop.js +20 -1
  285. package/models/management.cattle.io.cluster.js +434 -41
  286. package/models/management.cattle.io.node.js +50 -7
  287. package/models/management.cattle.io.nodepool.js +1 -1
  288. package/models/namespace.js +1 -1
  289. package/models/networking.k8s.io.ingress.js +12 -4
  290. package/models/pod.js +33 -1
  291. package/models/provisioning.cattle.io.cluster.js +51 -334
  292. package/models/rke.cattle.io.etcdsnapshot.js +1 -2
  293. package/models/workload.js +108 -13
  294. package/models/workload.service.js +5 -0
  295. package/package.json +22 -39
  296. package/pages/__tests__/readme.test.ts +49 -0
  297. package/pages/about.vue +5 -6
  298. package/pages/auth/login.vue +0 -35
  299. package/pages/auth/setup.vue +13 -3
  300. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  301. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  302. package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +76 -0
  303. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  304. package/pages/c/_cluster/apps/charts/chart.vue +62 -9
  305. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  306. package/pages/c/_cluster/apps/charts/install.vue +122 -113
  307. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  308. package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
  309. package/pages/c/_cluster/explorer/index.vue +5 -49
  310. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  311. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  312. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  313. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  314. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  315. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  316. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  317. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  318. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  319. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  320. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  321. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  322. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  323. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  324. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  325. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  326. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  327. package/pages/c/_cluster/fleet/index.vue +2 -2
  328. package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
  329. package/pages/c/_cluster/istio/index.vue +21 -6
  330. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +1 -0
  331. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +815 -2
  332. package/pages/c/_cluster/uiplugins/index.vue +218 -197
  333. package/pages/diagnostic.vue +13 -17
  334. package/pages/fail-whale.vue +30 -7
  335. package/pages/home.vue +93 -306
  336. package/pages/readme.vue +88 -0
  337. package/plugins/clean-html.d.ts +9 -0
  338. package/plugins/dashboard-store/__tests__/resource-class.test.ts +181 -0
  339. package/plugins/dashboard-store/actions.js +40 -18
  340. package/plugins/dashboard-store/resource-class.js +67 -9
  341. package/plugins/steve/__tests__/actions.test.ts +212 -0
  342. package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
  343. package/plugins/steve/actions.js +96 -0
  344. package/plugins/steve/steve-pagination-utils.ts +12 -4
  345. package/plugins/steve/subscribe.js +35 -5
  346. package/rancher-components/Accordion/Accordion.vue +53 -9
  347. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  348. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +10 -4
  349. package/rancher-components/Form/LabeledInput/LabeledInput.vue +7 -52
  350. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  351. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  352. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  353. package/rancher-components/RcButton/RcButton.test.ts +140 -1
  354. package/rancher-components/RcButton/RcButton.vue +126 -17
  355. package/rancher-components/RcButton/types.ts +3 -0
  356. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
  357. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  358. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  359. package/rancher-components/RcSection/RcSection.vue +28 -3
  360. package/scripts/extension/helm/package/Dockerfile +1 -1
  361. package/scripts/test-plugins-build.sh +2 -1
  362. package/store/__tests__/catalog.test.ts +115 -1
  363. package/store/__tests__/notifications.test.ts +434 -0
  364. package/store/__tests__/type-map.test.ts +556 -1
  365. package/store/action-menu.js +8 -3
  366. package/store/auth.js +1 -1
  367. package/store/aws.js +27 -16
  368. package/store/catalog.js +84 -3
  369. package/store/digitalocean.js +20 -38
  370. package/store/index.js +2 -0
  371. package/store/linode.js +25 -40
  372. package/store/plugins.js +7 -4
  373. package/store/pnap.js +1 -0
  374. package/store/type-map.js +111 -29
  375. package/tsconfig.paths.json +8 -8
  376. package/types/components/buttonGroup.ts +5 -0
  377. package/types/kube/kube-api.ts +14 -1
  378. package/types/rancher/steve.api.ts +12 -12
  379. package/types/resources/settings.d.ts +2 -1
  380. package/types/shell/index.d.ts +206 -72
  381. package/types/store/dashboard-store.types.ts +108 -11
  382. package/types/store/pagination.types.ts +6 -3
  383. package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
  384. package/utils/__tests__/async.test.ts +87 -0
  385. package/utils/__tests__/auth.test.ts +273 -0
  386. package/utils/__tests__/aws.test.ts +140 -0
  387. package/utils/__tests__/banners.test.ts +176 -0
  388. package/utils/__tests__/chart.test.ts +64 -1
  389. package/utils/__tests__/color.test.ts +226 -0
  390. package/utils/__tests__/computed.test.ts +193 -0
  391. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  392. package/utils/__tests__/dom.test.ts +81 -0
  393. package/utils/__tests__/duration.test.ts +176 -0
  394. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  395. package/utils/__tests__/fleet-appco.test.ts +312 -0
  396. package/utils/__tests__/fleet.test.ts +340 -0
  397. package/utils/__tests__/ingress.test.ts +553 -0
  398. package/utils/__tests__/kube.test.ts +68 -0
  399. package/utils/__tests__/monitoring.test.ts +130 -0
  400. package/utils/__tests__/namespace-filter.test.ts +109 -0
  401. package/utils/__tests__/object.test.ts +22 -0
  402. package/utils/__tests__/pagination-utils.test.ts +361 -0
  403. package/utils/__tests__/parse-externalid.test.ts +137 -0
  404. package/utils/__tests__/perf-setting.utils.test.ts +98 -0
  405. package/utils/__tests__/platform.test.ts +91 -0
  406. package/utils/__tests__/poller-sequential.test.ts +177 -0
  407. package/utils/__tests__/poller.test.ts +170 -0
  408. package/utils/__tests__/position.test.ts +237 -0
  409. package/utils/__tests__/promise.test.ts +346 -0
  410. package/utils/__tests__/provider.test.ts +51 -1
  411. package/utils/__tests__/queue.test.ts +232 -0
  412. package/utils/__tests__/release-notes.test.ts +221 -0
  413. package/utils/__tests__/router.test.js +254 -1
  414. package/utils/__tests__/select.test.ts +208 -0
  415. package/utils/__tests__/settings.test.ts +140 -0
  416. package/utils/__tests__/sort-utils.test.ts +301 -0
  417. package/utils/__tests__/string-utils.test.ts +798 -0
  418. package/utils/__tests__/string.test.ts +23 -1
  419. package/utils/__tests__/style.test.ts +154 -0
  420. package/utils/__tests__/svg-filter.test.ts +184 -0
  421. package/utils/__tests__/time.test.ts +265 -1
  422. package/utils/__tests__/title.test.ts +47 -0
  423. package/utils/__tests__/units.test.ts +417 -0
  424. package/utils/__tests__/versions.test.ts +128 -0
  425. package/utils/__tests__/width.test.ts +53 -0
  426. package/utils/__tests__/window.test.ts +158 -0
  427. package/utils/__tests__/xccdf.test.ts +511 -0
  428. package/utils/chart.js +36 -0
  429. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  430. package/utils/crypto/__tests__/index.test.ts +144 -0
  431. package/utils/duration.ts +104 -0
  432. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  433. package/utils/dynamic-content/info.ts +2 -1
  434. package/utils/error.js +13 -0
  435. package/utils/fleet-appco.ts +323 -0
  436. package/utils/fleet.ts +13 -3
  437. package/utils/gatekeeper/__tests__/util.test.ts +174 -0
  438. package/utils/gc/__tests__/gc-interval.test.ts +119 -0
  439. package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
  440. package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
  441. package/utils/gc/__tests__/gc.test.ts +487 -0
  442. package/utils/ingress.ts +9 -1
  443. package/utils/object.js +22 -2
  444. package/utils/pagination-utils.ts +2 -1
  445. package/utils/provider.ts +12 -0
  446. package/utils/string.js +25 -2
  447. package/utils/uiplugins.ts +5 -5
  448. package/utils/validators/__tests__/cluster-name.test.ts +110 -0
  449. package/utils/validators/__tests__/container-images.test.ts +104 -0
  450. package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
  451. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  452. package/utils/validators/__tests__/index.test.ts +481 -0
  453. package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
  454. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  455. package/utils/validators/__tests__/misc-validators.test.ts +246 -0
  456. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  457. package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
  458. package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
  459. package/utils/validators/__tests__/role-template.test.ts +149 -0
  460. package/utils/validators/__tests__/service.test.ts +283 -0
  461. package/utils/validators/__tests__/setting.test.js +32 -0
  462. package/utils/validators/formRules/__tests__/index.test.ts +50 -0
  463. package/utils/validators/formRules/index.ts +5 -5
  464. package/utils/validators/machine-pool.ts +1 -1
  465. package/utils/validators/setting.js +18 -3
  466. package/utils/xccdf.ts +415 -0
  467. package/vue.config.js +1 -1
  468. package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
  469. package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
  470. package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
  471. package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
  472. package/pages/support/index.vue +0 -264
  473. package/utils/duration.js +0 -43
@@ -1,4 +1,9 @@
1
1
  <script>
2
+ import { ref, computed, provide } from 'vue';
3
+ import { useStore } from 'vuex';
4
+ import { useForm } from 'vee-validate';
5
+ import { toTypedSchema } from '@vee-validate/zod';
6
+ import * as z from 'zod';
2
7
  import Loading from '@shell/components/Loading';
3
8
  import CreateEditView from '@shell/mixins/create-edit-view';
4
9
  import CruResource from '@shell/components/CruResource';
@@ -13,6 +18,7 @@ import AuthProviderWarningBanners from '@shell/edit/auth/AuthProviderWarningBann
13
18
  import FileSelector from '@shell/components/form/FileSelector';
14
19
  import GithubSteps from '@shell/edit/auth/github-steps.vue';
15
20
  import GithubAppSteps from '@shell/edit/auth/github-app-steps.vue';
21
+ import { useI18n } from '@shell/composables/useI18n';
16
22
 
17
23
  export default {
18
24
  components: {
@@ -30,6 +36,49 @@ export default {
30
36
 
31
37
  mixins: [CreateEditView, AuthConfig],
32
38
 
39
+ setup() {
40
+ const store = useStore();
41
+ const { t } = useI18n(store);
42
+
43
+ // These refs sync Options API state into the Composition API for the reactive schema.
44
+ const isGithubAppRef = ref(false);
45
+ const isPublicRef = ref(true);
46
+
47
+ const coerce = (schema) => z.preprocess((v) => v ?? '', schema);
48
+ const requiredField = (key) => coerce(z.string().min(1, t('validation.required', { key: t(key) })));
49
+ const requiredUrlField = (key) => coerce(z.string().min(1, t('validation.required', { key: t(key) })).url(t('validation.genericUrl')));
50
+ const optionalField = coerce(z.string());
51
+
52
+ const validationSchema = computed(() => toTypedSchema(
53
+ z.object({
54
+ clientId: requiredField('authConfig.github.clientId.label'),
55
+ clientSecret: requiredField('authConfig.github.clientSecret.label'),
56
+ appId: isGithubAppRef.value ? requiredField('authConfig.githubapp.githubAppId.label') : optionalField,
57
+ privateKey: isGithubAppRef.value ? requiredField('authConfig.githubapp.privateKey.label') : optionalField,
58
+ targetUrl: !isPublicRef.value ? requiredUrlField('authConfig.github.host.label') : optionalField,
59
+ })
60
+ ));
61
+
62
+ const showAllErrors = ref(false);
63
+
64
+ provide('vee-show-all-errors', showAllErrors);
65
+
66
+ const { errors, validate } = useForm({ validationSchema });
67
+ const isFormValid = computed(() => Object.keys(errors.value).length === 0);
68
+
69
+ const validateAllFields = async() => {
70
+ await validate();
71
+ showAllErrors.value = true;
72
+ };
73
+
74
+ return {
75
+ isGithubAppRef,
76
+ isPublicRef,
77
+ isFormValid,
78
+ validateAllFields,
79
+ };
80
+ },
81
+
33
82
  async fetch() {
34
83
  await this.mixinFetch();
35
84
 
@@ -97,32 +146,37 @@ export default {
97
146
  },
98
147
 
99
148
  validationPassed() {
100
- // Allows for configuring authorized users and groups
101
149
  if ( this.model.enabled && !this.editConfig ) {
102
150
  return true;
103
151
  }
104
152
 
105
- if (!this.model.clientId || !this.model.clientSecret) {
106
- return false;
107
- }
108
-
109
- if (this.isGithubApp && (!this.model.appId || !this.model.privateKey)) {
110
- return false;
111
- }
112
-
113
- return true;
153
+ return this.isFormValid;
114
154
  },
115
155
 
116
156
  },
117
157
 
118
158
  watch: {
119
- targetType: 'updateHost',
120
- targetUrl: 'updateHost',
159
+ 'model.id': {
160
+ handler(newVal) {
161
+ this.isGithubAppRef = newVal === 'githubapp';
162
+ },
163
+ immediate: true,
164
+ },
165
+
166
+ targetType: {
167
+ handler(newVal) {
168
+ this.isPublicRef = newVal === 'public';
169
+ this.updateHost();
170
+ },
171
+ immediate: true,
172
+ },
173
+
174
+ targetUrl: 'updateHost',
121
175
  },
122
176
 
123
177
  methods: {
124
178
  updateHost() {
125
- const match = this.targetUrl.match(/^(((https?):)?\/\/)?([^/]+)(\/.*)?$/);
179
+ const match = this.targetUrl?.match(/^(((https?):)?\/\/)?([^/]+)(\/.*)?$/);
126
180
 
127
181
  if ( match ) {
128
182
  if ( match[3] === 'http') {
@@ -212,6 +266,7 @@ export default {
212
266
  <LabeledInput
213
267
  v-if="!isPublic"
214
268
  v-model:value="targetUrl"
269
+ name="targetUrl"
215
270
  :label-key="`authConfig.${NAME}.host.label`"
216
271
  :placeholder="t(`authConfig.${NAME}.host.placeholder`)"
217
272
  :required="true"
@@ -231,6 +286,7 @@ export default {
231
286
  <div class="col span-6">
232
287
  <LabeledInput
233
288
  v-model:value="model.clientId"
289
+ name="clientId"
234
290
  required
235
291
  data-testid="client-id"
236
292
  :label="t(`authConfig.${NAME}.clientId.label`)"
@@ -240,6 +296,7 @@ export default {
240
296
  <div class="col span-6">
241
297
  <LabeledInput
242
298
  v-model:value="model.clientSecret"
299
+ name="clientSecret"
243
300
  required
244
301
  data-testid="client-secret"
245
302
  type="password"
@@ -253,6 +310,7 @@ export default {
253
310
  <div class="col span-6">
254
311
  <LabeledInput
255
312
  v-model:value="model.appId"
313
+ name="appId"
256
314
  required
257
315
  data-testid="app-id"
258
316
  :label="t(`authConfig.${NAME}.githubAppId.label`)"
@@ -272,6 +330,7 @@ export default {
272
330
  <div class="col span-6">
273
331
  <LabeledInput
274
332
  v-model:value="model.privateKey"
333
+ name="privateKey"
275
334
  required
276
335
  data-testid="private-key"
277
336
  type="multiline"
@@ -0,0 +1,206 @@
1
+ import { nextTick } from 'vue';
2
+ import { mount, type VueWrapper, flushPromises } from '@vue/test-utils';
3
+ import { _EDIT } from '@shell/config/query-params';
4
+
5
+ import LDAPIndex from '@shell/edit/auth/ldap/index.vue';
6
+
7
+ jest.mock('@shell/utils/clipboard', () => {
8
+ return { copyTextToClipboard: jest.fn(() => Promise.resolve({})) };
9
+ });
10
+
11
+ const validOpenLdapModel = {
12
+ enabled: false,
13
+ servers: ['ldap.example.com'],
14
+ port: 389,
15
+ connectionTimeout: 5000,
16
+ serviceAccountDistinguishedName: 'cn=admin,dc=example,dc=com',
17
+ serviceAccountPassword: 'secretpassword',
18
+ userSearchBase: 'dc=example,dc=com',
19
+ };
20
+
21
+ const validActiveDirectoryModel = {
22
+ enabled: false,
23
+ servers: ['ad.example.com'],
24
+ port: 389,
25
+ connectionTimeout: 5000,
26
+ serviceAccountUsername: 'DOMAIN\\admin',
27
+ serviceAccountPassword: 'secretpassword',
28
+ userSearchBase: 'dc=example,dc=com',
29
+ };
30
+
31
+ const validUsername = 'testuser';
32
+ const validPassword = 'testpassword';
33
+
34
+ const buildSetup = (type = 'openldap', modelOverride = {}, localDataOverride = {}) => ({
35
+ data() {
36
+ const baseModel = type === 'activedirectory' ? validActiveDirectoryModel : validOpenLdapModel;
37
+
38
+ return {
39
+ isEnabling: false,
40
+ editConfig: false,
41
+ model: { ...baseModel, ...modelOverride },
42
+ username: validUsername,
43
+ password: validPassword,
44
+ errors: [],
45
+ serverSetting: null,
46
+ originalModel: null,
47
+ principals: [],
48
+ authConfigName: type,
49
+ ...localDataOverride,
50
+ } as any;
51
+ },
52
+ global: {
53
+ mocks: {
54
+ $fetchState: { pending: false },
55
+ $store: {
56
+ getters: {
57
+ currentStore: () => 'current_store',
58
+ 'current_store/schemaFor': jest.fn(),
59
+ 'current_store/all': jest.fn(),
60
+ 'i18n/t': (val: string) => val,
61
+ 'i18n/exists': jest.fn(),
62
+ },
63
+ dispatch: jest.fn()
64
+ },
65
+ $route: { query: { AS: '' }, params: { id: type } },
66
+ $router: { applyQuery: jest.fn() },
67
+ },
68
+ },
69
+ props: {
70
+ value: { ...validOpenLdapModel, ...modelOverride },
71
+ mode: _EDIT,
72
+ },
73
+ });
74
+
75
+ const mountAndValidate = async(type: string, modelOverride = {}, localDataOverride = {}) => {
76
+ const wrapper = mount(LDAPIndex, buildSetup(type, modelOverride, localDataOverride));
77
+
78
+ await wrapper.vm.validateAllFields();
79
+ await flushPromises();
80
+
81
+ return wrapper;
82
+ };
83
+
84
+ describe('ldap/index.vue', () => {
85
+ describe('given default valid values (openldap)', () => {
86
+ let wrapper: VueWrapper<any, any>;
87
+
88
+ beforeEach(() => {
89
+ wrapper = mount(LDAPIndex, buildSetup());
90
+ });
91
+
92
+ afterEach(() => {
93
+ wrapper.unmount();
94
+ });
95
+
96
+ it('has "Enable" button enabled when all required fields are filled', async() => {
97
+ await nextTick();
98
+
99
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
100
+
101
+ expect(saveButton.disabled).toBe(false);
102
+ });
103
+
104
+ it('has "Enable" button enabled when provider is already enabled and not editing config', async() => {
105
+ wrapper.setData({ model: { ...validOpenLdapModel, enabled: true }, editConfig: false });
106
+ await nextTick();
107
+
108
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
109
+
110
+ expect(saveButton.disabled).toBe(false);
111
+ });
112
+ });
113
+
114
+ describe('have "Enable" button disabled when required fields are empty', () => {
115
+ it.each([
116
+ ['username', { username: '', password: validPassword }],
117
+ ['password', { username: validUsername, password: '' }],
118
+ ])('given empty %s (test credentials)', async(field, localData) => {
119
+ const wrapper = await mountAndValidate('openldap', {}, localData);
120
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
121
+
122
+ expect(saveButton.disabled).toBe(true);
123
+ wrapper.unmount();
124
+ });
125
+
126
+ it.each([
127
+ ['serviceAccountDistinguishedName', { serviceAccountDistinguishedName: '' }],
128
+ ['serviceAccountPassword', { serviceAccountPassword: '' }],
129
+ ['userSearchBase', { userSearchBase: '' }],
130
+ ])('given empty %s (config field)', async(field, modelOverride) => {
131
+ const wrapper = await mountAndValidate('openldap', modelOverride);
132
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
133
+
134
+ expect(saveButton.disabled).toBe(true);
135
+ wrapper.unmount();
136
+ });
137
+ });
138
+
139
+ describe('certificate conditional validation', () => {
140
+ it('is not required when TLS and STARTTLS are disabled', async() => {
141
+ const wrapper = await mountAndValidate('openldap', { tls: false, starttls: false });
142
+
143
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
144
+
145
+ expect(saveButton.disabled).toBe(false);
146
+ wrapper.unmount();
147
+ });
148
+
149
+ it('is required and causes button disabled when TLS is enabled and certificate is empty', async() => {
150
+ const wrapper = await mountAndValidate('openldap', {
151
+ tls: true,
152
+ starttls: false,
153
+ certificate: '',
154
+ });
155
+
156
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
157
+
158
+ expect(saveButton.disabled).toBe(true);
159
+ wrapper.unmount();
160
+ });
161
+
162
+ it('button is enabled when TLS is enabled and certificate is provided', async() => {
163
+ const wrapper = mount(LDAPIndex, buildSetup('openldap', {
164
+ tls: true,
165
+ starttls: false,
166
+ certificate: '-----BEGIN CERTIFICATE-----\nMIIB\n-----END CERTIFICATE-----',
167
+ }));
168
+
169
+ await nextTick();
170
+
171
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
172
+
173
+ expect(saveButton.disabled).toBe(false);
174
+ wrapper.unmount();
175
+ });
176
+ });
177
+
178
+ describe('service account field conditional validation', () => {
179
+ it('requires serviceAccountDistinguishedName for openldap when empty', async() => {
180
+ const wrapper = await mountAndValidate('openldap', { serviceAccountDistinguishedName: '' });
181
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
182
+
183
+ expect(saveButton.disabled).toBe(true);
184
+ wrapper.unmount();
185
+ });
186
+
187
+ it('requires serviceAccountUsername for activedirectory when empty', async() => {
188
+ const wrapper = await mountAndValidate('activedirectory', { serviceAccountUsername: '' });
189
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
190
+
191
+ expect(saveButton.disabled).toBe(true);
192
+ wrapper.unmount();
193
+ });
194
+
195
+ it('button is enabled for activedirectory when serviceAccountUsername is provided', async() => {
196
+ const wrapper = mount(LDAPIndex, buildSetup('activedirectory'));
197
+
198
+ await nextTick();
199
+
200
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
201
+
202
+ expect(saveButton.disabled).toBe(false);
203
+ wrapper.unmount();
204
+ });
205
+ });
206
+ });
@@ -110,6 +110,7 @@ export default {
110
110
  <div class="col span-6">
111
111
  <LabeledInput
112
112
  v-model:value="hostname"
113
+ name="hostname"
113
114
  required
114
115
  :mode="mode"
115
116
  :hoover-tooltip="true"
@@ -121,6 +122,7 @@ export default {
121
122
  <div class="col span-4">
122
123
  <LabeledInput
123
124
  :value="model.port"
125
+ name="port"
124
126
  type="number"
125
127
  required
126
128
  :min="0"
@@ -156,6 +158,7 @@ export default {
156
158
  <div class="col span-12">
157
159
  <LabeledInput
158
160
  v-model:value="model.certificate"
161
+ name="certificate"
159
162
  required
160
163
  type="multiline"
161
164
  :mode="mode"
@@ -173,6 +176,7 @@ export default {
173
176
  <div class="col span-6">
174
177
  <UnitInput
175
178
  v-model:value="model.connectionTimeout"
179
+ name="connectionTimeout"
176
180
  required
177
181
  :mode="mode"
178
182
  :label="t('authConfig.ldap.serverConnectionTimeout')"
@@ -191,6 +195,7 @@ export default {
191
195
  >
192
196
  <LabeledInput
193
197
  v-model:value="model.serviceAccountUsername"
198
+ name="serviceAccountUsername"
194
199
  required
195
200
  :mode="mode"
196
201
  :label="t('authConfig.ldap.serviceAccountDN')"
@@ -203,6 +208,7 @@ export default {
203
208
  >
204
209
  <LabeledInput
205
210
  v-model:value="model.serviceAccountDistinguishedName"
211
+ name="serviceAccountDistinguishedName"
206
212
  required
207
213
  :mode="mode"
208
214
  :label="t('authConfig.ldap.serviceAccountDN')"
@@ -211,6 +217,7 @@ export default {
211
217
  <div class="col span-6">
212
218
  <LabeledInput
213
219
  v-model:value="model.serviceAccountPassword"
220
+ name="serviceAccountPassword"
214
221
  required
215
222
  type="password"
216
223
  :mode="mode"
@@ -254,6 +261,7 @@ export default {
254
261
  <div class="col span-6">
255
262
  <LabeledInput
256
263
  v-model:value="model.userSearchBase"
264
+ name="userSearchBase"
257
265
  required
258
266
  :mode="mode"
259
267
  :label="t('authConfig.ldap.userSearchBase.label')"
@@ -1,4 +1,9 @@
1
1
  <script>
2
+ import { ref, computed, provide } from 'vue';
3
+ import { useStore } from 'vuex';
4
+ import { useForm } from 'vee-validate';
5
+ import { toTypedSchema } from '@vee-validate/zod';
6
+ import * as z from 'zod';
2
7
  import Loading from '@shell/components/Loading';
3
8
  import CreateEditView from '@shell/mixins/create-edit-view';
4
9
  import CruResource from '@shell/components/CruResource';
@@ -9,6 +14,7 @@ import AuthConfig from '@shell/mixins/auth-config';
9
14
  import AuthBanner from '@shell/components/auth/AuthBanner';
10
15
  import Password from '@shell/components/form/Password';
11
16
  import AuthProviderWarningBanners from '@shell/edit/auth/AuthProviderWarningBanners';
17
+ import { useI18n } from '@shell/composables/useI18n';
12
18
 
13
19
  const AUTH_TYPE = 'ldap';
14
20
 
@@ -26,6 +32,49 @@ export default {
26
32
 
27
33
  mixins: [CreateEditView, AuthConfig],
28
34
 
35
+ setup() {
36
+ const store = useStore();
37
+ const { t } = useI18n(store);
38
+
39
+ const coerce = (schema) => z.preprocess((v) => (v === null || v === undefined) ? '' : String(v), schema);
40
+ const requiredField = (key) => coerce(z.string().min(1, t('validation.required', { key: t(key) })));
41
+ const optionalField = coerce(z.string());
42
+
43
+ const tlsEnabledRef = ref(false);
44
+ const isActiveDirectoryRef = ref(false);
45
+
46
+ const validationSchema = computed(() => toTypedSchema(
47
+ z.object({
48
+ hostname: requiredField('authConfig.ldap.hostname.label'),
49
+ port: requiredField('authConfig.ldap.port'),
50
+ certificate: tlsEnabledRef.value ? requiredField('authConfig.ldap.cert') : optionalField,
51
+ connectionTimeout: requiredField('authConfig.ldap.serverConnectionTimeout'),
52
+ serviceAccountUsername: isActiveDirectoryRef.value ? requiredField('authConfig.ldap.serviceAccountDN') : optionalField,
53
+ serviceAccountDistinguishedName: !isActiveDirectoryRef.value ? requiredField('authConfig.ldap.serviceAccountDN') : optionalField,
54
+ serviceAccountPassword: requiredField('authConfig.ldap.serviceAccountPassword'),
55
+ userSearchBase: requiredField('authConfig.ldap.userSearchBase.label'),
56
+ username: requiredField(`authConfig.${ AUTH_TYPE }.username`),
57
+ password: requiredField(`authConfig.${ AUTH_TYPE }.password`),
58
+ })
59
+ ));
60
+
61
+ const showAllErrors = ref(false);
62
+
63
+ provide('vee-show-all-errors', showAllErrors);
64
+
65
+ const { errors, validate } = useForm({ validationSchema });
66
+ const isFormValid = computed(() => Object.keys(errors.value).length === 0);
67
+
68
+ const validateAllFields = async() => {
69
+ await validate();
70
+ showAllErrors.value = true;
71
+ };
72
+
73
+ return {
74
+ isFormValid, validateAllFields, tlsEnabledRef, isActiveDirectoryRef
75
+ };
76
+ },
77
+
29
78
  data() {
30
79
  return {
31
80
  username: null,
@@ -33,7 +82,21 @@ export default {
33
82
  };
34
83
  },
35
84
 
85
+ created() {
86
+ this.tlsEnabledRef = !!(this.model?.tls || this.model?.starttls);
87
+ this.isActiveDirectoryRef = this.NAME === 'activedirectory';
88
+ this.registerBeforeHook(this.validateAllFields, 'willSave');
89
+ },
90
+
36
91
  computed: {
92
+ validationPassed() {
93
+ if (this.model?.enabled && !this.editConfig) {
94
+ return true;
95
+ }
96
+
97
+ return this.isFormValid;
98
+ },
99
+
37
100
  tArgs() {
38
101
  return {
39
102
  provider: this.displayName,
@@ -66,6 +129,15 @@ export default {
66
129
  },
67
130
  },
68
131
 
132
+ watch: {
133
+ 'model.tls'(neu) {
134
+ this.tlsEnabledRef = !!(neu || this.model?.starttls);
135
+ },
136
+ 'model.starttls'(neu) {
137
+ this.tlsEnabledRef = !!(this.model?.tls || neu);
138
+ },
139
+ },
140
+
69
141
  };
70
142
  </script>
71
143
 
@@ -78,7 +150,7 @@ export default {
78
150
  :mode="mode"
79
151
  :resource="model"
80
152
  :subtypes="[]"
81
- :validation-passed="true"
153
+ :validation-passed="validationPassed"
82
154
  :finish-button-mode="model.enabled ? 'edit' : 'enable'"
83
155
  :can-yaml="false"
84
156
  :errors="errors"
@@ -126,6 +198,7 @@ export default {
126
198
  <div class="col span-6">
127
199
  <LabeledInput
128
200
  v-model:value="username"
201
+ name="username"
129
202
  :label="t(`authConfig.${AUTH_TYPE}.username`)"
130
203
  :mode="mode"
131
204
  required
@@ -134,6 +207,7 @@ export default {
134
207
  <div class="col span-6">
135
208
  <Password
136
209
  v-model:value="password"
210
+ name="password"
137
211
  :label="t(`authConfig.${AUTH_TYPE}.password`)"
138
212
  :mode="mode"
139
213
  required