fixing the remainder of issue 428 (#621)

* fixing the remainder of issue 428

fixing: #428

* fix undefined

* add leave dialog
This commit is contained in:
Erik Jan de Wit 2021-05-24 06:21:49 +02:00 committed by GitHub
parent 0f6ce35687
commit 29323cb12c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 31 deletions

View file

@ -35,7 +35,7 @@ export const SignedJWT = () => {
> >
<Controller <Controller
name="attributes.token-endpoint-auth-signing-alg" name="attributes.token-endpoint-auth-signing-alg"
defaultValue={providers[0]} defaultValue=""
control={control} control={control}
render={({ onChange, value }) => ( render={({ onChange, value }) => (
<Select <Select
@ -46,18 +46,23 @@ export const SignedJWT = () => {
onChange(value as string); onChange(value as string);
isOpen(false); isOpen(false);
}} }}
selections={value} selections={value || t("anyAlgorithm")}
variant={SelectVariant.single} variant={SelectVariant.single}
aria-label={t("signatureAlgorithm")} aria-label={t("signatureAlgorithm")}
isOpen={open} isOpen={open}
> >
{providers.map((option) => ( <SelectOption selected={value === ""} key="any" value="">
<SelectOption {t("anyAlgorithm")}
selected={option === value} </SelectOption>
key={option} <>
value={option} {providers.map((option) => (
/> <SelectOption
))} selected={option === value}
key={option}
value={option}
/>
))}
</>
</Select> </Select>
)} )}
/> />

View file

@ -1,12 +1,12 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form";
import { FormGroup, TextInput } from "@patternfly/react-core"; import { FormGroup, TextInput, ValidatedOptions } from "@patternfly/react-core";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
export const X509 = () => { export const X509 = () => {
const { t } = useTranslation("clients"); const { t } = useTranslation("clients");
const { register } = useFormContext(); const { register, errors } = useFormContext();
return ( return (
<FormGroup <FormGroup
label={t("subject")} label={t("subject")}
@ -18,12 +18,24 @@ export const X509 = () => {
forID="kc-subject" forID="kc-subject"
/> />
} }
helperTextInvalid={t("common:required")}
validated={
errors.attributes && errors.attributes["x509-subjectdn"]
? ValidatedOptions.error
: ValidatedOptions.default
}
isRequired
> >
<TextInput <TextInput
ref={register()} ref={register({ required: true })}
type="text" type="text"
id="kc-subject" id="kc-subject"
name="attributes.x509-subjectdn" name="attributes.x509-subjectdn"
validated={
errors.attributes && errors.attributes["x509-subjectdn"]
? ValidatedOptions.error
: ValidatedOptions.default
}
/> />
</FormGroup> </FormGroup>
); );

View file

@ -128,6 +128,7 @@
"changeAuthenticatorConfirmTitle": "Change to {{clientAuthenticatorType}}", "changeAuthenticatorConfirmTitle": "Change to {{clientAuthenticatorType}}",
"changeAuthenticatorConfirm": "If you change authenticator to {{clientAuthenticatorType}}, the keycloak database will be updated and you may need to download a new adapter configuration for this client", "changeAuthenticatorConfirm": "If you change authenticator to {{clientAuthenticatorType}}, the keycloak database will be updated and you may need to download a new adapter configuration for this client",
"signedJWTConfirm": "You should configure JWKS URL or keys in the \"Keys\" tab to change the parameters of Signed JWT authenticator.", "signedJWTConfirm": "You should configure JWKS URL or keys in the \"Keys\" tab to change the parameters of Signed JWT authenticator.",
"anyAlgorithm": "Any algorithm",
"clientSecret": "Client secret", "clientSecret": "Client secret",
"regenerate": "Regenerate", "regenerate": "Regenerate",
"confirmClientSecretTitle": "Regenerate secret for this client?", "confirmClientSecretTitle": "Regenerate secret for this client?",

View file

@ -127,6 +127,10 @@
"emptyMappers": "No mappers", "emptyMappers": "No mappers",
"emptyMappersInstructions": "If you want to add mappers, please click the button below to add some predefined mappers or to configure a new mapper.", "emptyMappersInstructions": "If you want to add mappers, please click the button below to add some predefined mappers or to configure a new mapper.",
"emptyPrimaryAction": "Add predefined mapper" "emptyPrimaryAction": "Add predefined mapper",
"leaveDirtyTitle": "Leave without saving?",
"leaveDirtyConfirm": "Do you want to leave this page without saving? Any unsaved changes will be lost.",
"leave": "Leave"
} }
} }

View file

@ -1,6 +1,8 @@
import React, { Children, isValidElement } from "react"; import React, { Children, isValidElement, useState } from "react";
import { useHistory, useRouteMatch } from "react-router-dom"; import { useHistory, useRouteMatch } from "react-router-dom";
import { TabProps, Tabs, TabsProps } from "@patternfly/react-core"; import { TabProps, Tabs, TabsProps } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { useConfirmDialog } from "../confirm-dialog/ConfirmDialog";
type KeycloakTabsProps = Omit<TabsProps, "ref" | "activeKey" | "onSelect"> & { type KeycloakTabsProps = Omit<TabsProps, "ref" | "activeKey" | "onSelect"> & {
paramName?: string; paramName?: string;
@ -28,6 +30,8 @@ export const KeycloakTabs = ({
const match = useRouteMatch(); const match = useRouteMatch();
const params = match.params as { [index: string]: string }; const params = match.params as { [index: string]: string };
const history = useHistory(); const history = useHistory();
const form = useFormContext();
const [key, setKey] = useState("");
const firstTab = Children.toArray(children)[0]; const firstTab = Children.toArray(children)[0];
const tab = const tab =
@ -37,21 +41,42 @@ export const KeycloakTabs = ({
const pathIndex = match.path.indexOf(paramName) + paramName.length; const pathIndex = match.path.indexOf(paramName) + paramName.length;
const path = match.path.substr(0, pathIndex); const path = match.path.substr(0, pathIndex);
const [toggleChangeTabDialog, ChangeTabConfirm] = useConfirmDialog({
titleKey: "common:leaveDirtyTitle",
messageKey: "common:leaveDirtyConfirm",
continueButtonLabel: "common:leave",
onConfirm: () => {
form.reset();
history.push(createUrl(path, { ...params, [paramName]: key as string }));
},
});
return ( return (
<Tabs <>
inset={{ <ChangeTabConfirm />
default: "insetNone", <Tabs
md: "insetSm", inset={{
xl: "inset2xl", default: "insetNone",
"2xl": "insetLg", md: "insetSm",
}} xl: "inset2xl",
activeKey={tab} "2xl": "insetLg",
onSelect={(_, key) => }}
history.push(createUrl(path, { ...params, [paramName]: key as string })) activeKey={tab}
} onSelect={(_, key) => {
{...rest} if (form?.formState.isDirty) {
> setKey(key as string);
{children} toggleChangeTabDialog();
</Tabs> } else {
history.push(
createUrl(path, { ...params, [paramName]: key as string })
);
}
}}
{...rest}
>
{children}
</Tabs>
</>
); );
}; };

View file

@ -21,7 +21,7 @@ export function convertToMultiline(fields: string[]): MultiLine[] {
} }
export function toValue(formValue: MultiLine[]): string[] { export function toValue(formValue: MultiLine[]): string[] {
return formValue.map((field) => field.value); return formValue?.map((field) => field.value);
} }
export type MultiLineInputProps = Omit<TextInputProps, "form"> & { export type MultiLineInputProps = Omit<TextInputProps, "form"> & {

View file

@ -45,7 +45,11 @@ export const ScrollForm = ({
</ScrollPanel> </ScrollPanel>
)} )}
{borders && ( {borders && (
<FormPanel scrollId={spacesToHyphens(cat)} title={cat}> <FormPanel
scrollId={spacesToHyphens(cat)}
title={cat}
className="kc-form-panel__panel"
>
{nodes[index]} {nodes[index]}
</FormPanel> </FormPanel>
)} )}