Only show activated required actions in credentials reset dialog (#19048)

This commit is contained in:
Oliver 2023-03-28 14:44:01 +02:00 committed by GitHub
parent e40fa5fcb4
commit fc0a9be79f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 83 deletions

View file

@ -45,6 +45,7 @@
"emailInvalid": "You must enter a valid email.",
"notVerified": "Not verified",
"requiredUserActions": "Required user actions",
"requiredActionPlaceholder": "Select action",
"federationLink": "Federation link",
"addUser": "Add user",
"impersonate": "Impersonate",

View file

@ -1,6 +1,5 @@
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
import type RequiredActionProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import {
ActionGroup,
@ -10,8 +9,6 @@ import {
ChipGroup,
FormGroup,
InputGroup,
Select,
SelectOption,
Switch,
} from "@patternfly/react-core";
import { useState } from "react";
@ -32,6 +29,7 @@ import useFormatDate from "../utils/useFormatDate";
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
import { FederatedUserLink } from "./FederatedUserLink";
import { UserProfileFields } from "./UserProfileFields";
import { RequiredActionMultiSelect } from "./user-credentials/RequiredActionMultiSelect";
export type BruteForced = {
isBruteForceProtected?: boolean;
@ -93,10 +91,6 @@ export const UserForm = ({
const formatDate = useFormatDate();
const isFeatureEnabled = useIsFeatureEnabled();
const [
isRequiredUserActionsDropdownOpen,
setRequiredUserActionsDropdownOpen,
] = useState(false);
const navigate = useNavigate();
const { adminClient } = useAdminClient();
const { addAlert, addError } = useAlerts();
@ -118,22 +112,14 @@ export const UserForm = ({
const [open, setOpen] = useState(false);
const [locked, setLocked] = useState(isLocked);
const [realm, setRealm] = useState<RealmRepresentation>();
const [requiredActions, setRequiredActions] = useState<
RequiredActionProviderRepresentation[]
>([]);
useFetch(
() =>
Promise.all([
adminClient.realms.findOne({ realm: realmName }),
adminClient.authenticationManagement.getRequiredActions(),
]),
([realm, actions]) => {
() => adminClient.realms.findOne({ realm: realmName }),
(realm) => {
if (!realm) {
throw new Error(t("common:notFound"));
}
setRealm(realm);
setRequiredActions(actions);
},
[]
);
@ -147,10 +133,6 @@ export const UserForm = ({
}
};
const clearSelection = () => {
setRequiredUserActionsDropdownOpen(false);
};
const deleteItem = (id: string) => {
setSelectedGroups(selectedGroups.filter((item) => item.name !== id));
onGroupsUpdate?.(selectedGroups);
@ -233,56 +215,11 @@ export const UserForm = ({
</FormGroup>
</>
)}
<FormGroup
label={t("requiredUserActions")}
fieldId="kc-required-user-actions"
validated={errors.requiredActions ? "error" : "default"}
helperTextInvalid={t("common:required")}
labelIcon={
<HelpItem
helpText={t("users-help:requiredUserActions")}
fieldLabelId="users:requiredUserActions"
/>
}
>
<Controller
name="requiredActions"
defaultValue={[]}
control={control}
render={({ field }) => (
<Select
data-testid="required-actions-select"
placeholderText="Select action"
toggleId="kc-required-user-actions"
onToggle={() =>
setRequiredUserActionsDropdownOpen(
!isRequiredUserActionsDropdownOpen
)
}
isOpen={isRequiredUserActionsDropdownOpen}
selections={field.value}
onSelect={(_, v) => {
const option = v as string;
if (field.value.includes(option)) {
field.onChange(
field.value.filter((item: string) => item !== option)
);
} else {
field.onChange([...field.value, option]);
}
}}
onClear={clearSelection}
variant="typeaheadmulti"
>
{requiredActions.map(({ alias, name }) => (
<SelectOption key={alias} value={alias}>
{name}
</SelectOption>
))}
</Select>
)}
/>
</FormGroup>
<RequiredActionMultiSelect
name="requiredActions"
label="requiredUserActions"
help="users-help:requiredUserActions"
/>
{(user?.federationLink || user?.origin) && (
<FormGroup
label={t("federationLink")}

View file

@ -12,7 +12,17 @@ import { useTranslation } from "react-i18next";
import { HelpItem } from "ui-shared";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
export const CredentialsResetActionMultiSelect = () => {
type RequiredActionMultiSelectProps = {
name: string;
label: string;
help: string;
};
export const RequiredActionMultiSelect = ({
name,
label,
help,
}: RequiredActionMultiSelectProps) => {
const { t } = useTranslation("users");
const { adminClient } = useAdminClient();
const { control } = useFormContext();
@ -24,24 +34,22 @@ export const CredentialsResetActionMultiSelect = () => {
useFetch(
() => adminClient.authenticationManagement.getRequiredActions(),
(actions) => {
setRequiredActions(actions);
const enabledUserActions = actions.filter((action) => {
return action.enabled;
});
setRequiredActions(enabledUserActions);
},
[]
);
return (
<FormGroup
label={t("resetActions")}
labelIcon={
<HelpItem
helpText={t("clients-help:resetActions")}
fieldLabelId="resetActions"
/>
}
label={t(label)}
labelIcon={<HelpItem helpText={t(help)} fieldLabelId="resetActions" />}
fieldId="actions"
>
<Controller
name="actions"
name={name}
defaultValue={[]}
control={control}
render={({ field }) => (
@ -52,6 +60,7 @@ export const CredentialsResetActionMultiSelect = () => {
chipGroupProps={{
numChips: 3,
}}
placeholderText={t("requiredActionPlaceholder")}
menuAppendTo="parent"
onToggle={(open) => setOpen(open)}
isOpen={open}

View file

@ -3,7 +3,7 @@ import { FormProvider, useForm, useWatch } from "react-hook-form";
import { ModalVariant, Form, AlertVariant } from "@patternfly/react-core";
import type { RequiredActionAlias } from "@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation";
import { CredentialsResetActionMultiSelect } from "./CredentialsResetActionMultiSelect";
import { RequiredActionMultiSelect } from "./RequiredActionMultiSelect";
import { ConfirmDialogModal } from "../../components/confirm-dialog/ConfirmDialog";
import { useAdminClient } from "../../context/auth/AdminClient";
import { useAlerts } from "../../components/alert/Alerts";
@ -84,7 +84,11 @@ export const ResetCredentialDialog = ({
data-testid="credential-reset-modal"
>
<FormProvider {...form}>
<CredentialsResetActionMultiSelect />
<RequiredActionMultiSelect
name="actions"
label="resetActions"
help="clients-help:resetActions"
/>
<LifespanField />
</FormProvider>
</Form>