From d0b224cae7caefae2752c1574fdacf425b4a533a Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Tue, 15 Nov 2022 16:21:43 +0100 Subject: [PATCH] Use `react-form-hook` v7 for user IDP modal (#3771) --- .../tabs/IdentityProviderLinksTab.ts | 3 +- apps/admin-ui/src/user/UserIdPModal.tsx | 110 +++++++----------- .../src/user/UserIdentityProviderLinks.tsx | 46 ++++---- apps/admin-ui/src/user/UsersTabs.tsx | 46 ++++---- 4 files changed, 89 insertions(+), 116 deletions(-) diff --git a/apps/admin-ui/cypress/support/pages/admin_console/manage/users/user_details/tabs/IdentityProviderLinksTab.ts b/apps/admin-ui/cypress/support/pages/admin_console/manage/users/user_details/tabs/IdentityProviderLinksTab.ts index 6c5a0a3f3f..03b3e46a48 100644 --- a/apps/admin-ui/cypress/support/pages/admin_console/manage/users/user_details/tabs/IdentityProviderLinksTab.ts +++ b/apps/admin-ui/cypress/support/pages/admin_console/manage/users/user_details/tabs/IdentityProviderLinksTab.ts @@ -11,7 +11,6 @@ export default class IdentityProviderLinksTab { private linkAccountModalIdentityProviderInput = "idpNameInput"; private linkAccountModalUserIdInput = "userIdInput"; private linkAccountModalUsernameInput = "usernameInput"; - private linkAccountModalLinkBtn = "Link"; public clickLinkAccount(idpName: string) { cy.get(this.availableProvidersSection + " tr") @@ -47,7 +46,7 @@ export default class IdentityProviderLinksTab { } public clickLinkAccountModalLinkBtn() { - cy.findByTestId(this.linkAccountModalLinkBtn).click(); + modalUtils.confirmModal(); cy.intercept("/admin/realms/master").as("load"); cy.wait(["@load"]); return this; diff --git a/apps/admin-ui/src/user/UserIdPModal.tsx b/apps/admin-ui/src/user/UserIdPModal.tsx index 59d7801090..35da460711 100644 --- a/apps/admin-ui/src/user/UserIdPModal.tsx +++ b/apps/admin-ui/src/user/UserIdPModal.tsx @@ -1,3 +1,4 @@ +import type FederatedIdentityRepresentation from "@keycloak/keycloak-admin-client/lib/defs/federatedIdentityRepresentation"; import { AlertVariant, Button, @@ -8,28 +9,26 @@ import { ModalVariant, ValidatedOptions, } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { useForm } from "react-hook-form"; - -import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; -import { useAdminClient } from "../context/auth/AdminClient"; -import { useAlerts } from "../components/alert/Alerts"; import { capitalize } from "lodash-es"; -import { useParams } from "react-router-dom"; -import type FederatedIdentityRepresentation from "@keycloak/keycloak-admin-client/lib/defs/federatedIdentityRepresentation"; -import type { UserParams } from "./routes/User"; +import { useForm } from "react-hook-form-v7"; +import { useTranslation } from "react-i18next"; + +import { useAlerts } from "../components/alert/Alerts"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; +import { useAdminClient } from "../context/auth/AdminClient"; type UserIdpModalProps = { - federatedId?: string; - handleModalToggle: () => void; - refresh: (group?: GroupRepresentation) => void; + userId: string; + federatedId: string; + onClose: () => void; + onRefresh: () => void; }; export const UserIdpModal = ({ + userId, federatedId, - handleModalToggle, - refresh, + onClose, + onRefresh, }: UserIdpModalProps) => { const { t } = useTranslation("users"); const { adminClient } = useAdminClient(); @@ -38,22 +37,22 @@ export const UserIdpModal = ({ register, handleSubmit, formState: { isValid, errors }, - } = useForm({ + } = useForm({ mode: "onChange", }); - const { id } = useParams(); - - const submitForm = async (fedIdentity: FederatedIdentityRepresentation) => { + const onSubmit = async ( + federatedIdentity: FederatedIdentityRepresentation + ) => { try { await adminClient.users.addToFederatedIdentity({ - id: id!, - federatedIdentityId: federatedId!, - federatedIdentity: fedIdentity, + id: userId, + federatedIdentityId: federatedId, + federatedIdentity, }); addAlert(t("users:idpLinkSuccess"), AlertVariant.success); - handleModalToggle(); - refresh(); + onClose(); + onRefresh(); } catch (error) { addError("users:couldNotLinkIdP", error); } @@ -65,12 +64,11 @@ export const UserIdpModal = ({ title={t("users:linkAccountTitle", { provider: capitalize(federatedId), })} - isOpen={true} - onClose={handleModalToggle} + onClose={onClose} actions={[ , ]} + isOpen > -
+
diff --git a/apps/admin-ui/src/user/UserIdentityProviderLinks.tsx b/apps/admin-ui/src/user/UserIdentityProviderLinks.tsx index bc135da911..72d0c31ded 100644 --- a/apps/admin-ui/src/user/UserIdentityProviderLinks.tsx +++ b/apps/admin-ui/src/user/UserIdentityProviderLinks.tsx @@ -1,5 +1,5 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; +import type FederatedIdentityRepresentation from "@keycloak/keycloak-admin-client/lib/defs/federatedIdentityRepresentation"; +import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation"; import { AlertVariant, Button, @@ -9,40 +9,41 @@ import { Text, TextContent, } from "@patternfly/react-core"; +import { cellWidth } from "@patternfly/react-table"; +import { capitalize } from "lodash-es"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom-v5-compat"; + +import { useAlerts } from "../components/alert/Alerts"; +import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { FormPanel } from "../components/scroll-form/FormPanel"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; -import { cellWidth } from "@patternfly/react-table"; -import { useParams } from "react-router-dom"; -import { Link } from "react-router-dom-v5-compat"; import { useAdminClient } from "../context/auth/AdminClient"; -import { emptyFormatter, upperCaseFormatter } from "../util"; -import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation"; -import type FederatedIdentityRepresentation from "@keycloak/keycloak-admin-client/lib/defs/federatedIdentityRepresentation"; import { useRealm } from "../context/realm-context/RealmContext"; import { useServerInfo } from "../context/server-info/ServerInfoProvider"; -import { capitalize } from "lodash-es"; -import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; -import { useAlerts } from "../components/alert/Alerts"; -import { UserIdpModal } from "./UserIdPModal"; import { toIdentityProvider } from "../identity-providers/routes/IdentityProvider"; +import { emptyFormatter, upperCaseFormatter } from "../util"; +import { UserIdpModal } from "./UserIdPModal"; -export const UserIdentityProviderLinks = () => { +type UserIdentityProviderLinksProps = { + userId: string; +}; + +export const UserIdentityProviderLinks = ({ + userId, +}: UserIdentityProviderLinksProps) => { const [key, setKey] = useState(0); const [federatedId, setFederatedId] = useState(""); const [isLinkIdPModalOpen, setIsLinkIdPModalOpen] = useState(false); const { adminClient } = useAdminClient(); - const { id } = useParams<{ id: string }>(); const { realm } = useRealm(); const { addAlert, addError } = useAlerts(); const { t } = useTranslation("users"); const refresh = () => setKey(new Date().getTime()); - const handleModalToggle = () => { - setIsLinkIdPModalOpen(!isLinkIdPModalOpen); - }; - type WithProviderId = FederatedIdentityRepresentation & { providerId: string; }; @@ -53,7 +54,7 @@ export const UserIdentityProviderLinks = () => { const allProviders = await adminClient.identityProviders.find(); const allFedIds = (await adminClient.users.listFederatedIdentities({ - id, + id: userId, })) as WithProviderId[]; for (const element of allFedIds) { element.providerId = allProviders.find( @@ -94,7 +95,7 @@ export const UserIdentityProviderLinks = () => { onConfirm: async () => { try { await adminClient.users.delFromFederatedIdentity({ - id, + id: userId, federatedIdentityId: federatedId, }); addAlert(t("users:idpUnlinkSuccess"), AlertVariant.success); @@ -180,9 +181,10 @@ export const UserIdentityProviderLinks = () => { <> {isLinkIdPModalOpen && ( setIsLinkIdPModalOpen(false)} + onRefresh={refresh} /> )} diff --git a/apps/admin-ui/src/user/UsersTabs.tsx b/apps/admin-ui/src/user/UsersTabs.tsx index 7c35a110d6..90694a1fc7 100644 --- a/apps/admin-ui/src/user/UsersTabs.tsx +++ b/apps/admin-ui/src/user/UsersTabs.tsx @@ -1,4 +1,5 @@ -import { useState } from "react"; +import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; +import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; import { AlertVariant, ButtonVariant, @@ -7,31 +8,30 @@ import { Tab, TabTitleText, } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; +import { useState } from "react"; import { Controller, FormProvider, useForm } from "react-hook-form"; - -import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; -import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; -import { ViewHeader } from "../components/view-header/ViewHeader"; -import { BruteForced, UserForm } from "./UserForm"; -import { useAlerts } from "../components/alert/Alerts"; -import { useAdminClient, useFetch } from "../context/auth/AdminClient"; +import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; import { useNavigate } from "react-router-dom-v5-compat"; -import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs"; -import { UserGroups } from "./UserGroups"; -import { UserConsents } from "./UserConsents"; -import { useRealm } from "../context/realm-context/RealmContext"; -import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks"; + +import { useAlerts } from "../components/alert/Alerts"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; -import { toUser } from "./routes/User"; -import { toUsers } from "./routes/Users"; -import { UserRoleMapping } from "./UserRoleMapping"; -import { UserAttributes } from "./UserAttributes"; -import { UserCredentials } from "./UserCredentials"; -import { UserSessions } from "./UserSessions"; -import { useAccess } from "../context/access/Access"; import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner"; +import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs"; +import { ViewHeader } from "../components/view-header/ViewHeader"; +import { useAccess } from "../context/access/Access"; +import { useAdminClient, useFetch } from "../context/auth/AdminClient"; +import { useRealm } from "../context/realm-context/RealmContext"; +import { toUser, UserParams } from "./routes/User"; +import { toUsers } from "./routes/Users"; +import { UserAttributes } from "./UserAttributes"; +import { UserConsents } from "./UserConsents"; +import { UserCredentials } from "./UserCredentials"; +import { BruteForced, UserForm } from "./UserForm"; +import { UserGroups } from "./UserGroups"; +import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks"; +import { UserRoleMapping } from "./UserRoleMapping"; +import { UserSessions } from "./UserSessions"; const UsersTabs = () => { const { t } = useTranslation("users"); @@ -42,7 +42,7 @@ const UsersTabs = () => { const { adminClient } = useAdminClient(); const userForm = useForm({ mode: "onChange" }); - const { id } = useParams<{ id: string }>(); + const { id } = useParams(); const [user, setUser] = useState(); const [bruteForced, setBruteForced] = useState(); const [addedGroups, setAddedGroups] = useState([]); @@ -247,7 +247,7 @@ const UsersTabs = () => { {t("identityProviderLinks")} } > - + )}