introduced password control (#27652)
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
e501cfcfb3
commit
4e7c2a5fa3
16 changed files with 153 additions and 200 deletions
|
@ -124,8 +124,10 @@ describe("Identity provider test", () => {
|
|||
}
|
||||
const instance = getSocialIdpClassInstance($idp.testName);
|
||||
instance
|
||||
.typeDisplayOrder("0")
|
||||
.clickAdd()
|
||||
.typeClientId("1")
|
||||
.typeClientId("")
|
||||
.typeClientSecret("1")
|
||||
.typeClientSecret("")
|
||||
.assertRequiredFieldsErrorsExist()
|
||||
.fillData($idp.testName)
|
||||
.clickAdd()
|
||||
|
@ -139,10 +141,7 @@ describe("Identity provider test", () => {
|
|||
createProviderPage.checkGitHubCardVisible().clickGitHubCard();
|
||||
|
||||
createProviderPage.checkAddButtonDisabled();
|
||||
createProviderPage
|
||||
.fill(identityProviderName)
|
||||
.clickAdd()
|
||||
.checkClientIdRequiredMessage(true);
|
||||
createProviderPage.fill(identityProviderName).checkAddButtonDisabled();
|
||||
createProviderPage.fill(identityProviderName, "123").clickAdd();
|
||||
masthead.checkNotificationMessage(createSuccessMsg, true);
|
||||
|
||||
|
@ -298,9 +297,8 @@ describe("Identity provider test", () => {
|
|||
createProviderPage.checkAddButtonDisabled();
|
||||
createProviderPage
|
||||
.fill(identityProviderName)
|
||||
.clickAdd()
|
||||
.checkClientIdRequiredMessage(true);
|
||||
createProviderPage.fill(identityProviderName, "123").clickAdd();
|
||||
.fill(identityProviderName, "123")
|
||||
.clickAdd();
|
||||
masthead.checkNotificationMessage(createSuccessMsg, true);
|
||||
|
||||
sidebarPage.goToIdentityProviders();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export default class CreateProviderPage {
|
||||
#github = "github";
|
||||
#clientIdField = "clientId";
|
||||
#clientIdError = "#kc-client-secret-helper";
|
||||
#clientSecretField = "clientSecret";
|
||||
#clientIdError = "#config\\.clientSecret-helper";
|
||||
#clientSecretField = "config.clientSecret";
|
||||
#displayName = "displayName";
|
||||
#discoveryEndpoint = "discoveryEndpoint";
|
||||
#authorizationUrl = "config.authorizationUrl";
|
||||
|
|
|
@ -6,7 +6,7 @@ const masthead = new Masthead();
|
|||
export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
||||
#redirectUriGroup = ".pf-c-clipboard-copy__group";
|
||||
protected clientIdInput = "#kc-client-id";
|
||||
protected clientSecretInput = "#kc-client-secret";
|
||||
protected clientSecretInput = "config.clientSecret";
|
||||
#displayOrderInput = "#kc-display-order";
|
||||
#addBtn = "createProvider";
|
||||
#cancelBtn = "cancel";
|
||||
|
@ -22,12 +22,20 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
};
|
||||
|
||||
public typeClientId(clientId: string) {
|
||||
cy.get(this.clientIdInput).type(clientId).blur();
|
||||
if (clientId) {
|
||||
cy.get(this.clientIdInput).type(clientId);
|
||||
} else {
|
||||
cy.get(this.clientIdInput).clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public typeClientSecret(clientSecret: string) {
|
||||
cy.get(this.clientSecretInput).type(clientSecret).blur();
|
||||
if (clientSecret) {
|
||||
cy.findByTestId(this.clientSecretInput).type(clientSecret);
|
||||
} else {
|
||||
cy.findByTestId(this.clientSecretInput).clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -38,7 +46,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
}
|
||||
|
||||
public clickShowPassword() {
|
||||
cy.get(this.clientSecretInput).parent().find("button").click();
|
||||
cy.findByTestId(this.clientSecretInput).parent().find("button").click();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -68,12 +76,12 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
}
|
||||
|
||||
public assertClientSecretInputEqual(text: string) {
|
||||
cy.get(this.clientSecretInput).should("have.text", text);
|
||||
cy.findByTestId(this.clientSecretInput).should("have.text", text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public assertDisplayOrderInputEqual(text: string) {
|
||||
cy.get(this.clientSecretInput).should("have.text", text);
|
||||
cy.findByTestId(this.clientSecretInput).should("have.text", text);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -124,7 +132,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
|
|||
"have.value",
|
||||
this.testData["ClientId"] + idpName,
|
||||
);
|
||||
cy.get(this.clientSecretInput).should("contain.value", "****");
|
||||
cy.findByTestId(this.clientSecretInput).should("contain.value", "****");
|
||||
cy.get(this.#displayOrderInput).should(
|
||||
"have.value",
|
||||
this.testData["DisplayOrder"],
|
||||
|
|
|
@ -18,7 +18,7 @@ export default class ProviderPage {
|
|||
bindTypeInput = "#kc-bind-type";
|
||||
#bindTypeList = "#kc-bind-type + ul";
|
||||
bindDnInput = "config.bindDn.0";
|
||||
bindCredsInput = "ldap-bind-credentials";
|
||||
bindCredsInput = "config.bindCredential.0";
|
||||
#testConnectionBtn = "test-connection-button";
|
||||
#testAuthBtn = "test-auth-button";
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ export default class RealmSettingsPage extends CommonPage {
|
|||
#eventListenersSaveBtn = "saveEventListenerBtn";
|
||||
#eventListenersRevertBtn = "revertEventListenerBtn";
|
||||
#eventListenersInputFld = ".pf-c-form-control.pf-c-select__toggle-typeahead";
|
||||
#eventListenersDrpDwnOption = ".pf-c-select__menu-item";
|
||||
#eventListenersDrpDwnOption = ".pf-c-select__menu";
|
||||
#eventListenersDrwDwnSelect =
|
||||
".pf-c-button.pf-c-select__toggle-button.pf-m-plain";
|
||||
#eventListenerRemove = '[data-ouia-component-id="Remove"]';
|
||||
|
|
|
@ -10,11 +10,10 @@ import {
|
|||
import { useState } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PasswordInput } from "ui-shared";
|
||||
import { adminClient } from "../../admin-client";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
||||
import { PasswordInput } from "../../components/password-input/PasswordInput";
|
||||
import { useAccess } from "../../context/access/Access";
|
||||
import useFormatDate from "../../utils/useFormatDate";
|
||||
import { CopyToClipboardButton } from "../scopes/CopyToClipboardButton";
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import type KeyStoreConfig from "@keycloak/keycloak-admin-client/lib/defs/keystoreConfig";
|
||||
import { FormGroup } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HelpItem, TextControl } from "ui-shared";
|
||||
import { PasswordInput } from "../../components/password-input/PasswordInput";
|
||||
import { PasswordControl, TextControl } from "ui-shared";
|
||||
|
||||
export const StoreSettings = ({
|
||||
hidePassword = false,
|
||||
|
@ -13,10 +9,6 @@ export const StoreSettings = ({
|
|||
isSaml?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useFormContext<KeyStoreConfig>();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -29,26 +21,14 @@ export const StoreSettings = ({
|
|||
}}
|
||||
/>
|
||||
{!hidePassword && (
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name="keyPassword"
|
||||
label={t("keyPassword")}
|
||||
fieldId="keyPassword"
|
||||
isRequired
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("keyPasswordHelp")}
|
||||
fieldLabelId="keyPassword"
|
||||
/>
|
||||
}
|
||||
helperTextInvalid={t("required")}
|
||||
validated={errors.keyPassword ? "error" : "default"}
|
||||
>
|
||||
<PasswordInput
|
||||
data-testid="keyPassword"
|
||||
id="keyPassword"
|
||||
validated={errors.keyPassword ? "error" : "default"}
|
||||
{...register("keyPassword", { required: true })}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t("keyPasswordHelp")}
|
||||
rules={{
|
||||
required: t("required"),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isSaml && (
|
||||
<TextControl
|
||||
|
@ -57,26 +37,14 @@ export const StoreSettings = ({
|
|||
labelIcon={t("realmCertificateAliasHelp")}
|
||||
/>
|
||||
)}
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name="storePassword"
|
||||
label={t("storePassword")}
|
||||
fieldId="storePassword"
|
||||
isRequired
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("storePasswordHelp")}
|
||||
fieldLabelId="storePassword"
|
||||
/>
|
||||
}
|
||||
helperTextInvalid={t("required")}
|
||||
validated={errors.storePassword ? "error" : "default"}
|
||||
>
|
||||
<PasswordInput
|
||||
data-testid="storePassword"
|
||||
id="storePassword"
|
||||
validated={errors.storePassword ? "error" : "default"}
|
||||
{...register("storePassword", { required: true })}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t("storePasswordHelp")}
|
||||
rules={{
|
||||
required: t("required"),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { FormGroup } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "ui-shared";
|
||||
import { PasswordInput } from "../password-input/PasswordInput";
|
||||
import type { ComponentProps } from "./components";
|
||||
import { PasswordControl } from "ui-shared";
|
||||
import { convertToName } from "./DynamicComponents";
|
||||
import type { ComponentProps } from "./components";
|
||||
|
||||
export const PasswordComponent = ({
|
||||
name,
|
||||
|
@ -16,22 +12,17 @@ export const PasswordComponent = ({
|
|||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { register } = useFormContext();
|
||||
|
||||
return (
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name={convertToName(name!)}
|
||||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<PasswordInput
|
||||
id={name!}
|
||||
data-testid={name}
|
||||
isDisabled={isDisabled}
|
||||
defaultValue={defaultValue?.toString()}
|
||||
{...register(convertToName(name!))}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t(helpText!)}
|
||||
isDisabled={isDisabled}
|
||||
defaultValue={defaultValue?.toString()}
|
||||
rules={{
|
||||
required: { value: !!required, message: t("required") },
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ import { GeneralSettings } from "./GeneralSettings";
|
|||
export default function AddIdentityProvider() {
|
||||
const { t } = useTranslation();
|
||||
const { providerId } = useParams<IdentityProviderCreateParams>();
|
||||
const form = useForm<IdentityProviderRepresentation>();
|
||||
const form = useForm<IdentityProviderRepresentation>({ mode: "onChange" });
|
||||
const serverInfo = useServerInfo();
|
||||
|
||||
const providerInfo = useMemo(() => {
|
||||
|
@ -48,7 +48,7 @@ export default function AddIdentityProvider() {
|
|||
|
||||
const {
|
||||
handleSubmit,
|
||||
formState: { isDirty },
|
||||
formState: { isValid },
|
||||
} = form;
|
||||
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
@ -100,7 +100,7 @@ export default function AddIdentityProvider() {
|
|||
</FormProvider>
|
||||
<ActionGroup>
|
||||
<Button
|
||||
isDisabled={!isDirty}
|
||||
isDisabled={!isValid}
|
||||
variant="primary"
|
||||
type="submit"
|
||||
data-testid="createProvider"
|
||||
|
|
|
@ -2,10 +2,8 @@ import IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/
|
|||
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { HelpItem } from "ui-shared";
|
||||
import { HelpItem, PasswordControl } from "ui-shared";
|
||||
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
|
||||
import { PasswordInput } from "../../components/password-input/PasswordInput";
|
||||
|
||||
export const ClientIdSecret = ({
|
||||
secretRequired = true,
|
||||
|
@ -44,40 +42,13 @@ export const ClientIdSecret = ({
|
|||
{...register("config.clientId", { required: true })}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name="config.clientSecret"
|
||||
label={t("clientSecret")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("clientSecretHelp")}
|
||||
fieldLabelId="clientSecret"
|
||||
/>
|
||||
}
|
||||
fieldId="kc-client-secret"
|
||||
isRequired={secretRequired}
|
||||
validated={
|
||||
errors.config?.clientSecret
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={t("required")}
|
||||
>
|
||||
{create ? (
|
||||
<PasswordInput
|
||||
isRequired={secretRequired}
|
||||
id="kc-client-secret"
|
||||
data-testid="clientSecret"
|
||||
{...register("config.clientSecret", { required: secretRequired })}
|
||||
/>
|
||||
) : (
|
||||
<KeycloakTextInput
|
||||
isRequired={secretRequired}
|
||||
type="password"
|
||||
id="kc-client-secret"
|
||||
data-testid="clientSecret"
|
||||
{...register("config.clientSecret", { required: secretRequired })}
|
||||
/>
|
||||
)}
|
||||
</FormGroup>
|
||||
labelIcon={t("clientSecretHelp")}
|
||||
hasReveal={create}
|
||||
rules={{ required: { value: secretRequired, message: t("required") } }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,16 +13,21 @@ import {
|
|||
import { Controller, FormProvider, useForm, useWatch } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { FormPanel, HelpItem, SwitchControl, TextControl } from "ui-shared";
|
||||
import {
|
||||
FormPanel,
|
||||
SwitchControl,
|
||||
TextControl,
|
||||
PasswordControl,
|
||||
} from "ui-shared";
|
||||
import { adminClient } from "../admin-client";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { FormAccess } from "../components/form/FormAccess";
|
||||
import { PasswordInput } from "../components/password-input/PasswordInput";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { toUser } from "../user/routes/User";
|
||||
import { emailRegexPattern } from "../util";
|
||||
import { useCurrentUser } from "../utils/useCurrentUser";
|
||||
import useToggle from "../utils/useToggle";
|
||||
|
||||
import "./realm-settings-section.css";
|
||||
|
||||
type RealmSettingsEmailTabProps = {
|
||||
|
@ -42,15 +47,7 @@ export const RealmSettingsEmailTab = ({
|
|||
const currentUser = useCurrentUser();
|
||||
|
||||
const form = useForm<FormFields>({ defaultValues: realm });
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
reset: resetForm,
|
||||
getValues,
|
||||
formState: { errors },
|
||||
} = form;
|
||||
const { control, handleSubmit, watch, reset: resetForm, getValues } = form;
|
||||
|
||||
const reset = () => resetForm(realm);
|
||||
const watchFromValue = watch("smtpServer.from", "");
|
||||
|
@ -219,29 +216,14 @@ export const RealmSettingsEmailTab = ({
|
|||
required: t("required"),
|
||||
}}
|
||||
/>
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name="smtpServer.password"
|
||||
label={t("password")}
|
||||
fieldId="kc-username"
|
||||
isRequired
|
||||
validated={errors.smtpServer?.password ? "error" : "default"}
|
||||
helperTextInvalid={t("required")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("passwordHelp")}
|
||||
fieldLabelId="password"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PasswordInput
|
||||
id="kc-password"
|
||||
data-testid="password-input"
|
||||
aria-label={t("password")}
|
||||
validated={
|
||||
errors.smtpServer?.password ? "error" : "default"
|
||||
}
|
||||
{...register("smtpServer.password", { required: true })}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t("passwordHelp")}
|
||||
rules={{
|
||||
required: t("required"),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{currentUser && (
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
SelectOption,
|
||||
SelectVariant,
|
||||
Switch,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { get, isEqual } from "lodash-es";
|
||||
import { useState } from "react";
|
||||
|
@ -18,11 +17,10 @@ import {
|
|||
useWatch,
|
||||
} from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HelpItem, TextControl } from "ui-shared";
|
||||
import { HelpItem, PasswordControl, TextControl } from "ui-shared";
|
||||
import { adminClient } from "../../admin-client";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
import { FormAccess } from "../../components/form/FormAccess";
|
||||
import { PasswordInput } from "../../components/password-input/PasswordInput";
|
||||
import { WizardSectionHeader } from "../../components/wizard-section-header/WizardSectionHeader";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
|
||||
|
@ -264,38 +262,15 @@ export const LdapSettingsConnection = ({
|
|||
required: t("validateBindDn"),
|
||||
}}
|
||||
/>
|
||||
<FormGroup
|
||||
<PasswordControl
|
||||
name="config.bindCredential.0"
|
||||
label={t("bindCredentials")}
|
||||
labelIcon={
|
||||
<HelpItem
|
||||
helpText={t("bindCredentialsHelp")}
|
||||
fieldLabelId="bindCredentials"
|
||||
/>
|
||||
}
|
||||
fieldId="kc-ui-bind-credentials"
|
||||
helperTextInvalid={t("validateBindCredentials")}
|
||||
validated={
|
||||
(form.formState.errors.config as any)?.bindCredential
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
isRequired
|
||||
>
|
||||
<PasswordInput
|
||||
hasReveal={!edit}
|
||||
isRequired
|
||||
id="kc-ui-bind-credentials"
|
||||
data-testid="ldap-bind-credentials"
|
||||
validated={
|
||||
(form.formState.errors.config as any)?.bindCredential
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
{...form.register("config.bindCredential.0", {
|
||||
required: true,
|
||||
})}
|
||||
/>
|
||||
</FormGroup>
|
||||
labelIcon={t("bindCredentialsHelp")}
|
||||
hasReveal={!edit}
|
||||
rules={{
|
||||
required: t("validateBindCredentials"),
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<FormGroup fieldId="kc-test-auth-button">
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "@patternfly/react-core";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { PasswordInput } from "ui-shared";
|
||||
import { adminClient } from "../../admin-client";
|
||||
import { DefaultSwitchControl } from "../../components/SwitchControl";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
|
@ -16,7 +17,6 @@ import {
|
|||
ConfirmDialogModal,
|
||||
useConfirmDialog,
|
||||
} from "../../components/confirm-dialog/ConfirmDialog";
|
||||
import { PasswordInput } from "../../components/password-input/PasswordInput";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
|
||||
type ResetPasswordDialogProps = {
|
||||
|
|
60
js/libs/ui-shared/src/controls/PasswordControl.tsx
Normal file
60
js/libs/ui-shared/src/controls/PasswordControl.tsx
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { ValidatedOptions } from "@patternfly/react-core";
|
||||
import {
|
||||
FieldPath,
|
||||
FieldValues,
|
||||
PathValue,
|
||||
UseControllerProps,
|
||||
useController,
|
||||
} from "react-hook-form";
|
||||
import { FormLabel } from "./FormLabel";
|
||||
import { PasswordInput, PasswordInputProps } from "./PasswordInput";
|
||||
|
||||
export type PasswordControlProps<
|
||||
T extends FieldValues,
|
||||
P extends FieldPath<T> = FieldPath<T>,
|
||||
> = UseControllerProps<T, P> &
|
||||
Omit<PasswordInputProps, "name" | "isRequired" | "required"> & {
|
||||
label: string;
|
||||
labelIcon?: string;
|
||||
isDisabled?: boolean;
|
||||
helperText?: string;
|
||||
};
|
||||
|
||||
export const PasswordControl = <
|
||||
T extends FieldValues,
|
||||
P extends FieldPath<T> = FieldPath<T>,
|
||||
>(
|
||||
props: PasswordControlProps<T, P>,
|
||||
) => {
|
||||
const { labelIcon, ...rest } = props;
|
||||
const required = !!props.rules?.required;
|
||||
const defaultValue = props.defaultValue ?? ("" as PathValue<T, P>);
|
||||
|
||||
const { field, fieldState } = useController({
|
||||
...props,
|
||||
defaultValue,
|
||||
});
|
||||
|
||||
return (
|
||||
<FormLabel
|
||||
name={props.name}
|
||||
label={props.label}
|
||||
labelIcon={labelIcon}
|
||||
isRequired={required}
|
||||
error={fieldState.error}
|
||||
helperText={props.helperText}
|
||||
>
|
||||
<PasswordInput
|
||||
isRequired={required}
|
||||
id={props.name}
|
||||
data-testid={props.name}
|
||||
validated={
|
||||
fieldState.error ? ValidatedOptions.error : ValidatedOptions.default
|
||||
}
|
||||
isDisabled={props.isDisabled}
|
||||
{...rest}
|
||||
{...field}
|
||||
/>
|
||||
</FormLabel>
|
||||
);
|
||||
};
|
|
@ -1,14 +1,13 @@
|
|||
import { forwardRef, MutableRefObject, Ref, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, InputGroup } from "@patternfly/react-core";
|
||||
import { EyeIcon, EyeSlashIcon } from "@patternfly/react-icons";
|
||||
|
||||
import { forwardRef, MutableRefObject, Ref, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
KeycloakTextInput,
|
||||
KeycloakTextInputProps,
|
||||
} from "../keycloak-text-input/KeycloakTextInput";
|
||||
|
||||
type PasswordInputProps = KeycloakTextInputProps & {
|
||||
export type PasswordInputProps = KeycloakTextInputProps & {
|
||||
hasReveal?: boolean;
|
||||
};
|
||||
|
|
@ -28,3 +28,5 @@ export {
|
|||
export type { UserFormFields } from "./user-profile/utils";
|
||||
export { ScrollForm, mainPageContentId } from "./scroll-form/ScrollForm";
|
||||
export { FormPanel } from "./scroll-form/FormPanel";
|
||||
export { PasswordControl } from "./controls/PasswordControl";
|
||||
export { PasswordInput } from "./controls/PasswordInput";
|
||||
|
|
Loading…
Reference in a new issue