Realm settings(Email): Adds email tab to realm settings section (#549)
* email tab wip * save username and pw info on auth toggle * add email tab * remove comments * remove log stmt * add help text * adjust styles * format * fix conflicts and address PR feedback * add back ref on reply to display name * rebase and fix conflicts * prevent save without sender email * add className prop to formpanel
This commit is contained in:
parent
78f843cdcc
commit
15677b6bfb
11 changed files with 603 additions and 230 deletions
|
@ -8,12 +8,6 @@ describe("Realm settings test", () => {
|
||||||
const sidebarPage = new SidebarPage();
|
const sidebarPage = new SidebarPage();
|
||||||
const realmSettingsPage = new RealmSettingsPage();
|
const realmSettingsPage = new RealmSettingsPage();
|
||||||
|
|
||||||
const managedAccessSwitch = "user-managed-access-switch";
|
|
||||||
const userRegSwitch = "user-reg-switch";
|
|
||||||
const forgotPwdSwitch = "forgot-pw-switch";
|
|
||||||
const rememberMeSwitch = "remember-me-switch";
|
|
||||||
const verifyEmailSwitch = "verify-email-switch";
|
|
||||||
|
|
||||||
describe("Realm settings", function () {
|
describe("Realm settings", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
keycloakBefore();
|
keycloakBefore();
|
||||||
|
@ -22,19 +16,33 @@ describe("Realm settings test", () => {
|
||||||
|
|
||||||
it("Go to general tab", function () {
|
it("Go to general tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
realmSettingsPage.toggleSwitch(managedAccessSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
||||||
realmSettingsPage.saveGeneral();
|
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
||||||
realmSettingsPage.toggleSwitch(managedAccessSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.managedAccessSwitch);
|
||||||
realmSettingsPage.saveGeneral();
|
realmSettingsPage.save(realmSettingsPage.generalSaveBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Go to login tab", function () {
|
it("Go to login tab", function () {
|
||||||
sidebarPage.goToRealmSettings();
|
sidebarPage.goToRealmSettings();
|
||||||
cy.getId("rs-login-tab").click();
|
cy.getId("rs-login-tab").click();
|
||||||
realmSettingsPage.toggleSwitch(userRegSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.userRegSwitch);
|
||||||
realmSettingsPage.toggleSwitch(forgotPwdSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.forgotPwdSwitch);
|
||||||
realmSettingsPage.toggleSwitch(rememberMeSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.rememberMeSwitch);
|
||||||
realmSettingsPage.toggleSwitch(verifyEmailSwitch);
|
realmSettingsPage.toggleSwitch(realmSettingsPage.verifyEmailSwitch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Go to email tab", function () {
|
||||||
|
sidebarPage.goToRealmSettings();
|
||||||
|
cy.getId("rs-email-tab").click();
|
||||||
|
|
||||||
|
realmSettingsPage.addSenderEmail("example@example.com");
|
||||||
|
|
||||||
|
cy.wait(100);
|
||||||
|
|
||||||
|
realmSettingsPage.toggleCheck(realmSettingsPage.enableSslCheck);
|
||||||
|
realmSettingsPage.toggleCheck(realmSettingsPage.enableStartTlsCheck);
|
||||||
|
|
||||||
|
realmSettingsPage.save(realmSettingsPage.emailSaveBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Go to themes tab", function () {
|
it("Go to themes tab", function () {
|
||||||
|
@ -42,7 +50,7 @@ describe("Realm settings test", () => {
|
||||||
cy.getId("rs-themes-tab").click();
|
cy.getId("rs-themes-tab").click();
|
||||||
realmSettingsPage.selectLoginThemeType("keycloak");
|
realmSettingsPage.selectLoginThemeType("keycloak");
|
||||||
realmSettingsPage.selectAccountThemeType("keycloak");
|
realmSettingsPage.selectAccountThemeType("keycloak");
|
||||||
realmSettingsPage.selectAdminThemeType("keycloak.v2");
|
realmSettingsPage.selectAdminThemeType("base");
|
||||||
realmSettingsPage.selectEmailThemeType("base");
|
realmSettingsPage.selectEmailThemeType("base");
|
||||||
|
|
||||||
realmSettingsPage.saveThemes();
|
realmSettingsPage.saveThemes();
|
||||||
|
|
|
@ -1,33 +1,30 @@
|
||||||
export default class RealmSettingsPage {
|
export default class RealmSettingsPage {
|
||||||
saveBtnGeneral: string;
|
generalSaveBtn = "general-tab-save";
|
||||||
saveBtnThemes: string;
|
themesSaveBtn = "themes-tab-save";
|
||||||
loginTab: string;
|
loginTab = "rs-login-tab";
|
||||||
selectLoginTheme: string;
|
selectLoginTheme = "#kc-login-theme";
|
||||||
loginThemeList: string;
|
loginThemeList = "#kc-login-theme + ul";
|
||||||
selectAccountTheme: string;
|
selectAccountTheme = "#kc-account-theme";
|
||||||
accountThemeList: string;
|
accountThemeList = "#kc-account-theme + ul";
|
||||||
selectAdminTheme: string;
|
selectAdminTheme = "#kc-admin-console-theme";
|
||||||
adminThemeList: string;
|
adminThemeList = "#kc-admin-console-theme + ul";
|
||||||
selectEmailTheme: string;
|
selectEmailTheme = "#kc-email-theme";
|
||||||
emailThemeList: string;
|
emailThemeList = "#kc-email-theme + ul";
|
||||||
selectDefaultLocale: string;
|
selectDefaultLocale = "select-default-locale";
|
||||||
defaultLocaleList: string;
|
defaultLocaleList = "select-default-locale + ul";
|
||||||
|
emailSaveBtn = "email-tab-save";
|
||||||
constructor() {
|
managedAccessSwitch = "user-managed-access-switch";
|
||||||
this.saveBtnGeneral = "general-tab-save";
|
userRegSwitch = "user-reg-switch";
|
||||||
this.saveBtnThemes = "themes-tab-save";
|
forgotPwdSwitch = "forgot-pw-switch";
|
||||||
this.loginTab = "rs-login-tab";
|
rememberMeSwitch = "remember-me-switch";
|
||||||
this.selectLoginTheme = "#kc-login-theme";
|
emailAsUsernameSwitch = "email-as-username-switch";
|
||||||
this.loginThemeList = "#kc-login-theme + ul";
|
loginWithEmailSwitch = "login-with-email-switch";
|
||||||
this.selectAccountTheme = "#kc-account-theme";
|
duplicateEmailsSwitch = "duplicate-emails-switch";
|
||||||
this.accountThemeList = "#kc-account-theme + ul";
|
verifyEmailSwitch = "verify-email-switch";
|
||||||
this.selectAdminTheme = "#kc-admin-console-theme";
|
authSwitch = "email-authentication-switch";
|
||||||
this.adminThemeList = "#kc-admin-console-theme + ul";
|
fromInput = "sender-email-address";
|
||||||
this.selectEmailTheme = "#kc-email-theme";
|
enableSslCheck = "enable-ssl";
|
||||||
this.emailThemeList = "#kc-email-theme + ul";
|
enableStartTlsCheck = "enable-start-tls";
|
||||||
this.selectDefaultLocale = "select-default-locale";
|
|
||||||
this.defaultLocaleList = "select-default-locale + ul";
|
|
||||||
}
|
|
||||||
|
|
||||||
selectLoginThemeType(themeType: string) {
|
selectLoginThemeType(themeType: string) {
|
||||||
cy.get(this.selectLoginTheme).click();
|
cy.get(this.selectLoginTheme).click();
|
||||||
|
@ -59,20 +56,42 @@ export default class RealmSettingsPage {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveGeneral() {
|
||||||
|
cy.getId(this.generalSaveBtn).click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveThemes() {
|
||||||
|
cy.getId(this.themesSaveBtn).click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSenderEmail(senderEmail: string) {
|
||||||
|
cy.getId(this.fromInput).clear();
|
||||||
|
|
||||||
|
if (senderEmail) {
|
||||||
|
cy.getId(this.fromInput).type(senderEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
toggleSwitch(switchName: string) {
|
toggleSwitch(switchName: string) {
|
||||||
cy.getId(switchName).next().click();
|
cy.getId(switchName).next().click();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveGeneral() {
|
toggleCheck(switchName: string) {
|
||||||
cy.getId(this.saveBtnGeneral).click();
|
cy.getId(switchName).click();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveThemes() {
|
save(saveBtn: string) {
|
||||||
cy.getId(this.saveBtnThemes).click();
|
cy.getId(saveBtn).click();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,18 @@ type FormPanelProps = {
|
||||||
title: string;
|
title: string;
|
||||||
scrollId?: string;
|
scrollId?: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FormPanel = ({ title, children, scrollId }: FormPanelProps) => {
|
export const FormPanel = ({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
scrollId,
|
||||||
|
className,
|
||||||
|
}: FormPanelProps) => {
|
||||||
return (
|
return (
|
||||||
<Card isFlat className="kc-form-panel__panel">
|
<Card className={className} isFlat>
|
||||||
<CardHeader>
|
<CardHeader className="kc-form-panel__header">
|
||||||
<CardTitle tabIndex={0}>
|
<CardTitle tabIndex={0}>
|
||||||
<Title
|
<Title
|
||||||
headingLevel="h4"
|
headingLevel="h4"
|
||||||
|
@ -31,7 +37,7 @@ export const FormPanel = ({ title, children, scrollId }: FormPanelProps) => {
|
||||||
</Title>
|
</Title>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody>{children}</CardBody>
|
<CardBody className="kc-form-panel__body">{children}</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
295
src/realm-settings/EmailTab.tsx
Normal file
295
src/realm-settings/EmailTab.tsx
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Controller, useFormContext, UseFormMethods } from "react-hook-form";
|
||||||
|
import {
|
||||||
|
ActionGroup,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
FormGroup,
|
||||||
|
PageSection,
|
||||||
|
Switch,
|
||||||
|
TextInput,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
|
||||||
|
import RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentation";
|
||||||
|
import { FormAccess } from "../components/form-access/FormAccess";
|
||||||
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
import { FormPanel } from "../components/scroll-form/FormPanel";
|
||||||
|
|
||||||
|
import "./RealmSettingsSection.css";
|
||||||
|
import { emailRegexPattern } from "../util";
|
||||||
|
|
||||||
|
export type UserFormProps = {
|
||||||
|
form: UseFormMethods<RealmRepresentation>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RealmSettingsEmailTabProps = {
|
||||||
|
save: (realm: RealmRepresentation) => void;
|
||||||
|
reset: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RealmSettingsEmailTab = ({
|
||||||
|
save,
|
||||||
|
reset,
|
||||||
|
}: RealmSettingsEmailTabProps) => {
|
||||||
|
const { t } = useTranslation("realm-settings");
|
||||||
|
const [isAuthenticationEnabled, setAuthenticationEnabled] = useState("");
|
||||||
|
const { register, control, handleSubmit, errors } = useFormContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PageSection variant="light">
|
||||||
|
<FormPanel title={t("template")} className="kc-email-template">
|
||||||
|
<FormAccess
|
||||||
|
isHorizontal
|
||||||
|
role="manage-realm"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save)}
|
||||||
|
>
|
||||||
|
<FormGroup
|
||||||
|
label={t("from")}
|
||||||
|
fieldId="kc-display-name"
|
||||||
|
isRequired
|
||||||
|
validated={
|
||||||
|
errors.attributes?.from?.type === "pattern"
|
||||||
|
? "error"
|
||||||
|
: "default"
|
||||||
|
}
|
||||||
|
helperTextInvalid={t("users:emailInvalid")}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="email"
|
||||||
|
id="kc-sender-email-address"
|
||||||
|
data-testid="sender-email-address"
|
||||||
|
name="attributes.from"
|
||||||
|
ref={register({
|
||||||
|
pattern: emailRegexPattern,
|
||||||
|
required: true,
|
||||||
|
})}
|
||||||
|
placeholder="Sender email address"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("fromDisplayName")}
|
||||||
|
fieldId="kc-from-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:fromDisplayName"
|
||||||
|
forLabel={t("authentication")}
|
||||||
|
forID="kc-user-manged-access"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-from-display-name"
|
||||||
|
data-testid="from-display-name"
|
||||||
|
name="attributes.fromDisplayName"
|
||||||
|
ref={register}
|
||||||
|
placeholder="Display name for Sender email address"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("replyTo")}
|
||||||
|
fieldId="kc-reply-to"
|
||||||
|
validated={
|
||||||
|
errors.attributes?.replyTo?.type === "pattern"
|
||||||
|
? "error"
|
||||||
|
: "default"
|
||||||
|
}
|
||||||
|
helperTextInvalid={t("users:emailInvalid")}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="email"
|
||||||
|
id="kc-reply-to"
|
||||||
|
name="attributes.replyTo"
|
||||||
|
ref={register({
|
||||||
|
pattern: emailRegexPattern,
|
||||||
|
})}
|
||||||
|
placeholder="Reply to email address"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("replyToDisplayName")}
|
||||||
|
fieldId="kc-reply-to-display-name"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:replyToDisplayName"
|
||||||
|
forLabel={t("replyToDisplayName")}
|
||||||
|
forID="kc-user-manged-access"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-reply-to-display-name"
|
||||||
|
name="attributes.replyToDisplayName"
|
||||||
|
ref={register}
|
||||||
|
placeholder='Display name for "reply to" email address'
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("envelopeFrom")}
|
||||||
|
fieldId="kc-envelope-from"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:envelopeFrom"
|
||||||
|
forLabel={t("envelopeFrom")}
|
||||||
|
forID="kc-envelope-from"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-envelope-from"
|
||||||
|
name="attributes.envelopeFrom"
|
||||||
|
ref={register}
|
||||||
|
placeholder="Sender envelope email address"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</FormAccess>
|
||||||
|
</FormPanel>
|
||||||
|
<FormPanel
|
||||||
|
className="kc-email-connection"
|
||||||
|
title={t("connectionAndAuthentication")}
|
||||||
|
>
|
||||||
|
<FormAccess
|
||||||
|
isHorizontal
|
||||||
|
role="manage-realm"
|
||||||
|
className="pf-u-mt-lg"
|
||||||
|
onSubmit={handleSubmit(save)}
|
||||||
|
>
|
||||||
|
<FormGroup label={t("host")} fieldId="kc-host" isRequired>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-host"
|
||||||
|
name="attributes.host"
|
||||||
|
ref={register({ required: true })}
|
||||||
|
placeholder="SMTP host"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup label={t("port")} fieldId="kc-port">
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-port"
|
||||||
|
name="attributes.port"
|
||||||
|
ref={register}
|
||||||
|
placeholder="SMTP port (defaults to 25)"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup label={t("encryption")} fieldId="kc-html-display-name">
|
||||||
|
<Controller
|
||||||
|
name="attributes.enableSsl"
|
||||||
|
control={control}
|
||||||
|
defaultValue="false"
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Checkbox
|
||||||
|
id="kc-enable-ssl"
|
||||||
|
data-testid="enable-ssl"
|
||||||
|
name="attributes.enableSsl"
|
||||||
|
label={t("enableSSL")}
|
||||||
|
ref={register}
|
||||||
|
isChecked={value === "true"}
|
||||||
|
onChange={(value) => onChange("" + value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="attributes.enableStartTls"
|
||||||
|
control={control}
|
||||||
|
defaultValue="false"
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Checkbox
|
||||||
|
id="kc-enable-start-tls"
|
||||||
|
data-testid="enable-start-tls"
|
||||||
|
name="attributes.startTls"
|
||||||
|
label={t("enableStartTLS")}
|
||||||
|
ref={register}
|
||||||
|
isChecked={value === "true"}
|
||||||
|
onChange={(value) => onChange("" + value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
hasNoPaddingTop
|
||||||
|
label={t("authentication")}
|
||||||
|
fieldId="kc-authentication"
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
name="attributes.authentication"
|
||||||
|
control={control}
|
||||||
|
defaultValue="true"
|
||||||
|
render={({ onChange, value }) => (
|
||||||
|
<Switch
|
||||||
|
id="kc-authentication"
|
||||||
|
data-testid="email-authentication-switch"
|
||||||
|
label={t("common:enabled")}
|
||||||
|
labelOff={t("common:disabled")}
|
||||||
|
isChecked={value === "true"}
|
||||||
|
onChange={(value) => {
|
||||||
|
onChange("" + value);
|
||||||
|
setAuthenticationEnabled(String(value));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{isAuthenticationEnabled === "true" && (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("username")}
|
||||||
|
fieldId="kc-username"
|
||||||
|
isRequired={isAuthenticationEnabled === "true"}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-username"
|
||||||
|
data-testid="username-input"
|
||||||
|
name="attributes.loginUsername"
|
||||||
|
ref={register({ required: true })}
|
||||||
|
placeholder="Login username"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("password")}
|
||||||
|
fieldId="kc-username"
|
||||||
|
isRequired={isAuthenticationEnabled === "true"}
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="realm-settings-help:frontendUrl"
|
||||||
|
forLabel={t("password")}
|
||||||
|
forID="kc-password"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="password"
|
||||||
|
id="kc-password"
|
||||||
|
data-testid="password-input"
|
||||||
|
name="attributes.loginPassword"
|
||||||
|
ref={register}
|
||||||
|
placeholder="Login password"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ActionGroup>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
data-testid="email-tab-save"
|
||||||
|
>
|
||||||
|
{t("common:save")}
|
||||||
|
</Button>
|
||||||
|
<Button variant="link" onClick={reset}>
|
||||||
|
{t("common:revert")}
|
||||||
|
</Button>
|
||||||
|
</ActionGroup>
|
||||||
|
</FormAccess>
|
||||||
|
</FormPanel>
|
||||||
|
</PageSection>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -21,192 +21,188 @@ export const RealmSettingsLoginTab = ({
|
||||||
<>
|
<>
|
||||||
<PageSection variant="light">
|
<PageSection variant="light">
|
||||||
<FormPanel title="Login screen customization">
|
<FormPanel title="Login screen customization">
|
||||||
{
|
<FormAccess isHorizontal role="manage-realm">
|
||||||
<FormAccess isHorizontal role="manage-realm">
|
<FormGroup
|
||||||
<FormGroup
|
label={t("userRegistration")}
|
||||||
label={t("userRegistration")}
|
fieldId="kc-user-reg"
|
||||||
fieldId="kc-user-reg"
|
labelIcon={
|
||||||
labelIcon={
|
<HelpItem
|
||||||
<HelpItem
|
helpText={t("userRegistrationHelpText")}
|
||||||
helpText={t("userRegistrationHelpText")}
|
forLabel={t("userRegistration")}
|
||||||
forLabel={t("userRegistration")}
|
forID="kc-user-reg"
|
||||||
forID="kc-user-reg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
hasNoPaddingTop
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
id="kc-user-reg"
|
|
||||||
data-testid="user-reg-switch"
|
|
||||||
name="registrationAllowed"
|
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={realm?.registrationAllowed}
|
|
||||||
onChange={(value) => {
|
|
||||||
save({ ...realm, registrationAllowed: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
<FormGroup
|
hasNoPaddingTop
|
||||||
label={t("forgotPassword")}
|
>
|
||||||
fieldId="kc-forgot-pw"
|
<Switch
|
||||||
labelIcon={
|
id="kc-user-reg"
|
||||||
<HelpItem
|
data-testid="user-reg-switch"
|
||||||
helpText={t("forgotPasswordHelpText")}
|
name="registrationAllowed"
|
||||||
forLabel={t("forgotPassword")}
|
label={t("common:on")}
|
||||||
forID="kc-forgot-pw"
|
labelOff={t("common:off")}
|
||||||
/>
|
isChecked={realm?.registrationAllowed}
|
||||||
}
|
onChange={(value) => {
|
||||||
hasNoPaddingTop
|
save({ ...realm, registrationAllowed: value });
|
||||||
>
|
}}
|
||||||
<Switch
|
/>
|
||||||
id="kc-forgot-pw"
|
</FormGroup>
|
||||||
data-testid="forgot-pw-switch"
|
<FormGroup
|
||||||
name="resetPasswordAllowed"
|
label={t("forgotPassword")}
|
||||||
label={t("common:on")}
|
fieldId="kc-forgot-pw"
|
||||||
labelOff={t("common:off")}
|
labelIcon={
|
||||||
isChecked={realm?.resetPasswordAllowed}
|
<HelpItem
|
||||||
onChange={(value) => {
|
helpText={t("forgotPasswordHelpText")}
|
||||||
save({ ...realm, resetPasswordAllowed: value });
|
forLabel={t("forgotPassword")}
|
||||||
}}
|
forID="kc-forgot-pw"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
<FormGroup
|
hasNoPaddingTop
|
||||||
label={t("rememberMe")}
|
>
|
||||||
fieldId="kc-remember-me"
|
<Switch
|
||||||
labelIcon={
|
id="kc-forgot-pw"
|
||||||
<HelpItem
|
data-testid="forgot-pw-switch"
|
||||||
helpText={t("rememberMeHelpText")}
|
name="resetPasswordAllowed"
|
||||||
forLabel={t("rememberMe")}
|
label={t("common:on")}
|
||||||
forID="kc-remember-me"
|
labelOff={t("common:off")}
|
||||||
/>
|
isChecked={realm?.resetPasswordAllowed}
|
||||||
}
|
onChange={(value) => {
|
||||||
hasNoPaddingTop
|
save({ ...realm, resetPasswordAllowed: value });
|
||||||
>
|
}}
|
||||||
<Switch
|
/>
|
||||||
id="kc-remember-me"
|
</FormGroup>
|
||||||
data-testid="remember-me-switch"
|
<FormGroup
|
||||||
name="rememberMe"
|
label={t("rememberMe")}
|
||||||
label={t("common:on")}
|
fieldId="kc-remember-me"
|
||||||
labelOff={t("common:off")}
|
labelIcon={
|
||||||
isChecked={realm?.rememberMe}
|
<HelpItem
|
||||||
onChange={(value) => {
|
helpText={t("rememberMeHelpText")}
|
||||||
save({ ...realm, rememberMe: value });
|
forLabel={t("rememberMe")}
|
||||||
}}
|
forID="kc-remember-me"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
</FormAccess>
|
hasNoPaddingTop
|
||||||
}
|
>
|
||||||
|
<Switch
|
||||||
|
id="kc-remember-me"
|
||||||
|
data-testid="remember-me-switch"
|
||||||
|
name="rememberMe"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={realm?.rememberMe}
|
||||||
|
onChange={(value) => {
|
||||||
|
save({ ...realm, rememberMe: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</FormAccess>
|
||||||
</FormPanel>
|
</FormPanel>
|
||||||
<FormPanel title="Email settings">
|
<FormPanel title="Email settings">
|
||||||
{
|
<FormAccess isHorizontal role="manage-realm">
|
||||||
<FormAccess isHorizontal role="manage-realm">
|
<FormGroup
|
||||||
<FormGroup
|
label={t("emailAsUsername")}
|
||||||
label={t("emailAsUsername")}
|
fieldId="kc-email-as-username"
|
||||||
fieldId="kc-email-as-username"
|
labelIcon={
|
||||||
labelIcon={
|
<HelpItem
|
||||||
<HelpItem
|
helpText={t("emailAsUsernameHelpText")}
|
||||||
helpText={t("emailAsUsernameHelpText")}
|
forLabel={t("emailAsUsername")}
|
||||||
forLabel={t("emailAsUsername")}
|
forID="kc-email-as-username"
|
||||||
forID="kc-email-as-username"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
hasNoPaddingTop
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
id="kc-email-as-username"
|
|
||||||
data-testid="email-as-username-switch"
|
|
||||||
name="registrationEmailAsUsername"
|
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={realm?.registrationEmailAsUsername}
|
|
||||||
onChange={(value) => {
|
|
||||||
save({ ...realm, registrationEmailAsUsername: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
<FormGroup
|
hasNoPaddingTop
|
||||||
label={t("loginWithEmail")}
|
>
|
||||||
fieldId="kc-login-with-email"
|
<Switch
|
||||||
labelIcon={
|
id="kc-email-as-username"
|
||||||
<HelpItem
|
data-testid="email-as-username-switch"
|
||||||
helpText={t("loginWithEmailHelpText")}
|
name="registrationEmailAsUsername"
|
||||||
forLabel={t("loginWithEmail")}
|
label={t("common:on")}
|
||||||
forID="kc-login-with-email"
|
labelOff={t("common:off")}
|
||||||
/>
|
isChecked={realm?.registrationEmailAsUsername}
|
||||||
}
|
onChange={(value) => {
|
||||||
hasNoPaddingTop
|
save({ ...realm, registrationEmailAsUsername: value });
|
||||||
>
|
}}
|
||||||
<Switch
|
/>
|
||||||
id="kc-login-with-email"
|
</FormGroup>
|
||||||
data-testid="login-with-email-switch"
|
<FormGroup
|
||||||
name="loginWithEmailAllowed"
|
label={t("loginWithEmail")}
|
||||||
label={t("common:on")}
|
fieldId="kc-login-with-email"
|
||||||
labelOff={t("common:off")}
|
labelIcon={
|
||||||
isChecked={realm?.loginWithEmailAllowed}
|
<HelpItem
|
||||||
onChange={(value) => {
|
helpText={t("loginWithEmailHelpText")}
|
||||||
save({ ...realm, loginWithEmailAllowed: value });
|
forLabel={t("loginWithEmail")}
|
||||||
}}
|
forID="kc-login-with-email"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
<FormGroup
|
hasNoPaddingTop
|
||||||
label={t("duplicateEmails")}
|
>
|
||||||
fieldId="kc-duplicate-emails"
|
<Switch
|
||||||
labelIcon={
|
id="kc-login-with-email"
|
||||||
<HelpItem
|
data-testid="login-with-email-switch"
|
||||||
helpText={t("duplicateEmailsHelpText")}
|
name="loginWithEmailAllowed"
|
||||||
forLabel={t("duplicateEmails")}
|
label={t("common:on")}
|
||||||
forID="kc-duplicate-emails"
|
labelOff={t("common:off")}
|
||||||
/>
|
isChecked={realm?.loginWithEmailAllowed}
|
||||||
}
|
onChange={(value) => {
|
||||||
hasNoPaddingTop
|
save({ ...realm, loginWithEmailAllowed: value });
|
||||||
>
|
}}
|
||||||
<Switch
|
/>
|
||||||
id="kc-duplicate-emails"
|
</FormGroup>
|
||||||
data-testid="duplicate-emails-switch"
|
<FormGroup
|
||||||
label={t("common:on")}
|
label={t("duplicateEmails")}
|
||||||
labelOff={t("common:off")}
|
fieldId="kc-duplicate-emails"
|
||||||
name="duplicateEmailsAllowed"
|
labelIcon={
|
||||||
isChecked={
|
<HelpItem
|
||||||
realm?.duplicateEmailsAllowed &&
|
helpText={t("duplicateEmailsHelpText")}
|
||||||
!realm?.loginWithEmailAllowed &&
|
forLabel={t("duplicateEmails")}
|
||||||
!realm?.registrationEmailAsUsername
|
forID="kc-duplicate-emails"
|
||||||
}
|
|
||||||
onChange={(value) => {
|
|
||||||
save({ ...realm, duplicateEmailsAllowed: value });
|
|
||||||
}}
|
|
||||||
isDisabled={
|
|
||||||
realm?.loginWithEmailAllowed ||
|
|
||||||
realm?.registrationEmailAsUsername
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
<FormGroup
|
hasNoPaddingTop
|
||||||
label={t("verifyEmail")}
|
>
|
||||||
fieldId="kc-verify-email"
|
<Switch
|
||||||
labelIcon={
|
id="kc-duplicate-emails"
|
||||||
<HelpItem
|
data-testid="duplicate-emails-switch"
|
||||||
helpText={t("verifyEmailHelpText")}
|
label={t("common:on")}
|
||||||
forLabel={t("verifyEmail")}
|
labelOff={t("common:off")}
|
||||||
forID="kc-verify-email"
|
name="duplicateEmailsAllowed"
|
||||||
/>
|
isChecked={
|
||||||
|
realm?.duplicateEmailsAllowed &&
|
||||||
|
!realm?.loginWithEmailAllowed &&
|
||||||
|
!realm?.registrationEmailAsUsername
|
||||||
}
|
}
|
||||||
hasNoPaddingTop
|
onChange={(value) => {
|
||||||
>
|
save({ ...realm, duplicateEmailsAllowed: value });
|
||||||
<Switch
|
}}
|
||||||
id="kc-verify-email"
|
isDisabled={
|
||||||
data-testid="verify-email-switch"
|
realm?.loginWithEmailAllowed ||
|
||||||
name="verifyEmail"
|
realm?.registrationEmailAsUsername
|
||||||
label={t("common:on")}
|
}
|
||||||
labelOff={t("common:off")}
|
/>
|
||||||
isChecked={realm?.verifyEmail}
|
</FormGroup>
|
||||||
onChange={(value) => {
|
<FormGroup
|
||||||
save({ ...realm, verifyEmail: value });
|
label={t("verifyEmail")}
|
||||||
}}
|
fieldId="kc-verify-email"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText={t("verifyEmailHelpText")}
|
||||||
|
forLabel={t("verifyEmail")}
|
||||||
|
forID="kc-verify-email"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
}
|
||||||
</FormAccess>
|
hasNoPaddingTop
|
||||||
}
|
>
|
||||||
|
<Switch
|
||||||
|
id="kc-verify-email"
|
||||||
|
data-testid="verify-email-switch"
|
||||||
|
name="verifyEmail"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={realm?.verifyEmail}
|
||||||
|
onChange={(value) => {
|
||||||
|
save({ ...realm, verifyEmail: value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</FormAccess>
|
||||||
</FormPanel>
|
</FormPanel>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
|
|
18
src/realm-settings/RealmSettingsSection.css
Normal file
18
src/realm-settings/RealmSettingsSection.css
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
.pf-c-card.pf-m-flat.kc-email-template,
|
||||||
|
.pf-c-card.pf-m-flat.kc-email-connection {
|
||||||
|
border: none;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
padding-bottom: var(--pf-global--spacer--sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pf-c-card__header.kc-form-panel__header {
|
||||||
|
padding-bottom: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pf-c-card__body.kc-form-panel__body {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-bottom: var(--pf-global--spacer--2xl);
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import { RealmSettingsLoginTab } from "./LoginTab";
|
||||||
import { RealmSettingsGeneralTab } from "./GeneralTab";
|
import { RealmSettingsGeneralTab } from "./GeneralTab";
|
||||||
import { PartialImportDialog } from "./PartialImport";
|
import { PartialImportDialog } from "./PartialImport";
|
||||||
import { RealmSettingsThemesTab } from "./ThemesTab";
|
import { RealmSettingsThemesTab } from "./ThemesTab";
|
||||||
|
import { RealmSettingsEmailTab } from "./EmailTab";
|
||||||
|
|
||||||
type RealmSettingsHeaderProps = {
|
type RealmSettingsHeaderProps = {
|
||||||
onChange: (value: boolean) => void;
|
onChange: (value: boolean) => void;
|
||||||
|
@ -186,6 +187,16 @@ export const RealmSettingsSection = () => {
|
||||||
>
|
>
|
||||||
<RealmSettingsLoginTab save={save} realm={realm!} />
|
<RealmSettingsLoginTab save={save} realm={realm!} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
eventKey="email"
|
||||||
|
title={<TabTitleText>{t("realm-settings:email")}</TabTitleText>}
|
||||||
|
data-testid="rs-email-tab"
|
||||||
|
>
|
||||||
|
<RealmSettingsEmailTab
|
||||||
|
save={save}
|
||||||
|
reset={() => setupForm(realm!)}
|
||||||
|
/>
|
||||||
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="themes"
|
eventKey="themes"
|
||||||
title={<TabTitleText>{t("realm-settings:themes")}</TabTitleText>}
|
title={<TabTitleText>{t("realm-settings:themes")}</TabTitleText>}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{
|
{
|
||||||
"realm-settings-help": {
|
"realm-settings-help": {
|
||||||
|
"fromDisplayName": "A user-friendly name for the 'From' address (optional).",
|
||||||
|
"replyToDisplayName": "A user-friendly name for the 'Reply-To' address (optional).",
|
||||||
|
"envelopeFrom": "An email address used for bounces (optional).",
|
||||||
"frontendUrl": "Set the frontend URL for the realm. Use in combination with the default hostname provider to override the base URL for frontend requests for a specific realm.",
|
"frontendUrl": "Set the frontend URL for the realm. Use in combination with the default hostname provider to override the base URL for frontend requests for a specific realm.",
|
||||||
"requireSsl": "Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses.",
|
"requireSsl": "Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses.",
|
||||||
"userManagedAccess": "If enabled, users are allowed to manage their resources and permissions using the Account Management Console.",
|
"userManagedAccess": "If enabled, users are allowed to manage their resources and permissions using the Account Management Console.",
|
||||||
|
|
|
@ -14,6 +14,22 @@
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"themes": "Themes",
|
"themes": "Themes",
|
||||||
|
"email": "Email",
|
||||||
|
"template": "Template",
|
||||||
|
"connectionAndAuthentication": "Connection & Authentication",
|
||||||
|
"from": "From",
|
||||||
|
"fromDisplayName": "From display name",
|
||||||
|
"replyTo": "Reply to",
|
||||||
|
"replyToDisplayName": "Reply to display name",
|
||||||
|
"envelopeFrom": "Envelope from",
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port",
|
||||||
|
"encryption": "Encryption",
|
||||||
|
"authentication": "Authentication",
|
||||||
|
"enableSSL": "Enable SSL",
|
||||||
|
"enableStartTLS": "Enable StartTLS",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
"userRegistration": "User registration",
|
"userRegistration": "User registration",
|
||||||
"userRegistrationHelpText": "Enable/disable the registration page. A link for registration will show on login page too.",
|
"userRegistrationHelpText": "Enable/disable the registration page. A link for registration will show on login page too.",
|
||||||
"forgotPassword": "Forgot password",
|
"forgotPassword": "Forgot password",
|
||||||
|
|
|
@ -25,6 +25,7 @@ import moment from "moment";
|
||||||
import { JoinGroupDialog } from "./JoinGroupDialog";
|
import { JoinGroupDialog } from "./JoinGroupDialog";
|
||||||
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
|
import GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
|
||||||
import { useAlerts } from "../components/alert/Alerts";
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import { emailRegexPattern } from "../util";
|
||||||
|
|
||||||
export type UserFormProps = {
|
export type UserFormProps = {
|
||||||
form: UseFormMethods<UserRepresentation>;
|
form: UseFormMethods<UserRepresentation>;
|
||||||
|
@ -86,8 +87,6 @@ export const UserForm = ({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const emailRegexPattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
||||||
|
|
||||||
const requiredUserActionsOptions = [
|
const requiredUserActionsOptions = [
|
||||||
<SelectOption key={0} value="CONFIGURE_TOTP">
|
<SelectOption key={0} value="CONFIGURE_TOTP">
|
||||||
{t("configureOTP")}
|
{t("configureOTP")}
|
||||||
|
|
|
@ -91,3 +91,5 @@ export const getBaseUrl = (adminClient: KeycloakAdminClient) => {
|
||||||
? adminClient.keycloak.authServerUrl!
|
? adminClient.keycloak.authServerUrl!
|
||||||
: adminClient.baseUrl + "/";
|
: adminClient.baseUrl + "/";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const emailRegexPattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||||
|
|
Loading…
Reference in a new issue