diff --git a/cypress/integration/realm_settings_test.spec.ts b/cypress/integration/realm_settings_test.spec.ts index 6437a0cbfa..11b3a1fb43 100644 --- a/cypress/integration/realm_settings_test.spec.ts +++ b/cypress/integration/realm_settings_test.spec.ts @@ -126,6 +126,15 @@ describe("Realm settings tests", () => { realmSettingsPage.toggleSwitch(realmSettingsPage.rememberMeSwitch); }); + it("Check login tab values", () => { + sidebarPage.goToRealmSettings(); + cy.findByTestId("rs-login-tab").click(); + + cy.get("#kc-user-reg-switch-off").should("be.visible"); + cy.get("#kc-forgot-pw-switch-off").should("be.visible"); + cy.get("#kc-remember-me-switch-off").should("not.be.visible"); + }); + it("Go to email tab", () => { sidebarPage.goToRealmSettings(); cy.findByTestId("rs-email-tab").click(); diff --git a/src/realm-settings/LoginTab.tsx b/src/realm-settings/LoginTab.tsx index 12cc78cc5c..3be9d5436c 100644 --- a/src/realm-settings/LoginTab.tsx +++ b/src/realm-settings/LoginTab.tsx @@ -5,18 +5,33 @@ import { FormAccess } from "../components/form-access/FormAccess"; import { HelpItem } from "../components/help-enabler/HelpItem"; import { FormPanel } from "../components/scroll-form/FormPanel"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; +import { Controller, useForm } from "react-hook-form"; type RealmSettingsLoginTabProps = { save: (realm: RealmRepresentation) => void; realm: RealmRepresentation; + refresh: () => void; }; export const RealmSettingsLoginTab = ({ save, realm, + refresh, }: RealmSettingsLoginTabProps) => { const { t } = useTranslation("realm-settings"); + const form = useForm({ mode: "onChange" }); + + const updateSwitchValue = ( + onChange: (newValue: boolean) => void, + value: boolean, + name: string + ) => { + save({ ...realm, [name as keyof typeof realm]: value }); + onChange(value); + refresh(); + }; + return ( @@ -35,16 +50,23 @@ export const RealmSettingsLoginTab = ({ } hasNoPaddingTop > - { - save({ ...realm, registrationAllowed: value }); - }} + defaultValue={realm.registrationAllowed} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue(onChange, value, "registrationAllowed"); + }} + /> + )} /> - { - save({ ...realm, resetPasswordAllowed: value }); - }} + defaultValue={realm.resetPasswordAllowed} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue(onChange, value, "resetPasswordAllowed"); + }} + /> + )} /> - { - save({ ...realm, rememberMe: value }); - }} + defaultValue={realm.rememberMe} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue(onChange, value, "rememberMe"); + }} + /> + )} /> @@ -111,16 +147,27 @@ export const RealmSettingsLoginTab = ({ } hasNoPaddingTop > - { - save({ ...realm, registrationEmailAsUsername: value }); - }} + defaultValue={realm.registrationEmailAsUsername} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue( + onChange, + value, + "registrationEmailAsUsername" + ); + }} + /> + )} /> - { - save({ ...realm, loginWithEmailAllowed: value }); - }} + defaultValue={realm.loginWithEmailAllowed} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue(onChange, value, "loginWithEmailAllowed"); + }} + /> + )} /> - { - save({ ...realm, duplicateEmailsAllowed: value }); - }} - isDisabled={ - realm?.loginWithEmailAllowed || - realm?.registrationEmailAsUsername - } + defaultValue={realm.duplicateEmailsAllowed} + control={form.control} + render={({ onChange }) => ( + { + updateSwitchValue( + onChange, + value, + "duplicateEmailsAllowed" + ); + }} + isDisabled={ + form.getValues().loginWithEmailAllowed || + form.getValues().registrationEmailAsUsername + } + /> + )} /> - { - save({ ...realm, verifyEmail: value }); - }} + defaultValue={realm.verifyEmail} + control={form.control} + render={({ onChange, value }) => ( + { + updateSwitchValue(onChange, value, "verifyEmail"); + }} + /> + )} /> diff --git a/src/realm-settings/RealmSettingsSection.tsx b/src/realm-settings/RealmSettingsSection.tsx index 722060e9f4..0ab9c4d9c6 100644 --- a/src/realm-settings/RealmSettingsSection.tsx +++ b/src/realm-settings/RealmSettingsSection.tsx @@ -2,7 +2,7 @@ import { Breadcrumb, BreadcrumbItem, Spinner } from "@patternfly/react-core"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import { useAdminClient, useFetch } from "../context/auth/AdminClient"; @@ -52,6 +52,20 @@ export const RealmSettingsSection = () => { useState(); const [currentUser, setCurrentUser] = useState(); const { whoAmI } = useWhoAmI(); + const [key, setKey] = useState(0); + + const refresh = () => { + setKey(key + 1); + }; + + // delays realm fetch by 100ms in order to fetch newly updated value from server + useEffect(() => { + const update = async () => { + const realm = await adminClient.realms.findOne({ realm: realmName }); + setRealm(realm); + }; + setTimeout(update, 100); + }, [key]); useFetch( async () => { @@ -82,6 +96,7 @@ export const RealmSettingsSection = () => { return ( diff --git a/src/realm-settings/RealmSettingsTabs.tsx b/src/realm-settings/RealmSettingsTabs.tsx index c65102fef2..6d4af66600 100644 --- a/src/realm-settings/RealmSettingsTabs.tsx +++ b/src/realm-settings/RealmSettingsTabs.tsx @@ -53,6 +53,7 @@ type RealmSettingsHeaderProps = { value: boolean; save: () => void; realmName: string; + refresh: () => void; }; const RealmSettingsHeader = ({ @@ -60,12 +61,12 @@ const RealmSettingsHeader = ({ onChange, value, realmName, + refresh, }: RealmSettingsHeaderProps) => { const { t } = useTranslation("realm-settings"); const adminClient = useAdminClient(); const { addAlert, addError } = useAlerts(); const history = useHistory(); - const { refresh } = useRealm(); const [partialImportOpen, setPartialImportOpen] = useState(false); const [toggleDisableDialog, DisableConfirm] = useConfirmDialog({ @@ -138,6 +139,7 @@ const RealmSettingsHeader = ({ type RealmSettingsTabsProps = { realm: RealmRepresentation; + refresh: () => void; realmComponents: ComponentRepresentation[]; currentUser: UserRepresentation; }; @@ -146,6 +148,7 @@ export const RealmSettingsTabs = ({ realm, realmComponents, currentUser, + refresh, }: RealmSettingsTabsProps) => { const { t } = useTranslation("realm-settings"); const adminClient = useAdminClient(); @@ -162,7 +165,7 @@ export const RealmSettingsTabs = ({ const [activeTab, setActiveTab] = useState(0); const [key, setKey] = useState(0); - const refresh = () => { + const refreshHeader = () => { setKey(new Date().getTime()); }; @@ -188,9 +191,14 @@ export const RealmSettingsTabs = ({ convertFormValuesToObject(realm.attributes, true) ).filter(([, v]) => v !== "") ); + await adminClient.realms.update( { realm: realmName }, - { ...realm, id: realmName, attributes } + { + ...realm, + id: realmName, + attributes, + } ); setupForm(realm); const isRealmRenamed = realmName !== realm.realm; @@ -215,6 +223,7 @@ export const RealmSettingsTabs = ({ value={value} onChange={onChange} realmName={realmName} + refresh={refreshHeader} save={() => save(getValues())} /> )} @@ -239,7 +248,11 @@ export const RealmSettingsTabs = ({ data-testid="rs-login-tab" aria-label="login-tab" > - +