@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.5

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 (315) hide show
  1. package/assets/styles/global/_button.scss +1 -1
  2. package/assets/styles/global/_layout.scss +4 -0
  3. package/assets/translations/en-us.yaml +183 -51
  4. package/assets/translations/zh-hans.yaml +1 -7
  5. package/chart/monitoring/ClusterSelector.vue +0 -21
  6. package/chart/monitoring/prometheus/index.vue +6 -3
  7. package/components/ActionDropdownShell.vue +5 -3
  8. package/components/ButtonGroup.vue +26 -1
  9. package/components/CruResource.vue +212 -16
  10. package/components/ExplorerMembers.vue +8 -4
  11. package/components/ExplorerProjectsNamespaces.vue +10 -6
  12. package/components/GrowlManager.vue +4 -0
  13. package/components/MgmtNodeList.vue +184 -0
  14. package/components/PromptRestore.vue +93 -32
  15. package/components/Questions/index.vue +1 -0
  16. package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
  17. package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
  18. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
  19. package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
  20. package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
  21. package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
  22. package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
  23. package/components/ResourceDetail/index.vue +1 -1
  24. package/components/ResourceList/Masthead.vue +7 -1
  25. package/components/ResourceList/index.vue +82 -1
  26. package/components/ResourceTable.vue +1 -0
  27. package/components/RichTranslation.vue +5 -2
  28. package/components/Setting.vue +1 -0
  29. package/components/SortableTable/index.vue +4 -3
  30. package/components/SubtleLink.vue +31 -6
  31. package/components/Tabbed/Tab.vue +29 -3
  32. package/components/Tabbed/index.vue +25 -3
  33. package/components/TableOfContents/TableOfContents.vue +109 -0
  34. package/components/TableOfContents/composables.ts +258 -0
  35. package/components/Window/ContainerShell.vue +21 -11
  36. package/components/Window/__tests__/ContainerShell.test.ts +107 -37
  37. package/components/Wizard.vue +23 -5
  38. package/components/__tests__/ButtonGroup.test.ts +56 -0
  39. package/components/__tests__/PromptRestore.test.ts +169 -19
  40. package/components/fleet/AppCoChartGrid.vue +401 -0
  41. package/components/fleet/AppCoEmptyState.vue +127 -0
  42. package/components/fleet/AppCoPageHeader.vue +119 -0
  43. package/components/fleet/AppCoVersionSelect.vue +70 -0
  44. package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
  45. package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
  46. package/components/fleet/FleetClusterTargets/index.vue +189 -146
  47. package/components/fleet/FleetIntro.vue +7 -3
  48. package/components/fleet/FleetNoWorkspaces.vue +7 -3
  49. package/components/fleet/FleetSecretSelector.vue +5 -3
  50. package/components/fleet/FleetValuesFrom.vue +8 -2
  51. package/components/fleet/GitRepoAdvancedTab.vue +1 -0
  52. package/components/fleet/GitRepoMetadataTab.vue +5 -0
  53. package/components/fleet/GitRepoTargetTab.vue +0 -2
  54. package/components/fleet/HelmOpAdvancedTab.vue +19 -53
  55. package/components/fleet/HelmOpAppCoConfigTab.vue +597 -0
  56. package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
  57. package/components/fleet/HelmOpMetadataTab.vue +5 -0
  58. package/components/fleet/HelmOpResourcesSection.vue +82 -0
  59. package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
  60. package/components/fleet/HelmOpTargetTab.vue +64 -60
  61. package/components/fleet/HelmOpValuesTab.vue +129 -105
  62. package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
  63. package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
  64. package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
  65. package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
  66. package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
  67. package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
  68. package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
  69. package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
  70. package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
  71. package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
  72. package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
  73. package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
  74. package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
  75. package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
  76. package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
  77. package/components/fleet/dashboard/Empty.vue +8 -4
  78. package/components/fleet/dashboard/ResourceCard.vue +28 -0
  79. package/components/fleet/dashboard/ResourceDetails.vue +28 -0
  80. package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
  81. package/components/form/ArrayList.vue +61 -4
  82. package/components/form/FileSelector.vue +39 -1
  83. package/components/form/KeyValue.vue +23 -2
  84. package/components/form/LabeledSelect.vue +39 -1
  85. package/components/form/Labels.vue +22 -3
  86. package/components/form/NameNsDescription.vue +13 -5
  87. package/components/form/PrivateRegistry.constants.ts +7 -0
  88. package/components/form/PrivateRegistry.vue +253 -18
  89. package/components/form/ResourceTabs/index.vue +1 -0
  90. package/components/form/SelectOrCreateAuthSecret.vue +140 -17
  91. package/components/form/__tests__/FileSelector.test.ts +23 -0
  92. package/components/form/__tests__/NameNsDescription.test.ts +75 -0
  93. package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
  94. package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
  95. package/components/formatter/EtcdSnapshotName.vue +73 -0
  96. package/components/formatter/InternalExternalIP.vue +10 -4
  97. package/components/formatter/ServiceTargets.vue +26 -7
  98. package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
  99. package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
  100. package/components/nav/Header.vue +12 -1
  101. package/components/nav/TopLevelMenu.vue +7 -2
  102. package/components/nav/__tests__/Header.test.ts +15 -0
  103. package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
  104. package/components/templates/default.vue +16 -4
  105. package/components/templates/home.vue +9 -4
  106. package/components/templates/plain.vue +9 -4
  107. package/composables/useHelmOpResources.test.ts +56 -0
  108. package/composables/useHelmOpResources.ts +32 -0
  109. package/composables/useStateColor.test.ts +325 -0
  110. package/composables/useStateColor.ts +128 -0
  111. package/config/features.js +1 -0
  112. package/config/home-links.js +1 -1
  113. package/config/labels-annotations.js +3 -0
  114. package/config/product/explorer.js +17 -4
  115. package/config/product/manager.js +8 -0
  116. package/config/router/index.js +16 -0
  117. package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
  118. package/config/router/navigation-guards/authentication.js +10 -4
  119. package/config/router/routes.js +20 -6
  120. package/config/secret.ts +10 -0
  121. package/config/settings.ts +6 -4
  122. package/config/table-headers.js +3 -4
  123. package/config/types.js +16 -0
  124. package/core/plugin-products-base.ts +3 -3
  125. package/core/plugin-types.ts +83 -30
  126. package/core/plugin.ts +3 -0
  127. package/core/types-provisioning.ts +34 -1
  128. package/core/types.ts +15 -2
  129. package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
  130. package/detail/__tests__/workload.test.ts +3 -152
  131. package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
  132. package/detail/provisioning.cattle.io.cluster.vue +109 -7
  133. package/detail/workload/index.vue +12 -55
  134. package/dialog/RotateEncryptionKeyDialog.vue +33 -9
  135. package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
  136. package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
  137. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
  138. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +206 -0
  139. package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
  140. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
  141. package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
  142. package/edit/auth/__tests__/azuread.test.ts +34 -9
  143. package/edit/auth/__tests__/github.test.ts +234 -0
  144. package/edit/auth/__tests__/oidc.test.ts +26 -6
  145. package/edit/auth/__tests__/saml.test.ts +196 -0
  146. package/edit/auth/azuread.vue +128 -95
  147. package/edit/auth/github.vue +72 -13
  148. package/edit/auth/ldap/__tests__/index.test.ts +206 -0
  149. package/edit/auth/ldap/config.vue +8 -0
  150. package/edit/auth/ldap/index.vue +75 -1
  151. package/edit/auth/oidc.vue +119 -73
  152. package/edit/auth/saml.vue +76 -12
  153. package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
  154. package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
  155. package/edit/fleet.cattle.io.gitrepo.vue +70 -16
  156. package/edit/fleet.cattle.io.helmop.vue +542 -141
  157. package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
  158. package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
  159. package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
  160. package/edit/management.cattle.io.user.vue +5 -2
  161. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
  162. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
  163. package/edit/provisioning.cattle.io.cluster/rke2.vue +89 -11
  164. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
  165. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
  166. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
  167. package/list/group.principal.vue +5 -4
  168. package/list/harvesterhci.io.management.cluster.vue +8 -9
  169. package/list/management.cattle.io.user.vue +12 -9
  170. package/list/provisioning.cattle.io.cluster.vue +16 -10
  171. package/mixins/__tests__/auth-config.test.ts +90 -0
  172. package/mixins/__tests__/chart.test.ts +94 -0
  173. package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
  174. package/mixins/auth-config.js +7 -0
  175. package/mixins/chart.js +11 -2
  176. package/mixins/child-hook.js +12 -6
  177. package/mixins/create-edit-view/impl.js +5 -3
  178. package/mixins/resource-fetch-api-pagination.js +21 -1
  179. package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
  180. package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
  181. package/models/__tests__/fleet-application.test.ts +175 -0
  182. package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
  183. package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
  184. package/models/__tests__/management.cattle.io.node.ts +22 -0
  185. package/models/__tests__/namespace.test.ts +36 -0
  186. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +205 -0
  187. package/models/__tests__/secret.test.ts +68 -1
  188. package/models/__tests__/workload.test.ts +401 -26
  189. package/models/catalog.cattle.io.clusterrepo.js +28 -4
  190. package/models/compliance.cattle.io.clusterscan.js +39 -4
  191. package/models/fleet-application.js +4 -0
  192. package/models/fleet.cattle.io.helmop.js +20 -1
  193. package/models/management.cattle.io.cluster.js +39 -5
  194. package/models/management.cattle.io.node.js +44 -3
  195. package/models/namespace.js +1 -1
  196. package/models/pod.js +46 -3
  197. package/models/provisioning.cattle.io.cluster.js +64 -14
  198. package/models/rke.cattle.io.etcdsnapshot.js +17 -9
  199. package/models/secret.js +19 -0
  200. package/models/workload.js +120 -20
  201. package/models/workload.service.js +5 -0
  202. package/package.json +14 -13
  203. package/pages/about.vue +5 -6
  204. package/pages/auth/login.vue +0 -35
  205. package/pages/auth/setup.vue +11 -0
  206. package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
  207. package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
  208. package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
  209. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
  210. package/pages/c/_cluster/apps/charts/chart.vue +2 -1
  211. package/pages/c/_cluster/apps/charts/index.vue +48 -10
  212. package/pages/c/_cluster/apps/charts/install.vue +236 -144
  213. package/pages/c/_cluster/auth/roles/index.vue +5 -4
  214. package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
  215. package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
  216. package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
  217. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
  218. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
  219. package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
  220. package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
  221. package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
  222. package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
  223. package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
  224. package/pages/c/_cluster/fleet/application/create.vue +187 -136
  225. package/pages/c/_cluster/fleet/application/index.vue +5 -3
  226. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
  227. package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
  228. package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
  229. package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
  230. package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
  231. package/pages/c/_cluster/fleet/index.vue +2 -2
  232. package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
  233. package/pages/c/_cluster/uiplugins/index.vue +15 -0
  234. package/pages/fail-whale.vue +16 -11
  235. package/pages/home.vue +16 -46
  236. package/pkg/require-asset.lib.js +25 -0
  237. package/pkg/vue.config.js +7 -0
  238. package/plugins/clean-html.d.ts +9 -0
  239. package/plugins/dashboard-store/__tests__/resource-class.test.ts +177 -0
  240. package/plugins/dashboard-store/getters.js +0 -1
  241. package/plugins/dashboard-store/resource-class.js +114 -19
  242. package/plugins/steve/__tests__/actions.test.ts +212 -0
  243. package/plugins/steve/actions.js +96 -0
  244. package/plugins/steve/steve-pagination-utils.ts +1 -1
  245. package/rancher-components/Accordion/Accordion.vue +53 -9
  246. package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
  247. package/rancher-components/Form/Radio/RadioButton.vue +17 -1
  248. package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
  249. package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
  250. package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
  251. package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
  252. package/rancher-components/RcButton/RcButton.test.ts +103 -0
  253. package/rancher-components/RcButton/RcButton.vue +94 -15
  254. package/rancher-components/RcButton/index.ts +1 -1
  255. package/rancher-components/RcButton/types.ts +3 -0
  256. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
  257. package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
  258. package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
  259. package/rancher-components/RcSection/RcSection.vue +28 -3
  260. package/scripts/extension/helm/package/Dockerfile +1 -1
  261. package/scripts/test-plugins-build.sh +2 -1
  262. package/store/__tests__/features.test.ts +131 -0
  263. package/store/__tests__/growl.test.ts +374 -0
  264. package/store/__tests__/modal.test.ts +131 -0
  265. package/store/__tests__/notifications.test.ts +434 -0
  266. package/store/__tests__/slideInPanel.test.ts +88 -0
  267. package/store/__tests__/type-map.utils.test.ts +433 -0
  268. package/store/catalog.js +57 -0
  269. package/store/features.js +4 -0
  270. package/store/plugins.js +7 -4
  271. package/types/components/buttonGroup.ts +5 -0
  272. package/types/shell/index.d.ts +166 -70
  273. package/utils/__tests__/auth.test.ts +273 -0
  274. package/utils/__tests__/computed.test.ts +193 -0
  275. package/utils/__tests__/cspAdaptor.test.ts +163 -0
  276. package/utils/__tests__/dom.test.ts +81 -0
  277. package/utils/__tests__/duration.test.ts +37 -1
  278. package/utils/__tests__/dynamic-importer.test.ts +102 -0
  279. package/utils/__tests__/fleet-appco.test.ts +312 -0
  280. package/utils/__tests__/monitoring.test.ts +130 -0
  281. package/utils/__tests__/object.test.ts +22 -0
  282. package/utils/__tests__/operation-cr.test.ts +34 -0
  283. package/utils/__tests__/platform.test.ts +91 -0
  284. package/utils/__tests__/position.test.ts +237 -0
  285. package/utils/__tests__/provider.test.ts +51 -1
  286. package/utils/__tests__/queue.test.ts +232 -0
  287. package/utils/__tests__/release-notes.test.ts +221 -0
  288. package/utils/__tests__/router.test.js +254 -1
  289. package/utils/__tests__/select.test.ts +208 -0
  290. package/utils/__tests__/time.test.ts +265 -1
  291. package/utils/__tests__/title.test.ts +47 -0
  292. package/utils/__tests__/width.test.ts +53 -0
  293. package/utils/__tests__/window.test.ts +158 -0
  294. package/utils/__tests__/xccdf.test.ts +126 -6
  295. package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
  296. package/utils/crypto/__tests__/index.test.ts +144 -0
  297. package/utils/duration.ts +104 -0
  298. package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
  299. package/utils/dynamic-content/info.ts +2 -1
  300. package/utils/error.js +13 -0
  301. package/utils/fleet-appco.ts +323 -0
  302. package/utils/object.js +22 -2
  303. package/utils/operation-cr.js +19 -0
  304. package/utils/provider.ts +12 -0
  305. package/utils/require-asset.ts +7 -0
  306. package/utils/validators/__tests__/container-images.test.ts +104 -0
  307. package/utils/validators/__tests__/flow-output.test.ts +91 -0
  308. package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
  309. package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
  310. package/utils/validators/__tests__/private-registry.test.ts +27 -15
  311. package/utils/validators/private-registry.ts +15 -4
  312. package/utils/xccdf.ts +39 -42
  313. package/vue.config.js +1 -1
  314. package/pages/support/index.vue +0 -264
  315. package/utils/duration.js +0 -43
@@ -1,8 +1,9 @@
1
1
  <script>
2
+ import { ref, computed } from 'vue';
3
+ import { useStore } from 'vuex';
2
4
  import isEqual from 'lodash/isEqual';
3
5
  import Loading from '@shell/components/Loading';
4
6
  import CreateEditView from '@shell/mixins/create-edit-view';
5
- import FormValidation from '@shell/mixins/form-validation';
6
7
  import CruResource from '@shell/components/CruResource';
7
8
  import InfoBox from '@shell/components/InfoBox';
8
9
  import { RadioGroup } from '@components/Form/Radio';
@@ -16,6 +17,8 @@ import { AZURE_MIGRATED } from '@shell/config/labels-annotations';
16
17
  import { get } from '@shell/utils/object';
17
18
  import AuthProviderWarningBanners from '@shell/edit/auth/AuthProviderWarningBanners';
18
19
  import formRulesGenerator from '@shell/utils/validators/formRules/index';
20
+ import { useFormValidation } from '@shell/composables/useFormValidation';
21
+ import { useI18n } from '@shell/composables/useI18n';
19
22
 
20
23
  const TENANT_ID_TOKEN = '__[[TENANT_ID]]__';
21
24
 
@@ -68,7 +71,73 @@ export default {
68
71
  AuthProviderWarningBanners
69
72
  },
70
73
 
71
- mixins: [CreateEditView, AuthConfig, FormValidation],
74
+ mixins: [CreateEditView, AuthConfig],
75
+
76
+ setup() {
77
+ const store = useStore();
78
+ const { t } = useI18n(store);
79
+
80
+ const editMemberConfigRef = ref(false);
81
+ const isLogoutAllSupported = ref(false);
82
+ const sloTypeRef = ref(null);
83
+ const sloEndSessionEndpointUiEnabled = computed(() => (
84
+ sloTypeRef.value === SLO_OPTION_VALUES.all || sloTypeRef.value === SLO_OPTION_VALUES.both
85
+ ));
86
+
87
+ const urlRule = formRulesGenerator(t, {}).genericUrl;
88
+
89
+ const extraRules = {
90
+ applicationSecretRequired: (value) => {
91
+ if (!editMemberConfigRef.value && !value) {
92
+ return t('validation.required', { key: t('authConfig.azuread.applicationSecret.label') });
93
+ }
94
+
95
+ return undefined;
96
+ },
97
+ endSessionEndpointRequiredAndValid: (value) => {
98
+ if (!isLogoutAllSupported.value || !sloEndSessionEndpointUiEnabled.value) {
99
+ return undefined;
100
+ }
101
+ if (!value) {
102
+ return t('validation.required', { key: t('authConfig.azuread.endSessionEndpoint.title') });
103
+ }
104
+
105
+ return urlRule(value);
106
+ },
107
+ };
108
+
109
+ const { getRules, isFormValid } = useFormValidation(t, [
110
+ {
111
+ path: 'tenantId', rules: ['required'], translationKey: 'authConfig.azuread.tenantId.label'
112
+ },
113
+ {
114
+ path: 'applicationId', rules: ['required'], translationKey: 'authConfig.azuread.applicationId.label'
115
+ },
116
+ { path: 'applicationSecret', rules: ['applicationSecretRequired'] },
117
+ {
118
+ path: 'endpoint', rules: ['required', 'url'], translationKey: 'authConfig.azuread.endpoint.label'
119
+ },
120
+ {
121
+ path: 'graphEndpoint', rules: ['required', 'url'], translationKey: 'authConfig.azuread.graphEndpoint.label'
122
+ },
123
+ {
124
+ path: 'tokenEndpoint', rules: ['required', 'url'], translationKey: 'authConfig.azuread.tokenEndpoint.label'
125
+ },
126
+ {
127
+ path: 'authEndpoint', rules: ['required', 'url'], translationKey: 'authConfig.azuread.authEndpoint.label'
128
+ },
129
+ { path: 'endSessionEndpoint', rules: ['endSessionEndpointRequiredAndValid'] },
130
+ ], extraRules);
131
+
132
+ return {
133
+ getRules,
134
+ isFormValid,
135
+ editMemberConfigRef,
136
+ isLogoutAllSupported,
137
+ sloTypeRef,
138
+ sloEndSessionEndpointUiEnabled,
139
+ };
140
+ },
72
141
 
73
142
  async fetch() {
74
143
  await this.reloadModel();
@@ -89,39 +158,11 @@ export default {
89
158
 
90
159
  // Storing the applicationSecret is necessary because norman doesn't support returning secrets and when we
91
160
  // override the steve authconfig with a norman config the applicationSecret is lost
92
- applicationSecret: this.value.applicationSecret,
93
- fvFormRuleSets: [
94
- { path: 'tenantId', rules: ['tenantIdRequired'] },
95
- { path: 'applicationId', rules: ['applicationIdRequired'] },
96
- { path: 'applicationSecret', rules: ['applicationSecretRequired'] },
97
- { path: 'endpoint', rules: ['endpointRequired', 'endpointMustBeURL'] },
98
- { path: 'graphEndpoint', rules: ['graphEndpointRequired', 'graphEndpointMustBeURL'] },
99
- { path: 'tokenEndpoint', rules: ['tokenEndpointRequired', 'tokenEndpointMustBeURL'] },
100
- { path: 'authEndpoint', rules: ['authEndpointRequired', 'authEndpointMustBeURL'] },
101
- { path: 'endSessionEndpoint', rules: ['endSessionEndpointRequiredAndValid'] },
102
- ]
161
+ applicationSecret: this.value.applicationSecret
103
162
  };
104
163
  },
105
164
 
106
165
  computed: {
107
- // Cannot pass this.model as a rootObject because it is undefined at that point, so had to use a workaround
108
- fvExtraRules() {
109
- return {
110
- tenantIdRequired: this.modelFieldRequired('tenantId', 'authConfig.azuread.tenantId.label'),
111
- applicationIdRequired: this.modelFieldRequired('applicationId', 'authConfig.azuread.applicationId.label'),
112
- applicationSecretRequired: this.applicationSecretRequired(),
113
- endpointRequired: this.modelFieldRequired('endpoint', 'authConfig.azuread.endpoint.label'),
114
- endpointMustBeURL: this.modelFieldURL('endpoint'),
115
- graphEndpointRequired: this.modelFieldRequired('graphEndpoint', 'authConfig.azuread.graphEndpoint.label'),
116
- graphEndpointMustBeURL: this.modelFieldURL('graphEndpoint'),
117
- tokenEndpointRequired: this.modelFieldRequired('tokenEndpoint', 'authConfig.azuread.tokenEndpoint.label'),
118
- tokenEndpointMustBeURL: this.modelFieldURL('tokenEndpoint'),
119
- authEndpointRequired: this.modelFieldRequired('authEndpoint', 'authConfig.azuread.authEndpoint.label'),
120
- authEndpointMustBeURL: this.modelFieldURL('authEndpoint'),
121
- endSessionEndpointRequiredAndValid: this.endSessionEndpointRule(),
122
- };
123
- },
124
-
125
166
  tArgs() {
126
167
  return {
127
168
  baseUrl: this.baseUrl,
@@ -172,14 +213,14 @@ export default {
172
213
  return this.model.enabled && !this.isEnabling && !this.editConfig;
173
214
  },
174
215
 
175
- isLogoutAllSupported() {
176
- return this.model?.logoutAllSupported;
216
+ displayName() {
217
+ return this.t('model.authConfig.name.azuread');
177
218
  },
178
219
 
179
220
  sloOptions() {
180
221
  return [
181
- { value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.slo.sloOptions.onlyRancher', { name: this.model?.nameDisplay }) },
182
- { value: SLO_OPTION_VALUES.all, label: this.t('authConfig.slo.sloOptions.logoutAll', { name: this.model?.nameDisplay }) },
222
+ { value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.slo.sloOptions.onlyRancher', { name: this.displayName }) },
223
+ { value: SLO_OPTION_VALUES.all, label: this.t('authConfig.slo.sloOptions.logoutAll', { name: this.displayName }) },
183
224
  { value: SLO_OPTION_VALUES.both, label: this.t('authConfig.slo.sloOptions.choose') },
184
225
  ];
185
226
  },
@@ -190,12 +231,23 @@ export default {
190
231
  return sloOptionSelected?.label || '';
191
232
  },
192
233
 
193
- sloEndSessionEndpointUiEnabled() {
194
- return this.sloType === SLO_OPTION_VALUES.all || this.sloType === SLO_OPTION_VALUES.both;
195
- },
196
234
  },
197
235
 
198
236
  watch: {
237
+ editMemberConfig: {
238
+ handler(val) {
239
+ this.editMemberConfigRef = val;
240
+ },
241
+ immediate: true,
242
+ },
243
+
244
+ 'model.logoutAllSupported': {
245
+ handler(val) {
246
+ this.isLogoutAllSupported = !!val;
247
+ },
248
+ immediate: true,
249
+ },
250
+
199
251
  endpoint(value) {
200
252
  this.setEndpoints(value);
201
253
  },
@@ -207,22 +259,26 @@ export default {
207
259
  },
208
260
 
209
261
  // sloType is defined on shell/mixins/auth-config.js
210
- sloType(neu) {
211
- switch (neu) {
212
- case SLO_OPTION_VALUES.rancher:
213
- this.model.logoutAllEnabled = false;
214
- this.model.logoutAllForced = false;
215
- this.model.endSessionEndpoint = '';
216
- break;
217
- case SLO_OPTION_VALUES.all:
218
- this.model.logoutAllEnabled = true;
219
- this.model.logoutAllForced = true;
220
- break;
221
- case SLO_OPTION_VALUES.both:
222
- this.model.logoutAllEnabled = true;
223
- this.model.logoutAllForced = false;
224
- break;
225
- }
262
+ sloType: {
263
+ handler(neu) {
264
+ this.sloTypeRef = neu;
265
+ switch (neu) {
266
+ case SLO_OPTION_VALUES.rancher:
267
+ this.model.logoutAllEnabled = false;
268
+ this.model.logoutAllForced = false;
269
+ this.model.endSessionEndpoint = '';
270
+ break;
271
+ case SLO_OPTION_VALUES.all:
272
+ this.model.logoutAllEnabled = true;
273
+ this.model.logoutAllForced = true;
274
+ break;
275
+ case SLO_OPTION_VALUES.both:
276
+ this.model.logoutAllEnabled = true;
277
+ this.model.logoutAllForced = false;
278
+ break;
279
+ }
280
+ },
281
+ immediate: true,
226
282
  },
227
283
 
228
284
  model: {
@@ -324,37 +380,6 @@ export default {
324
380
  });
325
381
  }
326
382
  },
327
- modelFieldRequired(path, label) {
328
- return () => {
329
- return !this.model[path] ? `${ this.t('validation.required', { key: this.t(label) }) }` : undefined;
330
- };
331
- },
332
- applicationSecretRequired() {
333
- return () => {
334
- return !this.editMemberConfig && !this.model.applicationSecret ? `${ this.t('validation.required', { key: this.t('authConfig.azuread.applicationSecret.label') }) }` : undefined;
335
- };
336
- },
337
- modelFieldURL(path) {
338
- return () => {
339
- const rule = formRulesGenerator(this.$store.getters['i18n/t'], {}).url;
340
-
341
- return rule(this.model[path]);
342
- };
343
- },
344
-
345
- endSessionEndpointRule() {
346
- return () => {
347
- if (!this.isLogoutAllSupported || !this.sloEndSessionEndpointUiEnabled) {
348
- return undefined;
349
- }
350
- if (!this.model.endSessionEndpoint) {
351
- return this.t('validation.required', { key: this.t('authConfig.azuread.endSessionEndpoint.title') });
352
- }
353
- const rule = formRulesGenerator(this.$store.getters['i18n/t'], {}).url;
354
-
355
- return rule(this.model.endSessionEndpoint);
356
- };
357
- },
358
383
  }
359
384
  };
360
385
  </script>
@@ -367,7 +392,7 @@ export default {
367
392
  :mode="mode"
368
393
  :resource="model"
369
394
  :subtypes="[]"
370
- :validation-passed="fvFormIsValid"
395
+ :validation-passed="isFormValid"
371
396
  :finish-button-mode="model && model.enabled ? 'edit' : 'enable'"
372
397
  :can-yaml="false"
373
398
  :errors="errors"
@@ -466,10 +491,11 @@ export default {
466
491
  <LabeledInput
467
492
  id="tenant-id"
468
493
  v-model:value="model.tenantId"
494
+ name="tenantId"
469
495
  :label="t('authConfig.azuread.tenantId.label')"
470
496
  :mode="mode"
471
497
  :required="true"
472
- :rules="fvGetAndReportPathRules('tenantId')"
498
+ :rules="getRules('tenantId')"
473
499
  :tooltip="t('authConfig.azuread.tenantId.tooltip')"
474
500
  :placeholder="t('authConfig.azuread.tenantId.placeholder')"
475
501
  data-testid="input-azureAD-tenantId"
@@ -481,10 +507,11 @@ export default {
481
507
  <LabeledInput
482
508
  id="application-id"
483
509
  v-model:value="model.applicationId"
510
+ name="applicationId"
484
511
  :label="t('authConfig.azuread.applicationId.label')"
485
512
  :mode="mode"
486
513
  :required="true"
487
- :rules="fvGetAndReportPathRules('applicationId')"
514
+ :rules="getRules('applicationId')"
488
515
  :placeholder="t('authConfig.azuread.applicationId.placeholder')"
489
516
  data-testid="input-azureAD-applcationId"
490
517
  />
@@ -493,10 +520,11 @@ export default {
493
520
  <LabeledInput
494
521
  id="application-secret"
495
522
  v-model:value="model.applicationSecret"
523
+ name="applicationSecret"
496
524
  type="password"
497
525
  :label="t('authConfig.azuread.applicationSecret.label')"
498
526
  :required="true"
499
- :rules="fvGetAndReportPathRules('applicationSecret')"
527
+ :rules="getRules('applicationSecret')"
500
528
  :mode="mode"
501
529
  data-testid="input-azureAD-applicationSecret"
502
530
  />
@@ -548,19 +576,21 @@ export default {
548
576
  <div class="col span-6">
549
577
  <LabeledInput
550
578
  v-model:value="model.endpoint"
579
+ name="endpoint"
551
580
  :label="t('authConfig.azuread.endpoint.label')"
552
581
  :mode="mode"
553
582
  :required="true"
554
- :rules="fvGetAndReportPathRules('endpoint')"
583
+ :rules="getRules('endpoint')"
555
584
  data-testid="input-azureAD-endpoint"
556
585
  />
557
586
  </div>
558
587
  <div class="col span-6">
559
588
  <LabeledInput
560
589
  v-model:value="model.graphEndpoint"
590
+ name="graphEndpoint"
561
591
  :label="t('authConfig.azuread.graphEndpoint.label')"
562
592
  :required="true"
563
- :rules="fvGetAndReportPathRules('graphEndpoint')"
593
+ :rules="getRules('graphEndpoint')"
564
594
  :mode="mode"
565
595
  data-testid="input-azureAD-graphEndpoint"
566
596
  />
@@ -570,19 +600,21 @@ export default {
570
600
  <div class="col span-6">
571
601
  <LabeledInput
572
602
  v-model:value="model.tokenEndpoint"
603
+ name="tokenEndpoint"
573
604
  :label="t('authConfig.azuread.tokenEndpoint.label')"
574
605
  :mode="mode"
575
606
  :required="true"
576
- :rules="fvGetAndReportPathRules('tokenEndpoint')"
607
+ :rules="getRules('tokenEndpoint')"
577
608
  data-testid="input-azureAD-tokenEndpoint"
578
609
  />
579
610
  </div>
580
611
  <div class="col span-6">
581
612
  <LabeledInput
582
613
  v-model:value="model.authEndpoint"
614
+ name="authEndpoint"
583
615
  :label="t('authConfig.azuread.authEndpoint.label')"
584
616
  :required="true"
585
- :rules="fvGetAndReportPathRules('authEndpoint')"
617
+ :rules="getRules('authEndpoint')"
586
618
  :mode="mode"
587
619
  data-testid="input-azureAD-authEndpoint"
588
620
  />
@@ -619,10 +651,11 @@ export default {
619
651
  <div class="col span-6">
620
652
  <LabeledInput
621
653
  v-model:value="model.endSessionEndpoint"
622
- :tooltip="t('authConfig.azuread.endSessionEndpoint.tooltip', { tenantId: `${ tenantId || 'tenant-id' }` }, true)"
654
+ name="endSessionEndpoint"
655
+ :tooltip="t('authConfig.azuread.endSessionEndpoint.tooltip', { name: displayName, tenantId: `${ tenantId || 'tenant-id' }` }, true)"
623
656
  :label="t('authConfig.azuread.endSessionEndpoint.title')"
624
657
  :mode="mode"
625
- :rules="fvGetAndReportPathRules('endSessionEndpoint')"
658
+ :rules="getRules('endSessionEndpoint')"
626
659
  :required="true"
627
660
  data-testid="azuread-endSessionEndpoint"
628
661
  />
@@ -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"