Replace text areas with KeycloakTextArea (#2617)

This commit is contained in:
Jon Koops 2022-05-11 11:46:14 +02:00 committed by GitHub
parent 9b0af12bd6
commit 960da1b849
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 59 additions and 31 deletions

View file

@ -1,10 +1,11 @@
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, TextArea, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
export const NameDescription = () => { export const NameDescription = () => {
const { t } = useTranslation("authentication"); const { t } = useTranslation("authentication");
@ -52,7 +53,7 @@ export const NameDescription = () => {
} }
helperTextInvalid={errors.description?.message} helperTextInvalid={errors.description?.message}
> >
<TextArea <KeycloakTextArea
ref={register({ ref={register({
maxLength: { maxLength: {
value: 255, value: 255,

View file

@ -11,7 +11,6 @@ import {
Switch, Switch,
ActionGroup, ActionGroup,
Button, Button,
TextArea,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation"; import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
@ -28,6 +27,7 @@ import { getProtocolName } from "../../clients/utils";
import { toClientScopes } from "../routes/ClientScopes"; import { toClientScopes } from "../routes/ClientScopes";
import { FormAccess } from "../../components/form-access/FormAccess"; import { FormAccess } from "../../components/form-access/FormAccess";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
type ScopeFormProps = { type ScopeFormProps = {
clientScope: ClientScopeRepresentation; clientScope: ClientScopeRepresentation;
@ -236,7 +236,7 @@ export const ScopeForm = ({ clientScope, save }: ScopeFormProps) => {
} }
fieldId="kc-consent-screen-text" fieldId="kc-consent-screen-text"
> >
<TextArea <KeycloakTextArea
ref={register} ref={register}
type="text" type="text"
id="kc-consent-screen-text" id="kc-consent-screen-text"

View file

@ -1,17 +1,13 @@
import React from "react"; import React from "react";
import { Controller, useFormContext } from "react-hook-form"; import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
FormGroup,
Switch,
TextArea,
ValidatedOptions,
} from "@patternfly/react-core";
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation"; import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem"; import { HelpItem } from "../components/help-enabler/HelpItem";
import { FormAccess } from "../components/form-access/FormAccess"; import { FormAccess } from "../components/form-access/FormAccess";
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
type ClientDescriptionProps = { type ClientDescriptionProps = {
protocol?: string; protocol?: string;
@ -76,7 +72,7 @@ export const ClientDescription = ({ protocol }: ClientDescriptionProps) => {
} }
helperTextInvalid={errors.description?.message} helperTextInvalid={errors.description?.message}
> >
<TextArea <KeycloakTextArea
ref={register({ ref={register({
maxLength: { maxLength: {
value: 255, value: 255,

View file

@ -5,7 +5,6 @@ import {
FormGroup, FormGroup,
Form, Form,
Switch, Switch,
TextArea,
Select, Select,
SelectVariant, SelectVariant,
SelectOption, SelectOption,
@ -20,6 +19,7 @@ import { MultiLineInput } from "../components/multi-line-input/MultiLineInput";
import { FormAccess } from "../components/form-access/FormAccess"; import { FormAccess } from "../components/form-access/FormAccess";
import { HelpItem } from "../components/help-enabler/HelpItem"; import { HelpItem } from "../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { SaveReset } from "./advanced/SaveReset"; import { SaveReset } from "./advanced/SaveReset";
import { SamlConfig } from "./add/SamlConfig"; import { SamlConfig } from "./add/SamlConfig";
@ -356,7 +356,7 @@ export const ClientSettings = ({
} }
fieldId="kc-consent-screen-text" fieldId="kc-consent-screen-text"
> >
<TextArea <KeycloakTextArea
id="kc-consent-screen-text" id="kc-consent-screen-text"
name="attributes.consent.screen.text" name="attributes.consent.screen.text"
ref={register} ref={register}

View file

@ -5,7 +5,6 @@ import {
PageSection, PageSection,
ActionGroup, ActionGroup,
Button, Button,
TextArea,
AlertVariant, AlertVariant,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
@ -19,6 +18,7 @@ import { useAlerts } from "../../components/alert/Alerts";
import type { ClientParams } from "../routes/Client"; import type { ClientParams } from "../routes/Client";
import type ResourceServerRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceServerRepresentation"; import type ResourceServerRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceServerRepresentation";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
import "./authorization-details.css"; import "./authorization-details.css";
@ -76,7 +76,7 @@ export const AuthorizationExport = () => {
} }
fieldId="client" fieldId="client"
> >
<TextArea <KeycloakTextArea
id="authorizationDetails" id="authorizationDetails"
readOnly readOnly
resizeOrientation="vertical" resizeOrientation="vertical"

View file

@ -13,7 +13,6 @@ import {
Radio, Radio,
SelectVariant, SelectVariant,
Switch, Switch,
TextArea,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import type PolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/policyRepresentation"; import type PolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/policyRepresentation";
@ -34,6 +33,7 @@ import { ScopeSelect } from "./ScopeSelect";
import { toUpperCase } from "../../util"; import { toUpperCase } from "../../util";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
const DECISION_STRATEGIES = ["UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"] as const; const DECISION_STRATEGIES = ["UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"] as const;
@ -230,7 +230,7 @@ export default function PermissionDetails() {
validated={errors.description ? "error" : "default"} validated={errors.description ? "error" : "default"}
helperTextInvalid={errors.description?.message} helperTextInvalid={errors.description?.message}
> >
<TextArea <KeycloakTextArea
id="description" id="description"
name="description" name="description"
ref={register({ ref={register({

View file

@ -1,10 +1,11 @@
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, TextArea, ValidatedOptions } from "@patternfly/react-core"; import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { HelpItem } from "../../../components/help-enabler/HelpItem"; import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../../../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../../../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../../../components/keycloak-text-area/KeycloakTextArea";
type NameDescriptionProps = { type NameDescriptionProps = {
prefix: string; prefix: string;
@ -59,7 +60,7 @@ export const NameDescription = ({ prefix }: NameDescriptionProps) => {
} }
helperTextInvalid={errors.description?.message} helperTextInvalid={errors.description?.message}
> >
<TextArea <KeycloakTextArea
ref={register({ ref={register({
maxLength: { maxLength: {
value: 255, value: 255,

View file

@ -1,9 +1,10 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FormGroup, GenerateId, TextArea } from "@patternfly/react-core"; import { FormGroup, GenerateId } from "@patternfly/react-core";
import type CertificateRepresentation from "@keycloak/keycloak-admin-client/lib/defs/certificateRepresentation"; import type CertificateRepresentation from "@keycloak/keycloak-admin-client/lib/defs/certificateRepresentation";
import { HelpItem } from "../../components/help-enabler/HelpItem"; import { HelpItem } from "../../components/help-enabler/HelpItem";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
type CertificateProps = Omit<CertificateDisplayProps, "id"> & { type CertificateProps = Omit<CertificateDisplayProps, "id"> & {
plain?: boolean; plain?: boolean;
@ -15,7 +16,7 @@ type CertificateDisplayProps = {
}; };
const CertificateDisplay = ({ id, keyInfo }: CertificateDisplayProps) => ( const CertificateDisplay = ({ id, keyInfo }: CertificateDisplayProps) => (
<TextArea <KeycloakTextArea
readOnly readOnly
rows={5} rows={5}
id={id} id={id}

View file

@ -5,12 +5,12 @@ import {
CodeBlockAction, CodeBlockAction,
EmptyState, EmptyState,
EmptyStateBody, EmptyStateBody,
TextArea,
Title, Title,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import { CopyToClipboardButton } from "./CopyToClipboardButton"; import { CopyToClipboardButton } from "./CopyToClipboardButton";
import { KeycloakTextArea } from "../../components/keycloak-text-area/KeycloakTextArea";
type GeneratedCodeTabProps = { type GeneratedCodeTabProps = {
user?: UserRepresentation; user?: UserRepresentation;
@ -34,7 +34,7 @@ export const GeneratedCodeTab = ({
</CodeBlockAction> </CodeBlockAction>
} }
> >
<TextArea id={`text-area-${label}`} rows={20} value={text} /> <KeycloakTextArea id={`text-area-${label}`} rows={20} value={text} />
</CodeBlock> </CodeBlock>
) : ( ) : (
<EmptyState variant="large"> <EmptyState variant="large">

View file

@ -9,7 +9,6 @@ import {
SelectVariant, SelectVariant,
Stack, Stack,
StackItem, StackItem,
TextArea,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import FileSaver from "file-saver"; import FileSaver from "file-saver";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
@ -20,6 +19,7 @@ import { prettyPrintJSON } from "../../util";
import { ConfirmDialogModal } from "../confirm-dialog/ConfirmDialog"; import { ConfirmDialogModal } from "../confirm-dialog/ConfirmDialog";
import { useHelp } from "../help-enabler/HelpHeader"; import { useHelp } from "../help-enabler/HelpHeader";
import { HelpItem } from "../help-enabler/HelpItem"; import { HelpItem } from "../help-enabler/HelpItem";
import { KeycloakTextArea } from "../keycloak-text-area/KeycloakTextArea";
type DownloadDialogProps = { type DownloadDialogProps = {
id: string; id: string;
@ -158,7 +158,7 @@ export const DownloadDialog = ({
/> />
} }
> >
<TextArea <KeycloakTextArea
id="details" id="details"
readOnly readOnly
rows={12} rows={12}

View file

@ -0,0 +1,29 @@
import { TextArea, TextAreaProps } from "@patternfly/react-core";
import React, { ComponentProps, forwardRef, HTMLProps } from "react";
// PatternFly changes the signature of the 'onChange' handler for textarea elements.
// This causes issues with React Hook Form as it expects the default signature for a textarea element.
// So we have to create this wrapper component that takes care of converting these signatures for us.
export type KeycloakTextAreaProps = Omit<
ComponentProps<typeof TextArea>,
"onChange"
> &
Pick<HTMLProps<HTMLTextAreaElement>, "onChange">;
export const KeycloakTextArea = forwardRef<
// TODO: This is typed incorrectly and will have to be replaced with 'HTMLTextAreaElement'.
// More information: https://github.com/patternfly/patternfly-react/pull/7397
HTMLInputElement,
KeycloakTextAreaProps
>(({ onChange, ...props }, ref) => {
const onChangeForward: TextAreaProps["onChange"] = (_, event) =>
onChange?.(event);
return <TextArea {...props} ref={ref} onChange={onChangeForward} />;
});
// We need to fake the displayName to match what PatternFly expects.
// This is because PatternFly uses it to filter children in certain aspects.
// This is a stupid approach, but it's not like we can change that.
KeycloakTextArea.displayName = "TextArea";

View file

@ -4,7 +4,6 @@ import {
Button, Button,
FormGroup, FormGroup,
PageSection, PageSection,
TextArea,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -13,6 +12,7 @@ import { ViewHeader } from "../components/view-header/ViewHeader";
import { FormAccess } from "../components/form-access/FormAccess"; import { FormAccess } from "../components/form-access/FormAccess";
import type { AttributeForm } from "../components/key-value-form/AttributeForm"; import type { AttributeForm } from "../components/key-value-form/AttributeForm";
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -72,7 +72,7 @@ export const RealmRoleForm = ({
} }
helperTextInvalid={errors.description?.message} helperTextInvalid={errors.description?.message}
> >
<TextArea <KeycloakTextArea
name="description" name="description"
aria-label="description" aria-label="description"
isDisabled={getValues().name?.includes("default-roles")} isDisabled={getValues().name?.includes("default-roles")}

View file

@ -16,7 +16,6 @@ import {
FormGroup, FormGroup,
PageSection, PageSection,
Text, Text,
TextArea,
TextVariants, TextVariants,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
@ -30,6 +29,7 @@ import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation"; import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem"; import { HelpItem } from "../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
import { PlusCircleIcon, TrashIcon } from "@patternfly/react-icons"; import { PlusCircleIcon, TrashIcon } from "@patternfly/react-icons";
import "./realm-settings-section.css"; import "./realm-settings-section.css";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
@ -247,7 +247,7 @@ export default function ClientProfileForm() {
/> />
</FormGroup> </FormGroup>
<FormGroup label={t("common:description")} fieldId="kc-description"> <FormGroup label={t("common:description")} fieldId="kc-description">
<TextArea <KeycloakTextArea
ref={register()} ref={register()}
name="description" name="description"
type="text" type="text"

View file

@ -16,7 +16,6 @@ import {
FormGroup, FormGroup,
PageSection, PageSection,
Text, Text,
TextArea,
TextVariants, TextVariants,
ValidatedOptions, ValidatedOptions,
} from "@patternfly/react-core"; } from "@patternfly/react-core";
@ -30,6 +29,7 @@ import { useAlerts } from "../components/alert/Alerts";
import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { HelpItem } from "../components/help-enabler/HelpItem"; import { HelpItem } from "../components/help-enabler/HelpItem";
import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput"; import { KeycloakTextInput } from "../components/keycloak-text-input/KeycloakTextInput";
import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextArea";
import { PlusCircleIcon, TrashIcon } from "@patternfly/react-icons"; import { PlusCircleIcon, TrashIcon } from "@patternfly/react-icons";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyRepresentation"; import type ClientPolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientPolicyRepresentation";
@ -475,7 +475,7 @@ export default function NewClientPolicyForm() {
/> />
</FormGroup> </FormGroup>
<FormGroup label={t("common:description")} fieldId="kc-description"> <FormGroup label={t("common:description")} fieldId="kc-description">
<TextArea <KeycloakTextArea
name="description" name="description"
aria-label={t("description")} aria-label={t("description")}
ref={form.register()} ref={form.register()}