put shared logic into common component + fixes (#1415)
* put shared logic into common component + fixes fixes: #1398 * removed conflicted name * code review * pr review comments * update admin-client for better retrun types import * use image file instead of encoded data:uri * fix package lock * is typechecked to be string
This commit is contained in:
parent
79f8452ab5
commit
48a006e1fa
11 changed files with 411 additions and 435 deletions
|
@ -28,8 +28,8 @@ describe("Identity provider test", () => {
|
||||||
|
|
||||||
const keycloakServer = Cypress.env("KEYCLOAK_SERVER");
|
const keycloakServer = Cypress.env("KEYCLOAK_SERVER");
|
||||||
const discoveryUrl = `${keycloakServer}/auth/realms/master/.well-known/openid-configuration`;
|
const discoveryUrl = `${keycloakServer}/auth/realms/master/.well-known/openid-configuration`;
|
||||||
|
const samlDiscoveryUrl = `${keycloakServer}/auth/realms/master/protocol/saml/descriptor`;
|
||||||
const authorizationUrl = `${keycloakServer}/auth/realms/master/protocol/openid-connect/auth`;
|
const authorizationUrl = `${keycloakServer}/auth/realms/master/protocol/openid-connect/auth`;
|
||||||
const ssoServiceUrl = `${keycloakServer}/auth/realms/sso`;
|
|
||||||
|
|
||||||
describe("Identity provider creation", () => {
|
describe("Identity provider creation", () => {
|
||||||
const identityProviderName = "github";
|
const identityProviderName = "github";
|
||||||
|
@ -112,8 +112,8 @@ describe("Identity provider test", () => {
|
||||||
createProviderPage
|
createProviderPage
|
||||||
.clickCreateDropdown()
|
.clickCreateDropdown()
|
||||||
.clickItem(samlProviderName)
|
.clickItem(samlProviderName)
|
||||||
.toggleEntityDescriptor()
|
.fillDiscoveryUrl(samlDiscoveryUrl)
|
||||||
.fillSsoServiceUrl(ssoServiceUrl)
|
.shouldBeSuccessful()
|
||||||
.clickAdd();
|
.clickAdd();
|
||||||
masthead.checkNotificationMessage(createSuccessMsg);
|
masthead.checkNotificationMessage(createSuccessMsg);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,6 @@ export default class CreateProviderPage {
|
||||||
private clientSecretField = "clientSecret";
|
private clientSecretField = "clientSecret";
|
||||||
private discoveryEndpoint = "discoveryEndpoint";
|
private discoveryEndpoint = "discoveryEndpoint";
|
||||||
private authorizationUrl = "authorizationUrl";
|
private authorizationUrl = "authorizationUrl";
|
||||||
private useEntityDescriptorSwitch = "useEntityDescriptor";
|
|
||||||
private addButton = "createProvider";
|
private addButton = "createProvider";
|
||||||
private ssoServiceUrl = "sso-service-url";
|
private ssoServiceUrl = "sso-service-url";
|
||||||
|
|
||||||
|
@ -96,9 +95,4 @@ export default class CreateProviderPage {
|
||||||
cy.findByTestId(this.authorizationUrl).should("have.value", value);
|
cy.findByTestId(this.authorizationUrl).should("have.value", value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleEntityDescriptor() {
|
|
||||||
cy.findByTestId(this.useEntityDescriptorSwitch).click({ force: true });
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -7,7 +7,7 @@
|
||||||
"name": "keycloak-admin-ui",
|
"name": "keycloak-admin-ui",
|
||||||
"license": "Apache",
|
"license": "Apache",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keycloak/keycloak-admin-client": "^16.0.0-dev.34",
|
"@keycloak/keycloak-admin-client": "^16.0.0-dev.37",
|
||||||
"@patternfly/patternfly": "^4.144.5",
|
"@patternfly/patternfly": "^4.144.5",
|
||||||
"@patternfly/react-code-editor": "^4.3.85",
|
"@patternfly/react-code-editor": "^4.3.85",
|
||||||
"@patternfly/react-core": "^4.162.3",
|
"@patternfly/react-core": "^4.162.3",
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keycloak/keycloak-admin-client": "^16.0.0-dev.34",
|
"@keycloak/keycloak-admin-client": "^16.0.0-dev.37",
|
||||||
"@patternfly/patternfly": "^4.144.5",
|
"@patternfly/patternfly": "^4.144.5",
|
||||||
"@patternfly/react-code-editor": "^4.3.85",
|
"@patternfly/react-code-editor": "^4.3.85",
|
||||||
"@patternfly/react-core": "^4.162.3",
|
"@patternfly/react-core": "^4.162.3",
|
||||||
|
|
1
public/discovery-load-indicator.svg
Normal file
1
public/discovery-load-indicator.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><circle cx="50" cy="50" fill="none" stroke="#0066cc" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform></circle></svg>
|
After Width: | Height: | Size: 438 B |
159
src/components/json-file-upload/FileUploadForm.tsx
Normal file
159
src/components/json-file-upload/FileUploadForm.tsx
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
FormGroup,
|
||||||
|
FileUpload,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
Button,
|
||||||
|
FileUploadProps,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { CodeEditor, Language } from "@patternfly/react-code-editor";
|
||||||
|
|
||||||
|
type FileUploadType = {
|
||||||
|
value: string;
|
||||||
|
filename: string;
|
||||||
|
isLoading: boolean;
|
||||||
|
modal: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FileUploadEvent =
|
||||||
|
| React.DragEvent<HTMLElement> // User dragged/dropped a file
|
||||||
|
| React.ChangeEvent<HTMLTextAreaElement> // User typed in the TextArea
|
||||||
|
| React.MouseEvent<HTMLButtonElement, MouseEvent>; // User clicked Clear button
|
||||||
|
|
||||||
|
export type FileUploadFormProps = Omit<FileUploadProps, "onChange"> & {
|
||||||
|
id: string;
|
||||||
|
extension: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
helpText?: string;
|
||||||
|
unWrap?: boolean;
|
||||||
|
language?: Language;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FileUploadForm = ({
|
||||||
|
id,
|
||||||
|
onChange,
|
||||||
|
helpText = "common-help:helpFileUpload",
|
||||||
|
unWrap = false,
|
||||||
|
language,
|
||||||
|
extension,
|
||||||
|
...rest
|
||||||
|
}: FileUploadFormProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const defaultUpload: FileUploadType = {
|
||||||
|
value: "",
|
||||||
|
filename: "",
|
||||||
|
isLoading: false,
|
||||||
|
modal: false,
|
||||||
|
};
|
||||||
|
const [fileUpload, setFileUpload] = useState<FileUploadType>(defaultUpload);
|
||||||
|
const removeDialog = () => setFileUpload({ ...fileUpload, modal: false });
|
||||||
|
const handleChange = (
|
||||||
|
value: string | File,
|
||||||
|
filename: string,
|
||||||
|
event:
|
||||||
|
| React.DragEvent<HTMLElement>
|
||||||
|
| React.ChangeEvent<HTMLTextAreaElement>
|
||||||
|
| React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||||
|
): void => {
|
||||||
|
if (
|
||||||
|
event.nativeEvent instanceof MouseEvent &&
|
||||||
|
!(event.nativeEvent instanceof DragEvent)
|
||||||
|
) {
|
||||||
|
setFileUpload({ ...fileUpload, modal: true });
|
||||||
|
} else {
|
||||||
|
setFileUpload({
|
||||||
|
...fileUpload,
|
||||||
|
value: value.toString(),
|
||||||
|
filename,
|
||||||
|
});
|
||||||
|
|
||||||
|
onChange(value.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{fileUpload.modal && (
|
||||||
|
<Modal
|
||||||
|
variant={ModalVariant.small}
|
||||||
|
title={t("clearFile")}
|
||||||
|
isOpen
|
||||||
|
onClose={removeDialog}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="confirm"
|
||||||
|
variant="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setFileUpload(defaultUpload);
|
||||||
|
onChange("");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("clear")}
|
||||||
|
</Button>,
|
||||||
|
<Button key="cancel" variant="link" onClick={removeDialog}>
|
||||||
|
{t("cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{t("clearFileExplain")}
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
{unWrap && (
|
||||||
|
<FileUpload
|
||||||
|
id={id}
|
||||||
|
{...rest}
|
||||||
|
type="text"
|
||||||
|
value={fileUpload.value}
|
||||||
|
filename={fileUpload.filename}
|
||||||
|
onChange={handleChange}
|
||||||
|
onReadStarted={() =>
|
||||||
|
setFileUpload({ ...fileUpload, isLoading: true })
|
||||||
|
}
|
||||||
|
onReadFinished={() =>
|
||||||
|
setFileUpload({ ...fileUpload, isLoading: false })
|
||||||
|
}
|
||||||
|
isLoading={fileUpload.isLoading}
|
||||||
|
dropzoneProps={{
|
||||||
|
accept: extension,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!unWrap && (
|
||||||
|
<FormGroup
|
||||||
|
label={t("resourceFile")}
|
||||||
|
fieldId={id}
|
||||||
|
helperText={t(helpText)}
|
||||||
|
>
|
||||||
|
<FileUpload
|
||||||
|
id={id}
|
||||||
|
{...rest}
|
||||||
|
type="text"
|
||||||
|
value={fileUpload.value}
|
||||||
|
filename={fileUpload.filename}
|
||||||
|
onChange={handleChange}
|
||||||
|
onReadStarted={() =>
|
||||||
|
setFileUpload({ ...fileUpload, isLoading: true })
|
||||||
|
}
|
||||||
|
onReadFinished={() =>
|
||||||
|
setFileUpload({ ...fileUpload, isLoading: false })
|
||||||
|
}
|
||||||
|
isLoading={fileUpload.isLoading}
|
||||||
|
hideDefaultPreview
|
||||||
|
>
|
||||||
|
<CodeEditor
|
||||||
|
isLineNumbersVisible
|
||||||
|
code={fileUpload.value}
|
||||||
|
language={language}
|
||||||
|
height="128px"
|
||||||
|
onChange={(value, event) =>
|
||||||
|
handleChange(value ?? "", fileUpload.filename, event)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FileUpload>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,167 +1,31 @@
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
import {
|
import { Language } from "@patternfly/react-code-editor";
|
||||||
FormGroup,
|
|
||||||
FileUpload,
|
|
||||||
Modal,
|
|
||||||
ModalVariant,
|
|
||||||
Button,
|
|
||||||
FileUploadProps,
|
|
||||||
} from "@patternfly/react-core";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { CodeEditor, Language } from "@patternfly/react-code-editor";
|
|
||||||
|
|
||||||
type FileUpload = {
|
import { FileUploadForm, FileUploadFormProps } from "./FileUploadForm";
|
||||||
value: string;
|
|
||||||
filename: string;
|
|
||||||
isLoading: boolean;
|
|
||||||
modal: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type JsonFileUploadEvent =
|
export type JsonFileUploadProps = Omit<
|
||||||
| React.DragEvent<HTMLElement> // User dragged/dropped a file
|
FileUploadFormProps,
|
||||||
| React.ChangeEvent<HTMLTextAreaElement> // User typed in the TextArea
|
"onChange" | "language" | "extension"
|
||||||
| React.MouseEvent<HTMLButtonElement, MouseEvent>; // User clicked Clear button
|
> & {
|
||||||
|
|
||||||
export type JsonFileUploadProps = Omit<FileUploadProps, "onChange"> & {
|
|
||||||
id: string;
|
|
||||||
onChange: (obj: object) => void;
|
onChange: (obj: object) => void;
|
||||||
helpText?: string;
|
|
||||||
unWrap?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JsonFileUpload = ({
|
export const JsonFileUpload = ({ onChange, ...props }: JsonFileUploadProps) => {
|
||||||
id,
|
const handleChange = (value: string) => {
|
||||||
onChange,
|
try {
|
||||||
helpText = "common-help:helpFileUpload",
|
onChange(JSON.parse(value));
|
||||||
unWrap = false,
|
} catch (error) {
|
||||||
...rest
|
onChange({});
|
||||||
}: JsonFileUploadProps) => {
|
console.warn("Invalid json, ignoring value using {}");
|
||||||
const { t } = useTranslation();
|
|
||||||
const defaultUpload = {
|
|
||||||
value: "",
|
|
||||||
filename: "",
|
|
||||||
isLoading: false,
|
|
||||||
modal: false,
|
|
||||||
};
|
|
||||||
const [fileUpload, setFileUpload] = useState<FileUpload>(defaultUpload);
|
|
||||||
const removeDialog = () => setFileUpload({ ...fileUpload, modal: false });
|
|
||||||
const handleChange = (
|
|
||||||
value: string | File,
|
|
||||||
filename: string,
|
|
||||||
event:
|
|
||||||
| React.DragEvent<HTMLElement>
|
|
||||||
| React.ChangeEvent<HTMLTextAreaElement>
|
|
||||||
| React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
||||||
): void => {
|
|
||||||
if (
|
|
||||||
event.nativeEvent instanceof MouseEvent &&
|
|
||||||
!(event.nativeEvent instanceof DragEvent)
|
|
||||||
) {
|
|
||||||
setFileUpload({ ...fileUpload, modal: true });
|
|
||||||
} else {
|
|
||||||
setFileUpload({
|
|
||||||
...fileUpload,
|
|
||||||
value: value as string,
|
|
||||||
filename,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
let obj = {};
|
|
||||||
try {
|
|
||||||
obj = JSON.parse(value as string);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("Invalid json, ignoring value using {}");
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<FileUploadForm
|
||||||
{fileUpload.modal && (
|
{...props}
|
||||||
<Modal
|
language={Language.json}
|
||||||
variant={ModalVariant.small}
|
extension=".json"
|
||||||
title={t("clearFile")}
|
onChange={handleChange}
|
||||||
isOpen
|
/>
|
||||||
onClose={removeDialog}
|
|
||||||
actions={[
|
|
||||||
<Button
|
|
||||||
key="confirm"
|
|
||||||
variant="primary"
|
|
||||||
onClick={() => {
|
|
||||||
setFileUpload(defaultUpload);
|
|
||||||
onChange({});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("clear")}
|
|
||||||
</Button>,
|
|
||||||
<Button key="cancel" variant="link" onClick={removeDialog}>
|
|
||||||
{t("cancel")}
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{t("clearFileExplain")}
|
|
||||||
</Modal>
|
|
||||||
)}
|
|
||||||
{unWrap && (
|
|
||||||
<FileUpload
|
|
||||||
id={id}
|
|
||||||
{...rest}
|
|
||||||
type="text"
|
|
||||||
value={fileUpload.value}
|
|
||||||
filename={fileUpload.filename}
|
|
||||||
onChange={handleChange}
|
|
||||||
onReadStarted={() =>
|
|
||||||
setFileUpload({ ...fileUpload, isLoading: true })
|
|
||||||
}
|
|
||||||
onReadFinished={() =>
|
|
||||||
setFileUpload({ ...fileUpload, isLoading: false })
|
|
||||||
}
|
|
||||||
isLoading={fileUpload.isLoading}
|
|
||||||
dropzoneProps={{
|
|
||||||
accept: ".json",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!unWrap && (
|
|
||||||
<FormGroup
|
|
||||||
label={t("resourceFile")}
|
|
||||||
fieldId={id}
|
|
||||||
helperText={t(helpText)}
|
|
||||||
>
|
|
||||||
<FileUpload
|
|
||||||
id={id}
|
|
||||||
{...rest}
|
|
||||||
type="text"
|
|
||||||
value={fileUpload.value}
|
|
||||||
filename={fileUpload.filename}
|
|
||||||
onChange={handleChange}
|
|
||||||
onReadStarted={() =>
|
|
||||||
setFileUpload({ ...fileUpload, isLoading: true })
|
|
||||||
}
|
|
||||||
onReadFinished={() =>
|
|
||||||
setFileUpload({ ...fileUpload, isLoading: false })
|
|
||||||
}
|
|
||||||
isLoading={fileUpload.isLoading}
|
|
||||||
dropzoneProps={{
|
|
||||||
accept: ".json",
|
|
||||||
}}
|
|
||||||
hideDefaultPreview
|
|
||||||
>
|
|
||||||
<CodeEditor
|
|
||||||
isLineNumbersVisible
|
|
||||||
code={fileUpload.value}
|
|
||||||
language={Language.json}
|
|
||||||
height="128px"
|
|
||||||
onChange={(value, event) =>
|
|
||||||
handleChange(value ?? "", fileUpload.filename, event)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</FileUpload>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,12 +18,16 @@ import { SamlConnectSettings } from "./SamlConnectSettings";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
|
|
||||||
|
type DiscoveryIdentityProvider = IdentityProviderRepresentation & {
|
||||||
|
discoveryEndpoint?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default function AddSamlConnect() {
|
export default function AddSamlConnect() {
|
||||||
const { t } = useTranslation("identity-providers");
|
const { t } = useTranslation("identity-providers");
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const id = "saml";
|
const id = "saml";
|
||||||
|
|
||||||
const form = useForm<IdentityProviderRepresentation>({
|
const form = useForm<DiscoveryIdentityProvider>({
|
||||||
defaultValues: { alias: id },
|
defaultValues: { alias: id },
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
|
@ -35,7 +39,8 @@ export default function AddSamlConnect() {
|
||||||
const { addAlert } = useAlerts();
|
const { addAlert } = useAlerts();
|
||||||
const { realm } = useRealm();
|
const { realm } = useRealm();
|
||||||
|
|
||||||
const save = async (provider: IdentityProviderRepresentation) => {
|
const save = async (provider: DiscoveryIdentityProvider) => {
|
||||||
|
delete provider.discoveryEndpoint;
|
||||||
try {
|
try {
|
||||||
await adminClient.identityProviders.create({
|
await adminClient.identityProviders.create({
|
||||||
...provider,
|
...provider,
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { FormGroup, Switch, TextInput, Title } from "@patternfly/react-core";
|
import { FormGroup, Title } from "@patternfly/react-core";
|
||||||
|
|
||||||
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||||
import type { OIDCConfigurationRepresentation } from "../OIDCConfigurationRepresentation";
|
|
||||||
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
|
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
import { DiscoverySettings } from "./DiscoverySettings";
|
import { DiscoverySettings } from "./DiscoverySettings";
|
||||||
import { getBaseUrl } from "../../util";
|
import { getBaseUrl } from "../../util";
|
||||||
|
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
|
||||||
type Result = OIDCConfigurationRepresentation & {
|
|
||||||
error: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const OpenIdConnectSettings = () => {
|
export const OpenIdConnectSettings = () => {
|
||||||
const { t } = useTranslation("identity-providers");
|
const { t } = useTranslation("identity-providers");
|
||||||
|
@ -21,40 +17,13 @@ export const OpenIdConnectSettings = () => {
|
||||||
|
|
||||||
const adminClient = useAdminClient();
|
const adminClient = useAdminClient();
|
||||||
const { realm } = useRealm();
|
const { realm } = useRealm();
|
||||||
const { setValue, register, errors } = useFormContext();
|
const { setValue, errors, setError } = useFormContext();
|
||||||
|
|
||||||
const [discovery, setDiscovery] = useState(true);
|
|
||||||
const [discoveryUrl, setDiscoveryUrl] = useState("");
|
|
||||||
const [discovering, setDiscovering] = useState(false);
|
|
||||||
const [discoveryResult, setDiscoveryResult] = useState<Result>();
|
|
||||||
|
|
||||||
const setupForm = (result: any) => {
|
const setupForm = (result: any) => {
|
||||||
Object.keys(result).map((k) => setValue(`config.${k}`, result[k]));
|
Object.keys(result).map((k) => setValue(`config.${k}`, result[k]));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const fileUpload = async (obj?: object) => {
|
||||||
if (discovering) {
|
|
||||||
setDiscovering(!!discoveryUrl);
|
|
||||||
if (discoveryUrl)
|
|
||||||
(async () => {
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
result = await adminClient.identityProviders.importFromUrl({
|
|
||||||
providerId: id,
|
|
||||||
fromUrl: discoveryUrl,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
result = { error };
|
|
||||||
}
|
|
||||||
|
|
||||||
setDiscoveryResult(result as Result);
|
|
||||||
setupForm(result);
|
|
||||||
setDiscovering(false);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}, [discovering]);
|
|
||||||
|
|
||||||
const fileUpload = async (obj: object) => {
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("providerId", id);
|
formData.append("providerId", id);
|
||||||
|
@ -75,8 +44,11 @@ export const OpenIdConnectSettings = () => {
|
||||||
);
|
);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
setupForm(result);
|
setupForm(result);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
setDiscoveryResult({ error });
|
setError("discoveryError", {
|
||||||
|
type: "manual",
|
||||||
|
message: (error as Error).message,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -86,103 +58,36 @@ export const OpenIdConnectSettings = () => {
|
||||||
<Title headingLevel="h4" size="xl" className="kc-form-panel__title">
|
<Title headingLevel="h4" size="xl" className="kc-form-panel__title">
|
||||||
{t("oidcSettings")}
|
{t("oidcSettings")}
|
||||||
</Title>
|
</Title>
|
||||||
<FormGroup
|
|
||||||
label={t("useDiscoveryEndpoint")}
|
<DiscoveryEndpointField
|
||||||
fieldId="kc-discovery-endpoint-switch"
|
id="oidc"
|
||||||
labelIcon={
|
fileUpload={
|
||||||
<HelpItem
|
<FormGroup
|
||||||
helpText="identity-providers-help:useDiscoveryEndpoint"
|
label={t("importConfig")}
|
||||||
forLabel={t("useDiscoveryEndpoint")}
|
fieldId="kc-import-config"
|
||||||
forID="kc-discovery-endpoint-switch"
|
labelIcon={
|
||||||
/>
|
<HelpItem
|
||||||
|
helpText="identity-providers-help:importConfig"
|
||||||
|
forLabel={t("importConfig")}
|
||||||
|
forID="kc-import-config"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
validated={errors.discoveryError ? "error" : "default"}
|
||||||
|
helperTextInvalid={errors.discoveryError}
|
||||||
|
>
|
||||||
|
<JsonFileUpload
|
||||||
|
id="kc-import-config"
|
||||||
|
helpText="identity=providers-help:jsonFileUpload"
|
||||||
|
hideDefaultPreview
|
||||||
|
unWrap
|
||||||
|
validated={errors.discoveryError ? "error" : "default"}
|
||||||
|
onChange={(value) => fileUpload(value)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Switch
|
{(readonly) => <DiscoverySettings readOnly={readonly} />}
|
||||||
id="kc-discovery-endpoint-switch"
|
</DiscoveryEndpointField>
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={discovery}
|
|
||||||
onChange={setDiscovery}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
{discovery && (
|
|
||||||
<FormGroup
|
|
||||||
label={t("discoveryEndpoint")}
|
|
||||||
fieldId="kc-discovery-endpoint"
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText="identity-providers-help:discoveryEndpoint"
|
|
||||||
forLabel={t("discoveryEndpoint")}
|
|
||||||
forID="kc-discovery-endpoint"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
validated={
|
|
||||||
discoveryResult?.error || errors.discoveryEndpoint
|
|
||||||
? "error"
|
|
||||||
: !discoveryResult
|
|
||||||
? "default"
|
|
||||||
: "success"
|
|
||||||
}
|
|
||||||
helperTextInvalid={
|
|
||||||
errors.discoveryEndpoint
|
|
||||||
? t("common:required")
|
|
||||||
: t("noValidMetaDataFound")
|
|
||||||
}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<TextInput
|
|
||||||
type="text"
|
|
||||||
name="discoveryEndpoint"
|
|
||||||
data-testid="discoveryEndpoint"
|
|
||||||
id="kc-discovery-endpoint"
|
|
||||||
placeholder="https://hostname/auth/realms/master/.well-known/openid-configuration"
|
|
||||||
value={discoveryUrl}
|
|
||||||
onChange={setDiscoveryUrl}
|
|
||||||
onBlur={() => setDiscovering(!discovering)}
|
|
||||||
validated={
|
|
||||||
discoveryResult?.error || errors.discoveryEndpoint
|
|
||||||
? "error"
|
|
||||||
: !discoveryResult
|
|
||||||
? "default"
|
|
||||||
: "success"
|
|
||||||
}
|
|
||||||
customIconUrl={
|
|
||||||
discovering
|
|
||||||
? 'data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"%3E%3Ccircle cx="50" cy="50" fill="none" stroke="%230066cc" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138"%3E%3CanimateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"%3E%3C/animateTransform%3E%3C/circle%3E%3C/svg%3E'
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
ref={register({ required: true })}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
{!discovery && (
|
|
||||||
<FormGroup
|
|
||||||
label={t("importConfig")}
|
|
||||||
fieldId="kc-import-config"
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText="identity-providers-help:importConfig"
|
|
||||||
forLabel={t("importConfig")}
|
|
||||||
forID="kc-import-config"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
validated={discoveryResult?.error ? "error" : "default"}
|
|
||||||
helperTextInvalid={discoveryResult?.error?.toString()}
|
|
||||||
>
|
|
||||||
<JsonFileUpload
|
|
||||||
id="kc-import-config"
|
|
||||||
helpText="identity=providers-help:jsonFileUpload"
|
|
||||||
hideDefaultPreview
|
|
||||||
unWrap
|
|
||||||
validated={discoveryResult?.error ? "error" : "default"}
|
|
||||||
onChange={(value) => fileUpload(value)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
{discovery && discoveryResult && !discoveryResult.error && (
|
|
||||||
<DiscoverySettings readOnly={true} />
|
|
||||||
)}
|
|
||||||
{!discovery && <DiscoverySettings readOnly={false} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,26 +1,17 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import {
|
import { FormGroup, TextInput, Title } from "@patternfly/react-core";
|
||||||
FormGroup,
|
|
||||||
Switch,
|
|
||||||
TextInput,
|
|
||||||
Title,
|
|
||||||
ValidatedOptions,
|
|
||||||
} from "@patternfly/react-core";
|
|
||||||
|
|
||||||
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||||
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
||||||
|
|
||||||
import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload";
|
import { FileUploadForm } from "../../components/json-file-upload/FileUploadForm";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
import { DescriptorSettings } from "./DescriptorSettings";
|
import { DescriptorSettings } from "./DescriptorSettings";
|
||||||
import { getBaseUrl } from "../../util";
|
import { getBaseUrl } from "../../util";
|
||||||
|
import { DiscoveryEndpointField } from "../component/DiscoveryEndpointField";
|
||||||
type Result = IdentityProviderRepresentation & {
|
|
||||||
error: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SamlConnectSettings = () => {
|
export const SamlConnectSettings = () => {
|
||||||
const { t } = useTranslation("identity-providers");
|
const { t } = useTranslation("identity-providers");
|
||||||
|
@ -28,16 +19,7 @@ export const SamlConnectSettings = () => {
|
||||||
|
|
||||||
const adminClient = useAdminClient();
|
const adminClient = useAdminClient();
|
||||||
const { realm } = useRealm();
|
const { realm } = useRealm();
|
||||||
const { setValue, register, errors } = useFormContext();
|
const { setValue, register, errors, setError } = useFormContext();
|
||||||
|
|
||||||
const [descriptor, setDescriptor] = useState(true);
|
|
||||||
|
|
||||||
const [entityUrl, setEntityUrl] = useState("");
|
|
||||||
const [descriptorUrl, setDescriptorUrl] = useState("");
|
|
||||||
const [discovering, setDiscovering] = useState(false);
|
|
||||||
const [discoveryResult, setDiscoveryResult] = useState<Result>();
|
|
||||||
|
|
||||||
const defaultEntityUrl = `${getBaseUrl(adminClient)}realms/${realm}`;
|
|
||||||
|
|
||||||
const setupForm = (result: IdentityProviderRepresentation) => {
|
const setupForm = (result: IdentityProviderRepresentation) => {
|
||||||
Object.entries(result).map(([key, value]) =>
|
Object.entries(result).map(([key, value]) =>
|
||||||
|
@ -45,38 +27,10 @@ export const SamlConnectSettings = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const fileUpload = async (xml: string) => {
|
||||||
if (!discovering) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDiscovering(!!entityUrl);
|
|
||||||
|
|
||||||
if (!entityUrl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
result = await adminClient.identityProviders.importFromUrl({
|
|
||||||
providerId: id,
|
|
||||||
fromUrl: entityUrl,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
result = { error };
|
|
||||||
}
|
|
||||||
|
|
||||||
setDiscoveryResult(result as Result);
|
|
||||||
setupForm(result);
|
|
||||||
setDiscovering(false);
|
|
||||||
})();
|
|
||||||
}, [discovering]);
|
|
||||||
|
|
||||||
const fileUpload = async (obj: object) => {
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("providerId", id);
|
formData.append("providerId", id);
|
||||||
formData.append("file", new Blob([JSON.stringify(obj)]));
|
formData.append("file", new Blob([xml]));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
|
@ -93,8 +47,11 @@ export const SamlConnectSettings = () => {
|
||||||
);
|
);
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
setupForm(result);
|
setupForm(result);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
setDiscoveryResult({ error });
|
setError("discoveryError", {
|
||||||
|
type: "manual",
|
||||||
|
message: (error as Error).message,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,90 +77,39 @@ export const SamlConnectSettings = () => {
|
||||||
name="config.entityId"
|
name="config.entityId"
|
||||||
data-testid="serviceProviderEntityId"
|
data-testid="serviceProviderEntityId"
|
||||||
id="kc-service-provider-entity-id"
|
id="kc-service-provider-entity-id"
|
||||||
value={entityUrl || defaultEntityUrl}
|
|
||||||
onChange={setEntityUrl}
|
|
||||||
ref={register()}
|
ref={register()}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<DiscoveryEndpointField
|
||||||
label={t("useEntityDescriptor")}
|
id="saml"
|
||||||
fieldId="kc-use-entity-descriptor"
|
fileUpload={
|
||||||
labelIcon={
|
<FormGroup
|
||||||
<HelpItem
|
label={t("importConfig")}
|
||||||
helpText="identity-providers-help:useEntityDescriptor"
|
fieldId="kc-import-config"
|
||||||
forLabel={t("useEntityDescriptor")}
|
labelIcon={
|
||||||
forID="kc-use-entity-descriptor-switch"
|
<HelpItem
|
||||||
/>
|
helpText="identity-providers-help:importConfig"
|
||||||
|
forLabel={t("importConfig")}
|
||||||
|
forID="kc-import-config"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
validated={errors.discoveryError ? "error" : "default"}
|
||||||
|
helperTextInvalid={errors.discoveryError}
|
||||||
|
>
|
||||||
|
<FileUploadForm
|
||||||
|
id="kc-import-config"
|
||||||
|
extension=".xml"
|
||||||
|
hideDefaultPreview
|
||||||
|
unWrap
|
||||||
|
validated={errors.discoveryError ? "error" : "default"}
|
||||||
|
onChange={(value) => fileUpload(value)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Switch
|
{(readonly) => <DescriptorSettings readOnly={readonly} />}
|
||||||
id="kc-use-entity-descriptor-switch"
|
</DiscoveryEndpointField>
|
||||||
label={t("common:on")}
|
|
||||||
data-testid="useEntityDescriptor"
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={descriptor}
|
|
||||||
onChange={setDescriptor}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
{descriptor && (
|
|
||||||
<FormGroup
|
|
||||||
label={t("samlEntityDescriptor")}
|
|
||||||
fieldId="kc-saml-entity-descriptor"
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText="identity-providers-help:samlEntityDescriptor"
|
|
||||||
forLabel={t("samlEntityDescriptor")}
|
|
||||||
forID="kc-saml-entity-descriptor"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TextInput
|
|
||||||
type="text"
|
|
||||||
name="samlEntityDescriptor"
|
|
||||||
data-testid="samlEntityDescriptor"
|
|
||||||
id="kc-saml-entity-descriptor"
|
|
||||||
value={descriptorUrl}
|
|
||||||
onChange={setDescriptorUrl}
|
|
||||||
ref={register()}
|
|
||||||
validated={
|
|
||||||
errors.samlEntityDescriptor
|
|
||||||
? ValidatedOptions.error
|
|
||||||
: ValidatedOptions.default
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
{!descriptor && (
|
|
||||||
<FormGroup
|
|
||||||
label={t("importConfig")}
|
|
||||||
fieldId="kc-import-config"
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText="identity-providers-help:importConfig"
|
|
||||||
forLabel={t("importConfig")}
|
|
||||||
forID="kc-import-config"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
validated={discoveryResult?.error ? "error" : "default"}
|
|
||||||
helperTextInvalid={discoveryResult?.error.toString()}
|
|
||||||
>
|
|
||||||
<JsonFileUpload
|
|
||||||
id="kc-import-config"
|
|
||||||
helpText="identity-providers-help:jsonFileUpload"
|
|
||||||
hideDefaultPreview
|
|
||||||
unWrap
|
|
||||||
validated={discoveryResult?.error ? "error" : "default"}
|
|
||||||
onChange={(value) => fileUpload(value)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{descriptor && discoveryResult && !discoveryResult.error && (
|
|
||||||
<DescriptorSettings readOnly={true} />
|
|
||||||
)}
|
|
||||||
{!descriptor && <DescriptorSettings readOnly={false} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
142
src/identity-providers/component/DiscoveryEndpointField.tsx
Normal file
142
src/identity-providers/component/DiscoveryEndpointField.tsx
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import React, { ReactNode, useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useFormContext } from "react-hook-form";
|
||||||
|
import { FormGroup, TextInput, Switch } from "@patternfly/react-core";
|
||||||
|
|
||||||
|
import environment from "../../environment";
|
||||||
|
import { HelpItem } from "../../components/help-enabler/HelpItem";
|
||||||
|
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||||
|
|
||||||
|
type DiscoveryEndpointFieldProps = {
|
||||||
|
id: string;
|
||||||
|
fileUpload: ReactNode;
|
||||||
|
children: (readOnly: boolean) => ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DiscoveryEndpointField = ({
|
||||||
|
id,
|
||||||
|
fileUpload,
|
||||||
|
children,
|
||||||
|
}: DiscoveryEndpointFieldProps) => {
|
||||||
|
const { t } = useTranslation("identity-providers");
|
||||||
|
|
||||||
|
const adminClient = useAdminClient();
|
||||||
|
|
||||||
|
const { setValue, register, errors, setError, watch, clearErrors } =
|
||||||
|
useFormContext();
|
||||||
|
const discoveryUrl = watch("discoveryEndpoint");
|
||||||
|
|
||||||
|
const [discovery, setDiscovery] = useState(true);
|
||||||
|
const [discovering, setDiscovering] = useState(false);
|
||||||
|
const [discoveryResult, setDiscoveryResult] =
|
||||||
|
useState<Record<string, string>>();
|
||||||
|
|
||||||
|
const setupForm = (result: Record<string, string>) => {
|
||||||
|
Object.keys(result).map((k) => setValue(`config.${k}`, result[k]));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!discoveryUrl) {
|
||||||
|
setDiscovering(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
clearErrors("discoveryError");
|
||||||
|
try {
|
||||||
|
const result = await adminClient.identityProviders.importFromUrl({
|
||||||
|
providerId: id,
|
||||||
|
fromUrl: discoveryUrl,
|
||||||
|
});
|
||||||
|
setupForm(result);
|
||||||
|
setDiscoveryResult(result);
|
||||||
|
} catch (error) {
|
||||||
|
setError("discoveryError", {
|
||||||
|
type: "manual",
|
||||||
|
message: (error as Error).message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setDiscovering(false);
|
||||||
|
})();
|
||||||
|
}, [discovering]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormGroup
|
||||||
|
label={t("useDiscoveryEndpoint")}
|
||||||
|
fieldId="kc-discovery-endpoint-switch"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="identity-providers-help:useDiscoveryEndpoint"
|
||||||
|
forLabel={t("useDiscoveryEndpoint")}
|
||||||
|
forID="kc-discovery-endpoint-switch"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
id="kc-discovery-endpoint-switch"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={discovery}
|
||||||
|
onChange={setDiscovery}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{discovery && (
|
||||||
|
<FormGroup
|
||||||
|
label={t("discoveryEndpoint")}
|
||||||
|
fieldId="kc-discovery-endpoint"
|
||||||
|
labelIcon={
|
||||||
|
<HelpItem
|
||||||
|
helpText="identity-providers-help:discoveryEndpoint"
|
||||||
|
forLabel={t("discoveryEndpoint")}
|
||||||
|
forID="kc-discovery-endpoint"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
validated={
|
||||||
|
errors.discoveryError || errors.discoveryEndpoint
|
||||||
|
? "error"
|
||||||
|
: !discoveryResult
|
||||||
|
? "default"
|
||||||
|
: "success"
|
||||||
|
}
|
||||||
|
helperTextInvalid={
|
||||||
|
errors.discoveryEndpoint
|
||||||
|
? t("common:required")
|
||||||
|
: t("noValidMetaDataFound")
|
||||||
|
}
|
||||||
|
isRequired
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
name="discoveryEndpoint"
|
||||||
|
data-testid="discoveryEndpoint"
|
||||||
|
id="kc-discovery-endpoint"
|
||||||
|
placeholder={
|
||||||
|
id === "oidc"
|
||||||
|
? "https://hostname/auth/realms/master/.well-known/openid-configuration"
|
||||||
|
: "https://hostname/context/saml/discovery"
|
||||||
|
}
|
||||||
|
onBlur={() => setDiscovering(true)}
|
||||||
|
validated={
|
||||||
|
errors.discoveryError || errors.discoveryEndpoint
|
||||||
|
? "error"
|
||||||
|
: !discoveryResult
|
||||||
|
? "default"
|
||||||
|
: "success"
|
||||||
|
}
|
||||||
|
customIconUrl={
|
||||||
|
discovering
|
||||||
|
? environment.resourceUrl + "./discovery-load-indicator.svg"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
ref={register({ required: true })}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
{!discovery && fileUpload}
|
||||||
|
{discovery && !errors.discoveryError && children(true)}
|
||||||
|
{!discovery && children(false)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in a new issue