fixes realm save (#633)
* fixes realm save currently save on realm screen didn't work as the email settings where required. Fixed this by changing email to be it's own section. Also email section was using the wrong attributes therefor the changes where not reflected in the old console * fix empty realmComponent array * fixed password help text
This commit is contained in:
parent
f278f34fe5
commit
bbc177abb8
5 changed files with 158 additions and 133 deletions
|
@ -1,8 +1,9 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Controller, useFormContext, UseFormMethods } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import {
|
import {
|
||||||
ActionGroup,
|
ActionGroup,
|
||||||
|
AlertVariant,
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
|
@ -15,26 +16,60 @@ import type RealmRepresentation from "keycloak-admin/lib/defs/realmRepresentatio
|
||||||
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 { FormPanel } from "../components/scroll-form/FormPanel";
|
import { FormPanel } from "../components/scroll-form/FormPanel";
|
||||||
|
import { emailRegexPattern } from "../util";
|
||||||
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useAlerts } from "../components/alert/Alerts";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
import "./RealmSettingsSection.css";
|
import "./RealmSettingsSection.css";
|
||||||
import { emailRegexPattern } from "../util";
|
|
||||||
|
|
||||||
export type UserFormProps = {
|
|
||||||
form: UseFormMethods<RealmRepresentation>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RealmSettingsEmailTabProps = {
|
type RealmSettingsEmailTabProps = {
|
||||||
save: (realm: RealmRepresentation) => void;
|
realm: RealmRepresentation;
|
||||||
reset: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RealmSettingsEmailTab = ({
|
export const RealmSettingsEmailTab = ({
|
||||||
save,
|
realm: initialRealm,
|
||||||
reset,
|
|
||||||
}: RealmSettingsEmailTabProps) => {
|
}: RealmSettingsEmailTabProps) => {
|
||||||
const { t } = useTranslation("realm-settings");
|
const { t } = useTranslation("realm-settings");
|
||||||
const [isAuthenticationEnabled, setAuthenticationEnabled] = useState("");
|
const adminClient = useAdminClient();
|
||||||
const { register, control, handleSubmit, errors } = useFormContext();
|
const { realm: realmName } = useRealm();
|
||||||
|
const { addAlert } = useAlerts();
|
||||||
|
|
||||||
|
const [isAuthenticationEnabled, setAuthenticationEnabled] = useState("true");
|
||||||
|
const [realm, setRealm] = useState(initialRealm);
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
errors,
|
||||||
|
setValue,
|
||||||
|
reset: resetForm,
|
||||||
|
} = useForm<RealmRepresentation>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reset();
|
||||||
|
}, [realm]);
|
||||||
|
|
||||||
|
const save = async (form: RealmRepresentation) => {
|
||||||
|
try {
|
||||||
|
const savedRealm = { ...realm, ...form };
|
||||||
|
await adminClient.realms.update({ realm: realmName }, savedRealm);
|
||||||
|
setRealm(savedRealm);
|
||||||
|
addAlert(t("saveSuccess"), AlertVariant.success);
|
||||||
|
} catch (error) {
|
||||||
|
addAlert(
|
||||||
|
t("saveError", { error: error.response?.data?.errorMessage || error }),
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
if (realm) {
|
||||||
|
resetForm(realm);
|
||||||
|
Object.entries(realm).map((entry) => setValue(entry[0], entry[1]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -50,23 +85,20 @@ export const RealmSettingsEmailTab = ({
|
||||||
label={t("from")}
|
label={t("from")}
|
||||||
fieldId="kc-display-name"
|
fieldId="kc-display-name"
|
||||||
isRequired
|
isRequired
|
||||||
validated={
|
validated={errors.smtpServer?.from ? "error" : "default"}
|
||||||
errors.attributes?.from?.type === "pattern"
|
|
||||||
? "error"
|
|
||||||
: "default"
|
|
||||||
}
|
|
||||||
helperTextInvalid={t("users:emailInvalid")}
|
helperTextInvalid={t("users:emailInvalid")}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="email"
|
type="email"
|
||||||
id="kc-sender-email-address"
|
id="kc-sender-email-address"
|
||||||
data-testid="sender-email-address"
|
data-testid="sender-email-address"
|
||||||
name="attributes.from"
|
name="smtpServer.from"
|
||||||
ref={register({
|
ref={register({
|
||||||
pattern: emailRegexPattern,
|
pattern: emailRegexPattern,
|
||||||
required: true,
|
required: true,
|
||||||
})}
|
})}
|
||||||
placeholder="Sender email address"
|
placeholder="Sender email address"
|
||||||
|
validated={errors.smtpServer?.from ? "error" : "default"}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
@ -84,7 +116,7 @@ export const RealmSettingsEmailTab = ({
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-from-display-name"
|
id="kc-from-display-name"
|
||||||
data-testid="from-display-name"
|
data-testid="from-display-name"
|
||||||
name="attributes.fromDisplayName"
|
name="smtpServer.fromDisplayName"
|
||||||
ref={register}
|
ref={register}
|
||||||
placeholder="Display name for Sender email address"
|
placeholder="Display name for Sender email address"
|
||||||
/>
|
/>
|
||||||
|
@ -92,21 +124,18 @@ export const RealmSettingsEmailTab = ({
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("replyTo")}
|
label={t("replyTo")}
|
||||||
fieldId="kc-reply-to"
|
fieldId="kc-reply-to"
|
||||||
validated={
|
validated={errors.smtpServer?.replyTo ? "error" : "default"}
|
||||||
errors.attributes?.replyTo?.type === "pattern"
|
|
||||||
? "error"
|
|
||||||
: "default"
|
|
||||||
}
|
|
||||||
helperTextInvalid={t("users:emailInvalid")}
|
helperTextInvalid={t("users:emailInvalid")}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="email"
|
type="email"
|
||||||
id="kc-reply-to"
|
id="kc-reply-to"
|
||||||
name="attributes.replyTo"
|
name="smtpServer.replyTo"
|
||||||
ref={register({
|
ref={register({
|
||||||
pattern: emailRegexPattern,
|
pattern: emailRegexPattern,
|
||||||
})}
|
})}
|
||||||
placeholder="Reply to email address"
|
placeholder="Reply to email address"
|
||||||
|
validated={errors.smtpServer?.replyTo ? "error" : "default"}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
@ -123,7 +152,7 @@ export const RealmSettingsEmailTab = ({
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-reply-to-display-name"
|
id="kc-reply-to-display-name"
|
||||||
name="attributes.replyToDisplayName"
|
name="smtpServer.replyToDisplayName"
|
||||||
ref={register}
|
ref={register}
|
||||||
placeholder='Display name for "reply to" email address'
|
placeholder='Display name for "reply to" email address'
|
||||||
/>
|
/>
|
||||||
|
@ -142,7 +171,7 @@ export const RealmSettingsEmailTab = ({
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-envelope-from"
|
id="kc-envelope-from"
|
||||||
name="attributes.envelopeFrom"
|
name="smtpServer.envelopeFrom"
|
||||||
ref={register}
|
ref={register}
|
||||||
placeholder="Sender envelope email address"
|
placeholder="Sender envelope email address"
|
||||||
/>
|
/>
|
||||||
|
@ -159,34 +188,40 @@ export const RealmSettingsEmailTab = ({
|
||||||
className="pf-u-mt-lg"
|
className="pf-u-mt-lg"
|
||||||
onSubmit={handleSubmit(save)}
|
onSubmit={handleSubmit(save)}
|
||||||
>
|
>
|
||||||
<FormGroup label={t("host")} fieldId="kc-host" isRequired>
|
<FormGroup
|
||||||
|
label={t("host")}
|
||||||
|
fieldId="kc-host"
|
||||||
|
isRequired
|
||||||
|
validated={errors.smtpServer?.host ? "error" : "default"}
|
||||||
|
helperTextInvalid={t("common:required")}
|
||||||
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-host"
|
id="kc-host"
|
||||||
name="attributes.host"
|
name="smtpServer.host"
|
||||||
ref={register({ required: true })}
|
ref={register({ required: true })}
|
||||||
placeholder="SMTP host"
|
placeholder="SMTP host"
|
||||||
|
validated={errors.smtpServer?.host ? "error" : "default"}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup label={t("port")} fieldId="kc-port">
|
<FormGroup label={t("port")} fieldId="kc-port">
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-port"
|
id="kc-port"
|
||||||
name="attributes.port"
|
name="smtpServer.port"
|
||||||
ref={register}
|
ref={register}
|
||||||
placeholder="SMTP port (defaults to 25)"
|
placeholder="SMTP port (defaults to 25)"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup label={t("encryption")} fieldId="kc-html-display-name">
|
<FormGroup label={t("encryption")} fieldId="kc-html-display-name">
|
||||||
<Controller
|
<Controller
|
||||||
name="attributes.enableSsl"
|
name="smtpServer.ssl"
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue="false"
|
defaultValue="false"
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="kc-enable-ssl"
|
id="kc-enable-ssl"
|
||||||
data-testid="enable-ssl"
|
data-testid="enable-ssl"
|
||||||
name="attributes.enableSsl"
|
|
||||||
label={t("enableSSL")}
|
label={t("enableSSL")}
|
||||||
ref={register}
|
ref={register}
|
||||||
isChecked={value === "true"}
|
isChecked={value === "true"}
|
||||||
|
@ -195,14 +230,13 @@ export const RealmSettingsEmailTab = ({
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Controller
|
<Controller
|
||||||
name="attributes.enableStartTls"
|
name="smtpServer.starttls"
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue="false"
|
defaultValue="false"
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="kc-enable-start-tls"
|
id="kc-enable-start-tls"
|
||||||
data-testid="enable-start-tls"
|
data-testid="enable-start-tls"
|
||||||
name="attributes.startTls"
|
|
||||||
label={t("enableStartTLS")}
|
label={t("enableStartTLS")}
|
||||||
ref={register}
|
ref={register}
|
||||||
isChecked={value === "true"}
|
isChecked={value === "true"}
|
||||||
|
@ -217,7 +251,7 @@ export const RealmSettingsEmailTab = ({
|
||||||
fieldId="kc-authentication"
|
fieldId="kc-authentication"
|
||||||
>
|
>
|
||||||
<Controller
|
<Controller
|
||||||
name="attributes.authentication"
|
name="smtpServer.authentication"
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue="true"
|
defaultValue="true"
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
|
@ -240,24 +274,29 @@ export const RealmSettingsEmailTab = ({
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("username")}
|
label={t("username")}
|
||||||
fieldId="kc-username"
|
fieldId="kc-username"
|
||||||
isRequired={isAuthenticationEnabled === "true"}
|
isRequired
|
||||||
|
validated={errors.smtpServer?.user ? "error" : "default"}
|
||||||
|
helperTextInvalid={t("common:required")}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
id="kc-username"
|
id="kc-username"
|
||||||
data-testid="username-input"
|
data-testid="username-input"
|
||||||
name="attributes.loginUsername"
|
name="smtpServer.user"
|
||||||
ref={register({ required: true })}
|
ref={register({ required: true })}
|
||||||
placeholder="Login username"
|
placeholder="Login username"
|
||||||
|
validated={errors.smtpServer?.user ? "error" : "default"}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("password")}
|
label={t("password")}
|
||||||
fieldId="kc-username"
|
fieldId="kc-username"
|
||||||
isRequired={isAuthenticationEnabled === "true"}
|
isRequired
|
||||||
|
validated={errors.smtpServer?.password ? "error" : "default"}
|
||||||
|
helperTextInvalid={t("common:required")}
|
||||||
labelIcon={
|
labelIcon={
|
||||||
<HelpItem
|
<HelpItem
|
||||||
helpText="realm-settings-help:frontendUrl"
|
helpText="realm-settings-help:password"
|
||||||
forLabel={t("password")}
|
forLabel={t("password")}
|
||||||
forID="kc-password"
|
forID="kc-password"
|
||||||
/>
|
/>
|
||||||
|
@ -267,9 +306,12 @@ export const RealmSettingsEmailTab = ({
|
||||||
type="password"
|
type="password"
|
||||||
id="kc-password"
|
id="kc-password"
|
||||||
data-testid="password-input"
|
data-testid="password-input"
|
||||||
name="attributes.loginPassword"
|
name="smtpServer.password"
|
||||||
ref={register}
|
ref={register({ required: true })}
|
||||||
placeholder="Login password"
|
placeholder="Login password"
|
||||||
|
validated={
|
||||||
|
errors.smtpServer?.password ? "error" : "default"
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -2,42 +2,51 @@ import React, { useState } from "react";
|
||||||
import { useHistory, useRouteMatch } from "react-router-dom";
|
import { useHistory, useRouteMatch } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Button, ButtonVariant, PageSection } from "@patternfly/react-core";
|
import { Button, ButtonVariant, PageSection } from "@patternfly/react-core";
|
||||||
|
import { cellWidth } from "@patternfly/react-table";
|
||||||
|
|
||||||
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
|
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
|
||||||
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import { emptyFormatter } from "../util";
|
import { emptyFormatter } from "../util";
|
||||||
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
import { useAdminClient } from "../context/auth/AdminClient";
|
||||||
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
|
||||||
import "./RealmSettingsSection.css";
|
import "./RealmSettingsSection.css";
|
||||||
import { cellWidth } from "@patternfly/react-table";
|
|
||||||
|
|
||||||
type KeyData = KeyMetadataRepresentation & {
|
type KeyData = KeyMetadataRepresentation & {
|
||||||
provider?: string;
|
provider?: string;
|
||||||
type?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type KeysTabInnerProps = {
|
type KeysListTabProps = {
|
||||||
keys: KeyData[];
|
realmComponents: ComponentRepresentation[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeysTabInner = ({ keys }: KeysTabInnerProps) => {
|
export const KeysListTab = ({ realmComponents }: KeysListTabProps) => {
|
||||||
const { t } = useTranslation("roles");
|
const { t } = useTranslation("roles");
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
const [key, setKey] = useState(0);
|
|
||||||
const refresh = () => setKey(new Date().getTime());
|
|
||||||
|
|
||||||
const [publicKey, setPublicKey] = useState("");
|
const [publicKey, setPublicKey] = useState("");
|
||||||
const [certificate, setCertificate] = useState("");
|
const [certificate, setCertificate] = useState("");
|
||||||
|
|
||||||
const loader = async () => {
|
const adminClient = useAdminClient();
|
||||||
return keys;
|
const { realm: realmName } = useRealm();
|
||||||
};
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
const loader = async () => {
|
||||||
refresh();
|
const keysMetaData = await adminClient.realms.getKeys({
|
||||||
}, [keys]);
|
realm: realmName,
|
||||||
|
});
|
||||||
|
const keys = keysMetaData.keys;
|
||||||
|
|
||||||
|
return keys?.map((key) => {
|
||||||
|
const provider = realmComponents.find(
|
||||||
|
(component: ComponentRepresentation) => component.id === key.providerId
|
||||||
|
);
|
||||||
|
return { ...key, provider: provider?.name } as KeyData;
|
||||||
|
})!;
|
||||||
|
};
|
||||||
|
|
||||||
const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({
|
const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({
|
||||||
titleKey: t("realm-settings:publicKeys").slice(0, -1),
|
titleKey: t("realm-settings:publicKeys").slice(0, -1),
|
||||||
|
@ -115,7 +124,6 @@ export const KeysTabInner = ({ keys }: KeysTabInnerProps) => {
|
||||||
<PublicKeyDialog />
|
<PublicKeyDialog />
|
||||||
<CertificateDialog />
|
<CertificateDialog />
|
||||||
<KeycloakDataTable
|
<KeycloakDataTable
|
||||||
key={key}
|
|
||||||
isNotCompact={true}
|
isNotCompact={true}
|
||||||
loader={loader}
|
loader={loader}
|
||||||
ariaLabelKey="realm-settings:keysList"
|
ariaLabelKey="realm-settings:keysList"
|
||||||
|
@ -166,23 +174,3 @@ export const KeysTabInner = ({ keys }: KeysTabInnerProps) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type KeysProps = {
|
|
||||||
keys: KeyMetadataRepresentation[];
|
|
||||||
realmComponents: ComponentRepresentation[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const KeysListTab = ({ keys, realmComponents, ...props }: KeysProps) => {
|
|
||||||
return (
|
|
||||||
<KeysTabInner
|
|
||||||
keys={keys?.map((key) => {
|
|
||||||
const provider = realmComponents.find(
|
|
||||||
(component: ComponentRepresentation) =>
|
|
||||||
component.id === key.providerId
|
|
||||||
);
|
|
||||||
return { ...key, provider: provider?.name };
|
|
||||||
})}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -19,12 +19,13 @@ import {
|
||||||
ToolbarGroup,
|
ToolbarGroup,
|
||||||
ToolbarItem,
|
ToolbarItem,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
import { SearchIcon } from "@patternfly/react-icons";
|
||||||
|
|
||||||
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
|
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
|
||||||
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
|
import type ComponentTypeRepresentation from "keycloak-admin/lib/defs/componentTypeRepresentation";
|
||||||
|
|
||||||
import "./RealmSettingsSection.css";
|
import "./RealmSettingsSection.css";
|
||||||
import type ComponentTypeRepresentation from "keycloak-admin/lib/defs/componentTypeRepresentation";
|
|
||||||
import { SearchIcon } from "@patternfly/react-icons";
|
|
||||||
|
|
||||||
type ComponentData = KeyMetadataRepresentation & {
|
type ComponentData = KeyMetadataRepresentation & {
|
||||||
providerDescription?: string;
|
providerDescription?: string;
|
||||||
|
@ -33,8 +34,6 @@ type ComponentData = KeyMetadataRepresentation & {
|
||||||
|
|
||||||
type KeysTabInnerProps = {
|
type KeysTabInnerProps = {
|
||||||
components: ComponentData[];
|
components: ComponentData[];
|
||||||
realmComponents: ComponentRepresentation[];
|
|
||||||
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
|
@ -46,7 +45,7 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const itemIds = components.map((item, idx) => "data" + idx);
|
const itemIds = components.map((_, idx) => "data" + idx);
|
||||||
|
|
||||||
const [itemOrder, setItemOrder] = useState<string[]>([]);
|
const [itemOrder, setItemOrder] = useState<string[]>([]);
|
||||||
|
|
||||||
|
@ -222,7 +221,6 @@ export const KeysTabInner = ({ components }: KeysTabInnerProps) => {
|
||||||
|
|
||||||
type KeysProps = {
|
type KeysProps = {
|
||||||
components: ComponentRepresentation[];
|
components: ComponentRepresentation[];
|
||||||
realmComponents: ComponentRepresentation[];
|
|
||||||
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
keyProviderComponentTypes: ComponentTypeRepresentation[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,7 +238,6 @@ export const KeysProviderTab = ({
|
||||||
);
|
);
|
||||||
return { ...component, providerDescription: provider?.helpText };
|
return { ...component, providerDescription: provider?.helpText };
|
||||||
})}
|
})}
|
||||||
keyProviderComponentTypes={keyProviderComponentTypes}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import { PartialImportDialog } from "./PartialImport";
|
||||||
import { RealmSettingsThemesTab } from "./ThemesTab";
|
import { RealmSettingsThemesTab } from "./ThemesTab";
|
||||||
import { RealmSettingsEmailTab } from "./EmailTab";
|
import { RealmSettingsEmailTab } from "./EmailTab";
|
||||||
import { KeysListTab } from "./KeysListTab";
|
import { KeysListTab } from "./KeysListTab";
|
||||||
import type { KeyMetadataRepresentation } from "keycloak-admin/lib/defs/keyMetadataRepresentation";
|
|
||||||
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
|
||||||
import { KeysProviderTab } from "./KeysProvidersTab";
|
import { KeysProviderTab } from "./KeysProvidersTab";
|
||||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
@ -128,43 +127,40 @@ export const RealmSettingsSection = () => {
|
||||||
const { realm: realmName } = useRealm();
|
const { realm: realmName } = useRealm();
|
||||||
const { addAlert } = useAlerts();
|
const { addAlert } = useAlerts();
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const { control, getValues, setValue } = form;
|
const { control, getValues, setValue, reset: resetForm } = form;
|
||||||
const [realm, setRealm] = useState<RealmRepresentation>();
|
const [realm, setRealm] = useState<RealmRepresentation>();
|
||||||
const [activeTab2, setActiveTab2] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
const [keys, setKeys] = useState<KeyMetadataRepresentation[]>([]);
|
|
||||||
const [realmComponents, setRealmComponents] = useState<
|
const [realmComponents, setRealmComponents] = useState<
|
||||||
ComponentRepresentation[]
|
ComponentRepresentation[]
|
||||||
>([]);
|
>();
|
||||||
|
|
||||||
const kpComponentTypes = useServerInfo().componentTypes![
|
const kpComponentTypes = useServerInfo().componentTypes![
|
||||||
"org.keycloak.keys.KeyProvider"
|
"org.keycloak.keys.KeyProvider"
|
||||||
];
|
];
|
||||||
|
|
||||||
useFetch(
|
useFetch(
|
||||||
() => adminClient.realms.findOne({ realm: realmName }),
|
async () => {
|
||||||
(realm) => {
|
const realm = await adminClient.realms.findOne({ realm: realmName });
|
||||||
setupForm(realm);
|
const realmComponents = await adminClient.components.find({
|
||||||
setRealm(realm);
|
type: "org.keycloak.keys.KeyProvider",
|
||||||
|
realm: realmName,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { realm, realmComponents };
|
||||||
|
},
|
||||||
|
(result) => {
|
||||||
|
setRealm(result.realm);
|
||||||
|
setRealmComponents(result.realmComponents);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const update = async () => {
|
if (realm) setupForm(realm);
|
||||||
const keysMetaData = await adminClient.realms.getKeys({
|
}, [realm]);
|
||||||
realm: realmName,
|
|
||||||
});
|
|
||||||
setKeys(keysMetaData.keys!);
|
|
||||||
const realmComponents = await adminClient.components.find({
|
|
||||||
type: "org.keycloak.keys.KeyProvider",
|
|
||||||
realm: realmName,
|
|
||||||
});
|
|
||||||
setRealmComponents(realmComponents);
|
|
||||||
};
|
|
||||||
setTimeout(update, 100);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setupForm = (realm: RealmRepresentation) => {
|
const setupForm = (realm: RealmRepresentation) => {
|
||||||
|
resetForm(realm);
|
||||||
Object.entries(realm).map((entry) => setValue(entry[0], entry[1]));
|
Object.entries(realm).map((entry) => setValue(entry[0], entry[1]));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -174,7 +170,10 @@ export const RealmSettingsSection = () => {
|
||||||
setRealm(realm);
|
setRealm(realm);
|
||||||
addAlert(t("saveSuccess"), AlertVariant.success);
|
addAlert(t("saveSuccess"), AlertVariant.success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addAlert(t("saveError", { error }), AlertVariant.danger);
|
addAlert(
|
||||||
|
t("saveError", { error: error.response?.data?.errorMessage || error }),
|
||||||
|
AlertVariant.danger
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -218,10 +217,7 @@ export const RealmSettingsSection = () => {
|
||||||
title={<TabTitleText>{t("realm-settings:email")}</TabTitleText>}
|
title={<TabTitleText>{t("realm-settings:email")}</TabTitleText>}
|
||||||
data-testid="rs-email-tab"
|
data-testid="rs-email-tab"
|
||||||
>
|
>
|
||||||
<RealmSettingsEmailTab
|
{realm && <RealmSettingsEmailTab realm={realm} />}
|
||||||
save={save}
|
|
||||||
reset={() => setupForm(realm!)}
|
|
||||||
/>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="themes"
|
eventKey="themes"
|
||||||
|
@ -238,29 +234,30 @@ export const RealmSettingsSection = () => {
|
||||||
title={<TabTitleText>{t("realm-settings:keys")}</TabTitleText>}
|
title={<TabTitleText>{t("realm-settings:keys")}</TabTitleText>}
|
||||||
data-testid="rs-keys-tab"
|
data-testid="rs-keys-tab"
|
||||||
>
|
>
|
||||||
<Tabs
|
{realmComponents && (
|
||||||
activeKey={activeTab2}
|
<Tabs
|
||||||
onSelect={(_, key) => setActiveTab2(key as number)}
|
activeKey={activeTab}
|
||||||
>
|
onSelect={(_, key) => setActiveTab(key as number)}
|
||||||
<Tab
|
|
||||||
id="setup"
|
|
||||||
eventKey={0}
|
|
||||||
title={<TabTitleText>{t("keysList")}</TabTitleText>}
|
|
||||||
>
|
>
|
||||||
<KeysListTab keys={keys} realmComponents={realmComponents} />
|
<Tab
|
||||||
</Tab>
|
id="setup"
|
||||||
<Tab
|
eventKey={0}
|
||||||
id="evaluate"
|
title={<TabTitleText>{t("keysList")}</TabTitleText>}
|
||||||
eventKey={1}
|
>
|
||||||
title={<TabTitleText>{t("providers")}</TabTitleText>}
|
<KeysListTab realmComponents={realmComponents} />
|
||||||
>
|
</Tab>
|
||||||
<KeysProviderTab
|
<Tab
|
||||||
components={realmComponents}
|
id="evaluate"
|
||||||
realmComponents={realmComponents}
|
eventKey={1}
|
||||||
keyProviderComponentTypes={kpComponentTypes}
|
title={<TabTitleText>{t("providers")}</TabTitleText>}
|
||||||
/>
|
>
|
||||||
</Tab>
|
<KeysProviderTab
|
||||||
</Tabs>
|
components={realmComponents}
|
||||||
|
keyProviderComponentTypes={kpComponentTypes}
|
||||||
|
/>
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
</KeycloakTabs>
|
</KeycloakTabs>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"fromDisplayName": "A user-friendly name for the 'From' address (optional).",
|
"fromDisplayName": "A user-friendly name for the 'From' address (optional).",
|
||||||
"replyToDisplayName": "A user-friendly name for the 'Reply-To' address (optional).",
|
"replyToDisplayName": "A user-friendly name for the 'Reply-To' address (optional).",
|
||||||
"envelopeFrom": "An email address used for bounces (optional).",
|
"envelopeFrom": "An email address used for bounces (optional).",
|
||||||
|
"password": "SMTP password. This field is able to obtain its value from vault, use ${vault.ID} format.",
|
||||||
"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.",
|
||||||
|
|
Loading…
Reference in a new issue