Skip to content

Commit

Permalink
required can have a value that is a boolean when used with controls (k…
Browse files Browse the repository at this point in the history
…eycloak#34251)

* required is a boolean when used with controls

fixes: keycloak#33614
Signed-off-by: Erik Jan de Wit <[email protected]>

* simplified rules declaration

Signed-off-by: Erik Jan de Wit <[email protected]>

* added missing messages

Signed-off-by: Erik Jan de Wit <[email protected]>

* use value when it's present

Signed-off-by: Erik Jan de Wit <[email protected]>

---------

Signed-off-by: Erik Jan de Wit <[email protected]>
  • Loading branch information
edewit authored Oct 25, 2024
1 parent 624817b commit 2f64f43
Show file tree
Hide file tree
Showing 17 changed files with 43 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
#jwksUrl = "config.jwksUrl";
#pkceSwitch = "#config\\.pkceEnabled";
#pkceMethod = "#pkceMethod";
#clientAuth = "#clientAuthentication";
#clientAuth = "#clientAuthMethod";
#clientAssertionSigningAlg = "#clientAssertionSigningAlg";
#clientAssertionAudienceInput = "#clientAssertionAudience";
#jwtX509HeadersSwitch = "#jwtX509HeadersEnabled";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const EditFlow = ({ execution, onRowChange }: EditFlowProps) => {
name="displayName"
label={t("name")}
labelIcon={t("flowNameHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<TextAreaControl
name="description"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const ExecutionConfigModal = ({
name="alias"
label={t("alias")}
labelIcon={t("authenticationAliasHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
isDisabled={!!config}
/>
<DynamicComponents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const AddSubFlowModal = ({
name="name"
label={t("name")}
labelIcon={t("clientIdHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<TextControl
name="description"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const NameDescription = () => {
name="alias"
label={t("name")}
labelIcon={t("flowNameHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<TextControl
name="description"
Expand Down
10 changes: 2 additions & 8 deletions js/apps/admin-ui/src/authentication/policies/CibaPolicy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ export const CibaPolicy = ({ realm, realmUpdated }: CibaPolicyProps) => {
value: CIBA_EXPIRES_IN_MAX,
message: t("lessThan", { value: CIBA_EXPIRES_IN_MAX }),
},
required: {
value: true,
message: t("required"),
},
required: t("required"),
}}
/>
<TextControl
Expand All @@ -124,10 +121,7 @@ export const CibaPolicy = ({ realm, realmUpdated }: CibaPolicyProps) => {
value: CIBA_INTERVAL_MAX,
message: t("lessThan", { value: CIBA_INTERVAL_MAX }),
},
required: {
value: true,
message: t("required"),
},
required: t("required"),
}}
/>
<SelectControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const WebauthnPolicy = ({
name={`${namePrefix}RpEntityName`}
label={t("webAuthnPolicyRpEntityName")}
labelIcon={t("webAuthnPolicyRpEntityNameHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<WebauthnSelect
name={`${namePrefix}SignatureAlgorithms`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export default function MappingDetails() {
label={t("name")}
labelIcon={t("mapperNameHelp")}
readOnlyVariant={isUpdating ? "default" : undefined}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<DynamicComponents
properties={mapping?.properties || []}
Expand Down
5 changes: 1 addition & 4 deletions js/apps/admin-ui/src/client-scopes/details/ScopeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
label={t("name")}
labelIcon={t("scopeNameHelp")}
rules={{
required: {
value: true,
message: t("required"),
},
required: t("required"),
onChange: (e) => {
if (isDynamicScopesEnabled)
setDynamicRegex(e.target.validated, true);
Expand Down
2 changes: 1 addition & 1 deletion js/apps/admin-ui/src/clients/ClientDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const ClientDescription = ({
name="clientId"
label={t("clientId")}
labelIcon={t("clientIdHelp")}
rules={{ required: { value: true, message: t("required") } }}
rules={{ required: t("required") }}
/>
<TextControl
name="name"
Expand Down
118 changes: 24 additions & 94 deletions js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import {
HelpItem,
KeycloakSelect,
SelectVariant,
} from "@keycloak/keycloak-ui-shared";
import { FormGroup, SelectOption } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { SelectControl } from "@keycloak/keycloak-ui-shared";
import { useFormContext, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
import { sortProviders } from "../../util";
Expand All @@ -25,8 +19,6 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {
const { t } = useTranslation();

const { control } = useFormContext();
const [openClientAuth, setOpenClientAuth] = useState(false);
const [openClientAuthSigAlg, setOpenClientAuthSigAlg] = useState(false);

const clientAuthMethod = useWatch({
control: control,
Expand All @@ -35,96 +27,34 @@ export const OIDCAuthentication = ({ create = true }: { create?: boolean }) => {

return (
<>
<FormGroup
<SelectControl
name="config.clientAuthMethod"
label={t("clientAuthentication")}
labelIcon={
<HelpItem
helpText={t("clientAuthenticationHelp")}
fieldLabelId="clientAuthentication"
/>
}
fieldId="clientAuthentication"
>
<Controller
name="config.clientAuthMethod"
defaultValue={clientAuthentications[0]}
control={control}
render={({ field }) => (
<KeycloakSelect
toggleId="clientAuthentication"
onToggle={() => setOpenClientAuth(!openClientAuth)}
onSelect={(value) => {
field.onChange(value as string);
setOpenClientAuth(false);
}}
selections={field.value}
variant={SelectVariant.single}
aria-label={t("clientAuthentication")}
isOpen={openClientAuth}
>
{clientAuthentications.map((option) => (
<SelectOption
selected={option === field.value}
key={option}
value={option}
>
{t(`clientAuthentications.${option}`)}
</SelectOption>
))}
</KeycloakSelect>
)}
/>
</FormGroup>
labelIcon={t("clientAuthenticationHelp")}
options={clientAuthentications.map((auth) => ({
key: auth,
value: t(`clientAuthentications.${auth}`),
}))}
controller={{
defaultValue: clientAuthentications[0],
}}
/>
<ClientIdSecret
secretRequired={clientAuthMethod !== "private_key_jwt"}
create={create}
/>
<FormGroup
<SelectControl
name="config.clientAssertionSigningAlg"
label={t("clientAssertionSigningAlg")}
labelIcon={
<HelpItem
helpText={t("clientAssertionSigningAlgHelp")}
fieldLabelId="clientAssertionSigningAlg"
/>
}
fieldId="clientAssertionSigningAlg"
>
<Controller
name="config.clientAssertionSigningAlg"
defaultValue=""
control={control}
render={({ field }) => (
<KeycloakSelect
maxHeight={200}
toggleId="clientAssertionSigningAlg"
onToggle={() => setOpenClientAuthSigAlg(!openClientAuthSigAlg)}
onSelect={(value) => {
field.onChange(value.toString());
setOpenClientAuthSigAlg(false);
}}
selections={field.value || t("algorithmNotSpecified")}
variant={SelectVariant.single}
aria-label={t("selectClientAssertionSigningAlg")}
isOpen={openClientAuthSigAlg}
>
{[
<SelectOption selected={field.value === ""} key="" value="">
{t("algorithmNotSpecified")}
</SelectOption>,
...sortProviders(providers).map((option) => (
<SelectOption
selected={option === field.value}
key={option}
value={option}
>
{option}
</SelectOption>
)),
]}
</KeycloakSelect>
)}
/>
</FormGroup>
labelIcon={t("clientAssertionSigningAlgHelp")}
options={[
{ key: "", value: t("algorithmNotSpecified") },
...sortProviders(providers).map((p) => ({ key: p, value: p })),
]}
controller={{
defaultValue: "",
}}
/>
{(clientAuthMethod === "private_key_jwt" ||
clientAuthMethod === "client_secret_jwt") && (
<TextField
Expand Down
2 changes: 1 addition & 1 deletion js/apps/admin-ui/src/realm-settings/NewClientPolicy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ export default function NewClientPolicy() {
name="name"
label={t("name")}
rules={{
required: { value: true, message: t("required") },
required: t("required"),
validate: (value) =>
policies.some((policy) => policy.name === value)
? t("createClientProfileNameHelperText").toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,7 @@ export default function AttributesGroupForm() {
labelIcon={t("nameHintHelp")}
isDisabled={!!matchingGroup || editMode}
rules={{
required: {
value: true,
message: t("required"),
},
required: t("required"),
onChange: (event) => {
handleAttributesGroupNameChange(event, event.target.value);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,7 @@ export const AddTranslationsDialog = ({
label={t("translationValue")}
data-testid={`translation-value-${rowIndex}`}
rules={{
required: {
value: true,
message: t("required"),
},
required: t("required"),
}}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const LdapSettingsSearching = ({
controller={{
defaultValue: "",
rules: {
required: { value: true, message: t("validateEditMode") },
required: t("validateEditMode"),
},
}}
options={["", "READ_ONLY", "WRITABLE", "UNSYNCED"]}
Expand Down
3 changes: 2 additions & 1 deletion js/libs/ui-shared/src/controls/PasswordControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
UseControllerProps,
useController,
} from "react-hook-form";
import { getRuleValue } from "../utils/getRuleValue";
import { FormLabel } from "./FormLabel";
import { PasswordInput, PasswordInputProps } from "./PasswordInput";

Expand All @@ -32,7 +33,7 @@ export const PasswordControl = <
props: PasswordControlProps<T, P>,
) => {
const { labelIcon, ...rest } = props;
const required = !!props.rules?.required;
const required = !!getRuleValue(props.rules?.required);
const defaultValue = props.defaultValue ?? ("" as PathValue<T, P>);

const { field, fieldState } = useController({
Expand Down
4 changes: 2 additions & 2 deletions js/libs/ui-shared/src/controls/TextControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
UseControllerProps,
useController,
} from "react-hook-form";

import { getRuleValue } from "../utils/getRuleValue";
import { FormLabel } from "./FormLabel";

export type TextControlProps<
Expand All @@ -36,7 +36,7 @@ export const TextControl = <
props: TextControlProps<T, P>,
) => {
const { labelIcon, helperText, ...rest } = props;
const required = !!props.rules?.required;
const required = !!getRuleValue(props.rules?.required);
const defaultValue = props.defaultValue ?? ("" as PathValue<T, P>);

const { field, fieldState } = useController({
Expand Down

0 comments on commit 2f64f43

Please sign in to comment.