Added missing fields when dynamic scope is enabled (#19984)
Closes #19865
This commit is contained in:
parent
81580908c3
commit
e8ed1abda7
6 changed files with 72 additions and 8 deletions
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"name": "Name of the client scope. Must be unique in the realm. Name should not contain space characters as it is used as value of scope parameter",
|
||||
"dynamicScope": "If on, this scope will be considered a Dynamic Scope, which will be comprised of a static and a variable portion.",
|
||||
"dynamicScopeFormat": "This is the regular expression that the system will use to extract the scope name and variable.",
|
||||
"description": "Description of the client scope",
|
||||
"protocol": "Which SSO protocol configuration is being supplied by this client scope",
|
||||
"type": "Client scopes, which will be added as default scopes to each created client",
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"clientScopeDetails": "Client scope details",
|
||||
"clientScopeExplain": "Client scopes are a common set of protocol mappers and roles that are shared between multiple clients.",
|
||||
"searchFor": "Search for client scope",
|
||||
"dynamicScope": "Dynamic scope",
|
||||
"dynamicScopeFormat": "Dynamic scope format",
|
||||
"protocol": "Protocol",
|
||||
"assignedType": "Assigned type",
|
||||
"displayOrder": "Display order",
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
|
@ -21,13 +21,15 @@ import {
|
|||
clientScopeTypesSelectOptions,
|
||||
} from "../../components/client-scope/ClientScopeTypes";
|
||||
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||
import { HelpItem } from "ui-shared";
|
||||
import { HelpItem, TextControl } from "ui-shared";
|
||||
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
|
||||
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { useLoginProviders } from "../../context/server-info/ServerInfoProvider";
|
||||
import { convertAttributeNameToForm, convertToFormValues } from "../../util";
|
||||
import { toClientScopes } from "../routes/ClientScopes";
|
||||
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
|
||||
import { DefaultSwitchControl } from "../../components/SwitchControl";
|
||||
|
||||
type ScopeFormProps = {
|
||||
clientScope?: ClientScopeRepresentation;
|
||||
|
@ -37,16 +39,19 @@ type ScopeFormProps = {
|
|||
export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
|
||||
const { t } = useTranslation("client-scopes");
|
||||
const { t: tc } = useTranslation("clients");
|
||||
const form = useForm<ClientScopeDefaultOptionalType>({ mode: "onChange" });
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm<ClientScopeDefaultOptionalType>({ mode: "onChange" });
|
||||
} = form;
|
||||
const { realm } = useRealm();
|
||||
|
||||
const providers = useLoginProviders();
|
||||
const isFeatureEnabled = useIsFeatureEnabled();
|
||||
const isDynamicScopesEnabled = isFeatureEnabled(Feature.DynamicScopes);
|
||||
const [open, isOpen] = useState(false);
|
||||
const [openType, setOpenType] = useState(false);
|
||||
|
||||
|
@ -57,6 +62,22 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
|
|||
clientScope?.attributes?.["display.on.consent.screen"] ?? "true",
|
||||
});
|
||||
|
||||
const dynamicScope = useWatch({
|
||||
control,
|
||||
name: convertAttributeNameToForm<ClientScopeDefaultOptionalType>(
|
||||
"attributes.is.dynamic.scope"
|
||||
),
|
||||
defaultValue: "false",
|
||||
});
|
||||
|
||||
const setDynamicRegex = (value: string, append: boolean) =>
|
||||
setValue(
|
||||
convertAttributeNameToForm<ClientScopeDefaultOptionalType>(
|
||||
"attributes.dynamic.scope.regexp"
|
||||
),
|
||||
append ? `${value}:*` : value
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
convertToFormValues(clientScope ?? {}, setValue);
|
||||
}, [clientScope]);
|
||||
|
@ -88,9 +109,41 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
|
|||
errors.name ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
isRequired
|
||||
{...register("name", { required: true })}
|
||||
{...register("name", {
|
||||
required: true,
|
||||
onChange: (e) => {
|
||||
if (isDynamicScopesEnabled) {
|
||||
setDynamicRegex(e.target.value, true);
|
||||
}
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</FormGroup>
|
||||
{isDynamicScopesEnabled && (
|
||||
<FormProvider {...form}>
|
||||
<DefaultSwitchControl
|
||||
name={convertAttributeNameToForm<ClientScopeDefaultOptionalType>(
|
||||
"attributes.is.dynamic.scope"
|
||||
)}
|
||||
label={t("dynamicScope")}
|
||||
labelIcon={t("client-scopes-help:dynamicScope")}
|
||||
onChange={(value) => {
|
||||
setDynamicRegex(value ? form.getValues("name") || "" : "", value);
|
||||
}}
|
||||
stringify
|
||||
/>
|
||||
{dynamicScope === "true" && (
|
||||
<TextControl
|
||||
name={convertAttributeNameToForm<ClientScopeDefaultOptionalType>(
|
||||
"attributes.dynamic.scope.regexp"
|
||||
)}
|
||||
label={t("dynamicScopeFormat")}
|
||||
labelIcon={t("client-scopes-help:dynamicScopeFormat")}
|
||||
isDisabled
|
||||
/>
|
||||
)}
|
||||
</FormProvider>
|
||||
)}
|
||||
<FormGroup
|
||||
label={t("common:description")}
|
||||
labelIcon={
|
||||
|
|
|
@ -3,7 +3,7 @@ import { FieldPath, FieldValues, UseControllerProps } from "react-hook-form";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { SwitchControl } from "ui-shared";
|
||||
|
||||
type AdminSwitchControlProps<
|
||||
type DefaultSwitchControlProps<
|
||||
T extends FieldValues,
|
||||
P extends FieldPath<T> = FieldPath<T>
|
||||
> = SwitchProps &
|
||||
|
@ -11,13 +11,14 @@ type AdminSwitchControlProps<
|
|||
name: string;
|
||||
label?: string;
|
||||
labelIcon?: string;
|
||||
stringify?: boolean;
|
||||
};
|
||||
|
||||
export const DefaultSwitchControl = <
|
||||
T extends FieldValues,
|
||||
P extends FieldPath<T> = FieldPath<T>
|
||||
>(
|
||||
props: AdminSwitchControlProps<T, P>
|
||||
props: DefaultSwitchControlProps<T, P>
|
||||
) => {
|
||||
const { t } = useTranslation("common");
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ export enum Feature {
|
|||
ClientPolicies = "CLIENT_POLICIES",
|
||||
DeclarativeUserProfile = "DECLARATIVE_USER_PROFILE",
|
||||
Kerberos = "KERBEROS",
|
||||
DynamicScopes = "DYNAMIC_SCOPES",
|
||||
}
|
||||
|
||||
export default function useIsFeatureEnabled() {
|
||||
|
|
|
@ -19,6 +19,7 @@ export type SwitchControlProps<
|
|||
labelIcon?: string;
|
||||
labelOn: string;
|
||||
labelOff: string;
|
||||
stringify?: boolean;
|
||||
};
|
||||
|
||||
export const SwitchControl = <
|
||||
|
@ -46,8 +47,12 @@ export const SwitchControl = <
|
|||
data-testid={props.name}
|
||||
label={props.labelOn}
|
||||
labelOff={props.labelOff}
|
||||
isChecked={value}
|
||||
onChange={(checked) => onChange(checked)}
|
||||
isChecked={props.stringify ? value === "true" : value}
|
||||
onChange={(checked, e) => {
|
||||
const value = props.stringify ? checked.toString() : checked;
|
||||
props.onChange?.(checked, e);
|
||||
onChange(value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
Loading…
Reference in a new issue