From 0dc3f08917d73711cb4785231c5c784f11edc0ad Mon Sep 17 00:00:00 2001 From: mfrances17 <39063664+mfrances17@users.noreply.github.com> Date: Fri, 22 Jan 2021 15:15:32 -0500 Subject: [PATCH] Add Save/Cancel buttons and logic to Kerberos settings (#307) * initial save cancel logic * cleanup work after merge * move form logic up to parent * save working * update messages * no longer need to pass in save from children * pass form into wizard to fix build errors * fix lint fmt issue * add simple field validation and error prevention * localize validation strings * fix default value issues * localize default value --- .../UserFederationKerberosSettings.tsx | 79 ++++++++- .../UserFederationKerberosWizard.tsx | 15 +- .../kerberos/KerberosSettingsCache.tsx | 109 +++++------- .../kerberos/KerberosSettingsRequired.tsx | 156 ++++++++++++------ src/user-federation/messages.json | 9 +- src/user-federation/user-federation.css | 4 + 6 files changed, 238 insertions(+), 134 deletions(-) diff --git a/src/user-federation/UserFederationKerberosSettings.tsx b/src/user-federation/UserFederationKerberosSettings.tsx index d5aa593603..9bc382ae30 100644 --- a/src/user-federation/UserFederationKerberosSettings.tsx +++ b/src/user-federation/UserFederationKerberosSettings.tsx @@ -1,16 +1,87 @@ -import { PageSection } from "@patternfly/react-core"; -import React from "react"; +import { + ActionGroup, + AlertVariant, + Button, + Form, + PageSection, +} from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import React, { useEffect } from "react"; + import { KerberosSettingsRequired } from "./kerberos/KerberosSettingsRequired"; import { KerberosSettingsCache } from "./kerberos/KerberosSettingsCache"; +import { useHistory } from "react-router-dom"; +import { useRealm } from "../context/realm-context/RealmContext"; +import { useParams } from "react-router-dom"; +import { convertToFormValues } from "../util"; +import { useAlerts } from "../components/alert/Alerts"; +import { useAdminClient } from "../context/auth/AdminClient"; +import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; +import { useForm } from "react-hook-form"; export const UserFederationKerberosSettings = () => { + const { t } = useTranslation("user-federation"); + const form = useForm({ mode: "onChange" }); + const history = useHistory(); + const adminClient = useAdminClient(); + const { realm } = useRealm(); + + const { id } = useParams<{ id: string }>(); + + const { addAlert } = useAlerts(); + + useEffect(() => { + (async () => { + const fetchedComponent = await adminClient.components.findOne({ id }); + if (fetchedComponent) { + setupForm(fetchedComponent); + } + })(); + }, []); + + const setupForm = (component: ComponentRepresentation) => { + Object.entries(component).map((entry) => { + form.setValue( + "config.allowPasswordAuthentication", + component.config?.allowPasswordAuthentication + ); + if (entry[0] === "config") { + convertToFormValues(entry[1], "config", form.setValue); + } + form.setValue(entry[0], entry[1]); + }); + }; + + const save = async (component: ComponentRepresentation) => { + try { + await adminClient.components.update({ id }, component); + setupForm(component as ComponentRepresentation); + addAlert(t("saveSuccess"), AlertVariant.success); + } catch (error) { + addAlert(`${t("saveError")} '${error}'`, AlertVariant.danger); + } + }; + return ( <> - + - + +
+ + + + +
); diff --git a/src/user-federation/UserFederationKerberosWizard.tsx b/src/user-federation/UserFederationKerberosWizard.tsx index 63b7b7389e..3c1937ca14 100644 --- a/src/user-federation/UserFederationKerberosWizard.tsx +++ b/src/user-federation/UserFederationKerberosWizard.tsx @@ -3,21 +3,32 @@ import { useTranslation } from "react-i18next"; import React from "react"; import { KerberosSettingsRequired } from "./kerberos/KerberosSettingsRequired"; import { KerberosSettingsCache } from "./kerberos/KerberosSettingsCache"; +import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; +import { useForm } from "react-hook-form"; export const UserFederationKerberosWizard = () => { const { t } = useTranslation("user-federation"); + const form = useForm({ mode: "onChange" }); const steps = [ { name: t("requiredSettings"), component: ( - + ), }, { name: t("cacheSettings"), component: ( - + ), nextButtonText: t("common:finish"), // TODO: needs to disable until cache policy is valid }, diff --git a/src/user-federation/kerberos/KerberosSettingsCache.tsx b/src/user-federation/kerberos/KerberosSettingsCache.tsx index 3e7693bd67..130d41bcfd 100644 --- a/src/user-federation/kerberos/KerberosSettingsCache.tsx +++ b/src/user-federation/kerberos/KerberosSettingsCache.tsx @@ -7,58 +7,31 @@ import { } from "@patternfly/react-core"; import { useTranslation } from "react-i18next"; import { HelpItem } from "../../components/help-enabler/HelpItem"; -import React, { useEffect, useState } from "react"; -import { convertToFormValues } from "../../util"; -import { useForm, Controller, useWatch } from "react-hook-form"; -import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; +import React, { useState } from "react"; +import { UseFormMethods, Controller, useWatch } from "react-hook-form"; import { FormAccess } from "../../components/form-access/FormAccess"; -import { - useAdminClient, - asyncStateFetch, -} from "../../context/auth/AdminClient"; -import { useParams } from "react-router-dom"; import _ from "lodash"; import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader"; export type KerberosSettingsCacheProps = { + form: UseFormMethods; showSectionHeading?: boolean; showSectionDescription?: boolean; }; export const KerberosSettingsCache = ({ + form, showSectionHeading = false, showSectionDescription = false, }: KerberosSettingsCacheProps) => { const { t } = useTranslation("user-federation"); const helpText = useTranslation("user-federation-help").t; - const adminClient = useAdminClient(); - const { register, control, setValue } = useForm(); - const { id } = useParams<{ id: string }>(); - const cachePolicyType = useWatch({ - control: control, + control: form.control, name: "config.cachePolicy", }); - const setupForm = (component: ComponentRepresentation) => { - Object.entries(component).map((entry) => { - setValue("config.cachePolicy", component.config?.cachePolicy); - if (entry[0] === "config") { - convertToFormValues(entry[1], "config", setValue); - } else { - setValue(entry[0], entry[1]); - } - }); - }; - - useEffect(() => { - return asyncStateFetch( - () => adminClient.components.findOne({ id }), - (component) => setupForm(component) - ); - }, []); - const [isCachePolicyDropdownOpen, setIsCachePolicyDropdownOpen] = useState( false ); @@ -73,18 +46,16 @@ export const KerberosSettingsCache = ({ false ); - const hourOptions = [ - , - ]; - for (let index = 1; index <= 24; index++) { - hourOptions.push(); + const hourOptions = []; + for (let index = 2; index <= 24; index++) { + hourOptions.push(); } const minuteOptions = [ - , + , ]; - for (let index = 1; index <= 60; index++) { - minuteOptions.push(); + for (let index = 2; index <= 60; index++) { + minuteOptions.push(); } return ( @@ -112,8 +83,8 @@ export const KerberosSettingsCache = ({ > ( )} > @@ -154,12 +120,13 @@ export const KerberosSettingsCache = ({ forID="kc-eviction-day" /> } + isRequired fieldId="kc-eviction-day" > ( @@ -221,12 +183,13 @@ export const KerberosSettingsCache = ({ forID="kc-eviction-hour" /> } + isRequired fieldId="kc-eviction-hour" > ( } + isRequired fieldId="kc-max-lifespan" > ) : ( diff --git a/src/user-federation/kerberos/KerberosSettingsRequired.tsx b/src/user-federation/kerberos/KerberosSettingsRequired.tsx index 027c673eb0..9b8eb579e9 100644 --- a/src/user-federation/kerberos/KerberosSettingsRequired.tsx +++ b/src/user-federation/kerberos/KerberosSettingsRequired.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { FormGroup, Select, @@ -6,62 +6,37 @@ import { SelectVariant, Switch, TextInput, - Title, } from "@patternfly/react-core"; import { useTranslation } from "react-i18next"; -import { HelpItem } from "../../components/help-enabler/HelpItem"; -import { useForm, Controller, useWatch } from "react-hook-form"; -import ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation"; +import { UseFormMethods, Controller, useWatch } from "react-hook-form"; + import { FormAccess } from "../../components/form-access/FormAccess"; -import { useAdminClient } from "../../context/auth/AdminClient"; -import { useParams } from "react-router-dom"; -import { convertToFormValues } from "../../util"; + +import { HelpItem } from "../../components/help-enabler/HelpItem"; import _ from "lodash"; import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader"; export type KerberosSettingsRequiredProps = { + form: UseFormMethods; showSectionHeading?: boolean; showSectionDescription?: boolean; }; export const KerberosSettingsRequired = ({ + form, showSectionHeading = false, showSectionDescription = false, }: KerberosSettingsRequiredProps) => { const { t } = useTranslation("user-federation"); const helpText = useTranslation("user-federation-help").t; - const adminClient = useAdminClient(); + const [isEditModeDropdownOpen, setIsEditModeDropdownOpen] = useState(false); - const { register, control, setValue } = useForm(); - const { id } = useParams<{ id: string }>(); const allowPassAuth = useWatch({ - control: control, + control: form.control, name: "config.allowPasswordAuthentication", }); - const setupForm = (component: ComponentRepresentation) => { - Object.entries(component).map((entry) => { - setValue( - "config.allowPasswordAuthentication", - component.config?.allowPasswordAuthentication - ); - if (entry[0] === "config") { - convertToFormValues(entry[1], "config", setValue); - } - setValue(entry[0], entry[1]); - }); - }; - - useEffect(() => { - (async () => { - const fetchedComponent = await adminClient.components.findOne({ id }); - if (fetchedComponent) { - setupForm(fetchedComponent); - } - })(); - }, []); - return ( <> {showSectionHeading && ( @@ -86,13 +61,51 @@ export const KerberosSettingsRequired = ({ fieldId="kc-console-display-name" isRequired > + {/* These hidden fields are required so data object written back matches data retrieved */} +