migrated to use ui-shared (#27849)

* migrated to use ui-shared

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fixed tests

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fixed tests

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

---------

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
Erik Jan de Wit 2024-03-22 14:07:25 +01:00 committed by GitHub
parent c3a98ae387
commit 4fb2f73b2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 77 additions and 168 deletions

View file

@ -237,8 +237,8 @@ describe("Realm settings events tab tests", () => {
it("Realm header settings", () => {
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-security-defenses-tab").click();
cy.findByTestId("headers-form-tab-save").should("be.disabled");
cy.get("#xFrameOptions").clear().type("DENY");
cy.findByTestId("browserSecurityHeaders.xFrameOptions").clear();
cy.findByTestId("browserSecurityHeaders.xFrameOptions").type("DENY");
cy.findByTestId("headers-form-tab-save").should("be.enabled").click();
masthead.checkNotificationMessage("Realm successfully updated");
@ -249,8 +249,6 @@ describe("Realm settings events tab tests", () => {
cy.findAllByTestId("rs-security-defenses-tab").click();
cy.get("#pf-tab-20-bruteForce").click();
cy.findByTestId("brute-force-tab-save").should("be.disabled");
cy.get("#kc-brute-force-mode").click();
cy.findByTestId("select-brute-force-mode")
.contains("Lockout temporarily")

View file

@ -136,7 +136,8 @@ describe("Realm settings tabs tests", () => {
it("Realm header settings- update single input", () => {
sidebarPage.goToRealmSettings();
realmSettingsPage.goToSecurityDefensesTab();
cy.get("#xFrameOptions").clear().type("DENY");
cy.findByTestId("browserSecurityHeaders.xFrameOptions").clear();
cy.findByTestId("browserSecurityHeaders.xFrameOptions").type("DENY");
realmSettingsPage.saveSecurityDefensesHeaders();
masthead.checkNotificationMessage("Realm successfully updated");
});
@ -144,14 +145,34 @@ describe("Realm settings tabs tests", () => {
it("Realm header settings- update all inputs", () => {
sidebarPage.goToRealmSettings();
realmSettingsPage.goToSecurityDefensesTab();
cy.get("#xFrameOptions").clear().type("SAMEORIGIN");
cy.get("#contentSecurityPolicy").clear().type("default-src 'self'");
cy.get("#strictTransportSecurity").clear().type("max-age=31536000");
cy.get("#xContentTypeOptions").clear().type("nosniff");
cy.get("#xRobotsTag").clear().type("none");
cy.get("#xXSSProtection").clear().type("1; mode=block");
cy.get("#strictTransportSecurity").clear().type("max-age=31537000");
cy.get("#referrerPolicy").clear().type("referrer");
cy.findByTestId("browserSecurityHeaders.xFrameOptions").clear();
cy.findByTestId("browserSecurityHeaders.xFrameOptions").type(
"SAMEORIGIN",
);
cy.findByTestId("browserSecurityHeaders.contentSecurityPolicy").clear();
cy.findByTestId("browserSecurityHeaders.contentSecurityPolicy").type(
"default-src 'self'",
);
cy.findByTestId("browserSecurityHeaders.strictTransportSecurity").clear();
cy.findByTestId("browserSecurityHeaders.strictTransportSecurity").type(
"max-age=31536000",
);
cy.findByTestId("browserSecurityHeaders.xContentTypeOptions").clear();
cy.findByTestId("browserSecurityHeaders.xContentTypeOptions").type(
"nosniff",
);
cy.findByTestId("browserSecurityHeaders.xRobotsTag").clear();
cy.findByTestId("browserSecurityHeaders.xRobotsTag").type("none");
cy.findByTestId("browserSecurityHeaders.xXSSProtection").clear();
cy.findByTestId("browserSecurityHeaders.xXSSProtection").type(
"1; mode=block",
);
cy.findByTestId("browserSecurityHeaders.strictTransportSecurity").clear();
cy.findByTestId("browserSecurityHeaders.strictTransportSecurity").type(
"max-age=31537000",
);
cy.findByTestId("browserSecurityHeaders.referrerPolicy").clear();
cy.findByTestId("browserSecurityHeaders.referrerPolicy").type("referrer");
realmSettingsPage.saveSecurityDefensesHeaders();
masthead.checkNotificationMessage("Realm successfully updated");
});

View file

@ -3,17 +3,15 @@ import {
ActionGroup,
Button,
FormGroup,
NumberInput,
Select,
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import { useEffect, useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem, NumberControl } from "ui-shared";
import { FormAccess } from "../../components/form/FormAccess";
import { HelpItem } from "ui-shared";
import { convertToFormValues } from "../../util";
import { Time } from "./Time";
@ -31,7 +29,6 @@ export const BruteForceDetection = ({
const {
setValue,
handleSubmit,
control,
formState: { isDirty },
} = form;
@ -131,74 +128,26 @@ export const BruteForceDetection = ({
</FormGroup>
{bruteForceMode !== BruteForceMode.Disabled && (
<>
<FormGroup
<NumberControl
name="failureFactor"
label={t("failureFactor")}
labelIcon={
<HelpItem
helpText={t("failureFactorHelp")}
fieldLabelId="failureFactor"
/>
}
fieldId="failureFactor"
>
<Controller
name="failureFactor"
defaultValue={0}
control={control}
rules={{ required: true }}
render={({ field }) => (
<NumberInput
type="text"
id="failureFactor"
value={field.value}
onPlus={() => field.onChange(field.value + 1)}
onMinus={() => field.onChange(field.value - 1)}
onChange={(event) =>
field.onChange(
Number((event.target as HTMLInputElement).value),
)
}
/>
)}
/>
</FormGroup>
labelIcon={t("failureFactorHelp")}
controller={{
defaultValue: 0,
rules: { required: t("required") },
}}
/>
{bruteForceMode ===
BruteForceMode.PermanentAfterTemporaryLockout && (
<FormGroup
<NumberControl
name="maxTemporaryLockouts"
label={t("maxTemporaryLockouts")}
labelIcon={
<HelpItem
helpText={t("maxTemporaryLockoutsHelp")}
fieldLabelId="maxTemporaryLockouts"
/>
}
fieldId="maxTemporaryLockouts"
hasNoPaddingTop
>
<Controller
name="maxTemporaryLockouts"
defaultValue={0}
control={control}
render={({ field }) => (
<NumberInput
type="text"
id="maxTemporaryLockouts"
value={field.value}
onPlus={() => field.onChange(field.value + 1)}
onMinus={() => field.onChange(field.value - 1)}
onChange={(event) =>
field.onChange(
Number((event.target as HTMLInputElement).value),
)
}
aria-label={t("maxTemporaryLockouts")}
/>
)}
/>
</FormGroup>
labelIcon={t("maxTemporaryLockoutsHelp")}
controller={{
defaultValue: 0,
}}
/>
)}
{(bruteForceMode === BruteForceMode.TemporaryLockout ||
bruteForceMode ===
BruteForceMode.PermanentAfterTemporaryLockout) && (
@ -208,38 +157,14 @@ export const BruteForceDetection = ({
<Time name="maxDeltaTimeSeconds" />
</>
)}
<FormGroup
<NumberControl
name="quickLoginCheckMilliSeconds"
label={t("quickLoginCheckMilliSeconds")}
labelIcon={
<HelpItem
helpText={t("quickLoginCheckMilliSecondsHelp")}
fieldLabelId="quickLoginCheckMilliSeconds"
/>
}
fieldId="quickLoginCheckMilliSeconds"
>
<Controller
name="quickLoginCheckMilliSeconds"
defaultValue={0}
control={control}
render={({ field }) => (
<NumberInput
type="text"
id="quickLoginCheckMilliSeconds"
value={field.value}
onPlus={() => field.onChange(field.value + 1)}
onMinus={() => field.onChange(field.value - 1)}
onChange={(event) =>
field.onChange(
Number((event.target as HTMLInputElement).value),
)
}
/>
)}
/>
</FormGroup>
labelIcon={t("quickLoginCheckMilliSecondsHelp")}
controller={{
defaultValue: 0,
}}
/>
<Time name="minimumQuickLoginWaitSeconds" />
</>
)}

View file

@ -1,10 +1,6 @@
import { FormGroup } from "@patternfly/react-core";
import { useFormContext } from "react-hook-form";
import { Trans, useTranslation } from "react-i18next";
import { TextControl } from "ui-shared";
import { FormattedLink } from "../../components/external-link/FormattedLink";
import { HelpItem } from "ui-shared";
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
type HelpLinkTextInputProps = {
fieldName: string;
@ -16,25 +12,17 @@ export const HelpLinkTextInput = ({
url,
}: HelpLinkTextInputProps) => {
const { t } = useTranslation();
const { register } = useFormContext();
const name = fieldName.substr(fieldName.indexOf(".") + 1);
return (
<FormGroup
<TextControl
name={fieldName}
label={t(name)}
fieldId={name}
labelIcon={
<HelpItem
helpText={
<Trans i18nKey={`${name}Help`}>
Default value prevents pages from being included
<FormattedLink href={url} title={t("learnMore")} />
</Trans>
}
fieldLabelId={name}
/>
<Trans i18nKey={`${name}Help`}>
Default value prevents pages from being included
<FormattedLink href={url} title={t("learnMore")} />
</Trans>
}
>
<KeycloakTextInput id={name} {...register(fieldName)} />
</FormGroup>
/>
);
};

View file

@ -1,10 +1,7 @@
import { FormGroup, ValidatedOptions } from "@patternfly/react-core";
import { CSSProperties } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { HelpItem } from "ui-shared";
import { TimeSelector } from "../../components/time-selector/TimeSelector";
import { TimeSelectorControl } from "../../components/time-selector/TimeSelectorControl";
export const Time = ({
name,
@ -14,37 +11,16 @@ export const Time = ({
style?: CSSProperties;
}) => {
const { t } = useTranslation();
const {
control,
formState: { errors },
} = useFormContext();
return (
<FormGroup
<TimeSelectorControl
name={name}
style={style}
label={t(name)}
fieldId={name}
labelIcon={<HelpItem helpText={t(`${name}Help`)} fieldLabelId={name} />}
validated={
errors[name] ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("required")}
>
<Controller
name={name}
defaultValue=""
control={control}
rules={{ required: true }}
render={({ field }) => (
<TimeSelector
data-testid={name}
value={field.value}
onChange={field.onChange}
validated={
errors[name] ? ValidatedOptions.error : ValidatedOptions.default
}
/>
)}
/>
</FormGroup>
labelIcon={t(`${name}Help`)}
controller={{
defaultValue: "",
rules: { required: t("required") },
}}
/>
);
};

View file

@ -3,14 +3,14 @@ import {
FormGroupProps,
ValidatedOptions,
} from "@patternfly/react-core";
import { PropsWithChildren } from "react";
import { PropsWithChildren, ReactNode } from "react";
import { FieldError, FieldValues, Merge } from "react-hook-form";
import { HelpItem } from "./HelpItem";
export type FieldProps<T extends FieldValues = FieldValues> = {
label?: string;
name: string;
labelIcon?: string;
labelIcon?: string | ReactNode;
error?: FieldError | Merge<FieldError, T>;
isRequired: boolean;
};

View file

@ -9,6 +9,7 @@ import {
import { KeycloakTextInput } from "../keycloak-text-input/KeycloakTextInput";
import { FormLabel } from "./FormLabel";
import { ReactNode } from "react";
export type TextControlProps<
T extends FieldValues,
@ -16,7 +17,7 @@ export type TextControlProps<
> = UseControllerProps<T, P> &
Omit<TextInputProps, "name" | "isRequired" | "required"> & {
label: string;
labelIcon?: string;
labelIcon?: string | ReactNode;
isDisabled?: boolean;
helperText?: string;
};