author jenny-s51 <jshandel@redhat.com> 1624022352 -0400
committer jenny-s51 <jshandel@redhat.com> 1625159705 -0400

wip provider details

provider details wip

move files wip

wip

wip all provider details

remove controllers

save and update working

address console warnings

remove log stmt

update test

keep aes only

remove comments

remove unused hook and function

remove unused props

revert ldap logs

fix conflict and remove duplicate function

format and cypress test

Partial import phase 2 (#702)

* Process the JSON and present user options

* Finish checkboxes.  Refactor.

* Add tests

* Refactor after rebase

* Add more test data for manual testing.

* Fix linting errors

* Put JsonFileUpload back the way it was.

* Clean up comments

* Update src/realm-settings/PartialImport.tsx

Remove comment

Co-authored-by: Jenny <32821331+jenny-s51@users.noreply.github.com>

Co-authored-by: Jenny <32821331+jenny-s51@users.noreply.github.com>

Localization tab (#685)

* localization wip

wip localization

return key value data as array

localization table

css

lint

lint

clean up log stmts

clean up log stmts

* PR feedback from Erik

* fix logic for supported locales

* update empty state text

* set default value

* fix cypress test

* Update src/realm-settings/RealmSettingsSection.tsx

Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* fix rsa-generated delete bug; PR feedback frog Erik

* revert locale abbreviation

* remove log stmts

* PR feedback from Erik, fix undefined

* fix loader w Erik

Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

add divider on section

Prepare for first alpha release (#711)

use typeahead for mapper list

fix test

Default roles: UI Changes from KEYCLOAK-14846 (#693)

* defaultRoles wip

default role changes done

clean up log stmts

update snapshot

fix masthead test

* fix cypress test

* fix tabs

Comment out Realm role CRUD test (#712)

* Bogus change

* Bogus change

* Comment out Realm role CRUD test

Bump postcss-cli from 7.1.1 to 8.3.1 (#718)

Bumps [postcss-cli](https://github.com/postcss/postcss-cli) from 7.1.1 to 8.3.1.
- [Release notes](https://github.com/postcss/postcss-cli/releases)
- [Changelog](https://github.com/postcss/postcss-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-cli/compare/7.1.1...8.3.1)

---
updated-dependencies:
- dependency-name: postcss-cli
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

Bump @testing-library/jest-dom from 5.12.0 to 5.14.1 (#717)

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.12.0 to 5.14.1.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.12.0...v5.14.1)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

fixing issue (#709)

* fixing issue

fixing: #680

* added kebab on row

* added more clear group seperation

Bump cypress from 7.4.0 to 7.5.0 (#715)

Bump @babel/preset-typescript from 7.13.0 to 7.14.5 (#714)

Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.13.0 to 7.14.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.5/packages/babel-preset-typescript)

---
updated-dependencies:
- dependency-name: "@babel/preset-typescript"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

Bump @testing-library/react from 10.4.6 to 11.2.7 (#716)

Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 10.4.6 to 11.2.7.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v10.4.6...v11.2.7)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

inherited roles disabled instead of non selectable

more style fixes

fixed size

change title of tab

add unassign kebab on row

added help item on enable switch

test email working, modal wip

email connection done

remove comment

fix cypress test

revert test file

fdisable email prompting when user email entered

prettier

update cypress tests

fix lint

try fix cypress test

try longer wait

save and test connection

make wait longer

increase wait

fix test

disable test connection button if form fields not entered

lint

afix username/password fields

fix test

mark suggested change

add modal button and input functions

fixed default value warning

fixing issue

fixing: #650

remove provider form

add delete cleanup function

AESproviderDetails extend wait for video

update test

test wait after

rebase

remove comments

remove log

format

format

PR feedback from Jon

Apply suggestions from Jon's code review

Co-authored-by: Jon Koops <jonkoops@gmail.com>

remove duplicate form

form

use array desctructuring

Apply suggestions from code review

Co-authored-by: Jon Koops <jonkoops@gmail.com>

update useroutematch

format

format

back to async

pretty

cypress test

remove email verification switch toggle

fix add provider on non-master realm

cleaning up

fix save

fix save for other providers

fix fetch

fix runtime error

remove unused import

Apply suggestions from code review

suggested changes for non-null assertions

Co-authored-by: Jon Koops <jonkoops@gmail.com>

make props required

make provider type required

use realm-settings file for translation

format and roll back route changes
This commit is contained in:
Jenny 2021-07-12 14:19:50 -04:00 committed by GitHub
parent 13a20d2e42
commit 9ad9d6c314
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 558 additions and 384 deletions

View file

@ -40,6 +40,18 @@ describe("Realm settings", () => {
return this;
};
const goToDetails = () => {
const keysUrl = `/auth/admin/realms/${realmName}/keys`;
cy.intercept(keysUrl).as("keysFetch");
cy.getId("rs-keys-tab").click();
cy.getId("rs-providers-tab").click();
cy.getId("provider-name-link").contains("test_aes-generated").click();
cy.wait(["@keysFetch"]);
return this;
};
const addBundle = () => {
const localizationUrl = `/auth/admin/realms/${realmName}/localization/en`;
cy.intercept(localizationUrl).as("localizationFetch");
@ -191,6 +203,11 @@ describe("Realm settings", () => {
realmSettingsPage.addProvider();
});
it("go to details", () => {
sidebarPage.goToRealmSettings();
goToDetails();
});
it("Test keys", () => {
sidebarPage.goToRealmSettings();
goToKeys();

View file

@ -43,6 +43,8 @@ export default class RealmSettingsPage {
confirmAddBundle = "add-bundle-confirm-button";
keyInput = "key-input";
valueInput = "value-input";
deleteAction = "delete-action";
modalConfirm = "modalConfirm";
selectLoginThemeType(themeType: string) {
cy.get(this.selectLoginTheme).click();
@ -75,7 +77,7 @@ export default class RealmSettingsPage {
}
fillHostField(host: string) {
cy.get(this.hostInput).type(host);
cy.get(this.hostInput).clear().type(host);
return this;
}
@ -151,6 +153,17 @@ export default class RealmSettingsPage {
return this;
}
deleteProvider(providerName: string) {
cy.getId("provider-name-link")
.contains(providerName)
.parent()
.siblings(".pf-c-data-list__item-action")
.click()
.getId(this.deleteAction)
.click();
cy.wait(500).getId(this.modalConfirm).click();
}
enterConsoleDisplayName(name: string) {
cy.getId(this.displayName).clear().type(name);
}

View file

@ -1,251 +0,0 @@
import React, { useState } from "react";
import {
AlertVariant,
Button,
ButtonVariant,
Form,
FormGroup,
Modal,
ModalVariant,
Select,
SelectOption,
SelectVariant,
Switch,
TextInput,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import { Controller, useForm } from "react-hook-form";
import { useAdminClient } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
type AESGeneratedModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
open: boolean;
};
export const AESGeneratedModal = ({
providerType,
handleModalToggle,
open,
refresh,
}: // save,
AESGeneratedModalProps) => {
const { t } = useTranslation("groups");
const serverInfo = useServerInfo();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { handleSubmit, control } = useForm({});
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
AlertVariant.danger
);
}
};
return (
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
<Button
data-testid="add-provider-button"
key="confirm"
variant="primary"
type="submit"
form="add-provider"
>
{t("common:Add")}
</Button>,
<Button
id="modal-cancel"
key="cancel"
variant={ButtonVariant.link}
onClick={() => {
handleModalToggle!();
}}
>
{t("common:cancel")}
</Button>,
]}
>
<Form
isHorizontal
id="add-provider"
className="pf-u-mt-lg"
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
helpText="realm-settings-help:displayName"
forLabel={t("loginTheme")}
forID="kc-console-display-name"
/>
}
>
<Controller
name="name"
control={control}
defaultValue={providerType}
render={({ onChange }) => (
<TextInput
aria-label={t("consoleDisplayName")}
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
)}
/>
</FormGroup>
<FormGroup
label={t("common:enabled")}
fieldId="kc-enabled"
labelIcon={
<HelpItem
helpText={t("realm-settings-help:enabled")}
forLabel={t("enabled")}
forID="kc-enabled"
/>
}
>
<Controller
name="config.enabled"
control={control}
defaultValue={["true"]}
render={({ onChange, value }) => (
<Switch
id="kc-enabled"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value[0] === "true"}
data-testid={
value[0] === "true"
? "internationalization-enabled"
: "internationalization-disabled"
}
onChange={(value) => {
onChange([value + ""]);
}}
/>
)}
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
fieldId="kc-active"
labelIcon={
<HelpItem
helpText="realm-settings-help:active"
forLabel={t("active")}
forID="kc-active"
/>
}
>
<Controller
name="config.active"
control={control}
defaultValue={["true"]}
render={({ onChange, value }) => (
<Switch
id="kc-active"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value[0] === "true"}
data-testid={
value[0] === "true"
? "internationalization-enabled"
: "internationalization-disabled"
}
onChange={(value) => {
onChange([value + ""]);
}}
/>
)}
/>
</FormGroup>
{providerType === "aes-generated" && (
<FormGroup
label={t("realm-settings:AESKeySize")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem
helpText="realm-settings-help:AESKeySize"
forLabel={t("AESKeySize")}
forID="kc-aes-key-size"
/>
}
>
<Controller
name="config.secretSize"
control={control}
defaultValue={["16"]}
render={({ onChange, value }) => (
<Select
toggleId="kc-aes-keysize"
onToggle={() =>
setIsKeySizeDropdownOpen(!isKeySizeDropdownOpen)
}
onSelect={(_, value) => {
onChange([value + ""]);
setIsKeySizeDropdownOpen(false);
}}
selections={[value + ""]}
isOpen={isKeySizeDropdownOpen}
variant={SelectVariant.single}
aria-label={t("aesKeySize")}
data-testid="select-secret-size"
>
{allComponentTypes[0].properties[3].options!.map(
(item, idx) => (
<SelectOption
selected={item === value}
key={`email-theme-${idx}`}
value={item}
/>
)
)}
</Select>
)}
/>
</FormGroup>
)}
</Form>
</Modal>
);
};

View file

@ -22,12 +22,11 @@ import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
type ECDSAGeneratedModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
@ -36,9 +35,8 @@ export const ECDSAGeneratedModal = ({
handleModalToggle,
open,
refresh,
}: // save,
ECDSAGeneratedModalProps) => {
const { t } = useTranslation("groups");
}: ECDSAGeneratedModalProps) => {
const { t } = useTranslation("realm-settings");
const serverInfo = useServerInfo();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
@ -46,31 +44,29 @@ ECDSAGeneratedModalProps) => {
const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] =
useState(false);
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const [keyFileName, setKeyFileName] = useState("");
const [certificateFileName, setCertificateFileName] = useState("");
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh();
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
@ -80,7 +76,7 @@ ECDSAGeneratedModalProps) => {
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
@ -112,7 +108,7 @@ ECDSAGeneratedModalProps) => {
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
label={t("consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
@ -132,7 +128,6 @@ ECDSAGeneratedModalProps) => {
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
@ -173,7 +168,7 @@ ECDSAGeneratedModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
@ -208,7 +203,7 @@ ECDSAGeneratedModalProps) => {
{providerType === "rsa" && (
<>
<FormGroup
label={t("realm-settings:algorithm")}
label={t("algorithm")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem
@ -252,7 +247,7 @@ ECDSAGeneratedModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:privateRSAKey")}
label={t("privateRSAKey")}
fieldId="kc-private-rsa-key"
labelIcon={
<HelpItem
@ -282,13 +277,13 @@ ECDSAGeneratedModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:x509Certificate")}
label={t("x509Certificate")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem
helpText="realm-settings-help:x509Certificate"
forLabel={t("x509Certificate")}
forID="kc-x509-certificatw"
forID="kc-x509-certificate"
/>
}
>
@ -315,7 +310,7 @@ ECDSAGeneratedModalProps) => {
)}
{providerType === "ecdsa-generated" && (
<FormGroup
label={t("realm-settings:ellipticCurve")}
label={t("ellipticCurve")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem

View file

@ -21,12 +21,11 @@ import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
type HMACGeneratedModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
@ -35,9 +34,8 @@ export const HMACGeneratedModal = ({
handleModalToggle,
open,
refresh,
}: // save,
HMACGeneratedModalProps) => {
const { t } = useTranslation("groups");
}: HMACGeneratedModalProps) => {
const { t } = useTranslation("realm-settings");
const serverInfo = useServerInfo();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
@ -45,28 +43,26 @@ HMACGeneratedModalProps) => {
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] =
useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
handleModalToggle();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh();
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
@ -76,7 +72,7 @@ HMACGeneratedModalProps) => {
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
@ -108,7 +104,7 @@ HMACGeneratedModalProps) => {
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
label={t("consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
@ -128,7 +124,6 @@ HMACGeneratedModalProps) => {
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
@ -169,7 +164,7 @@ HMACGeneratedModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
@ -204,7 +199,7 @@ HMACGeneratedModalProps) => {
{providerType === "hmac-generated" && (
<>
<FormGroup
label={t("realm-settings:secretSize")}
label={t("secretSize")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem
@ -248,7 +243,7 @@ HMACGeneratedModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:algorithm")}
label={t("algorithm")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem

View file

@ -21,12 +21,11 @@ import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
type JavaKeystoreModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
@ -44,28 +43,26 @@ JavaKeystoreModalProps) => {
const { handleSubmit, control } = useForm({});
const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] =
useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
handleModalToggle();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh();
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
@ -75,7 +72,7 @@ JavaKeystoreModalProps) => {
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
@ -107,7 +104,7 @@ JavaKeystoreModalProps) => {
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
label={t("consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
@ -127,7 +124,6 @@ JavaKeystoreModalProps) => {
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
@ -168,7 +164,7 @@ JavaKeystoreModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
@ -203,7 +199,7 @@ JavaKeystoreModalProps) => {
{providerType === "java-keystore" && (
<>
<FormGroup
label={t("realm-settings:algorithm")}
label={t("algorithm")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem
@ -250,7 +246,7 @@ JavaKeystoreModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:keystore")}
label={t("keystore")}
fieldId="kc-login-theme"
labelIcon={
<HelpItem
@ -276,7 +272,7 @@ JavaKeystoreModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:keystorePassword")}
label={t("keystorePassword")}
fieldId="kc-login-theme"
labelIcon={
<HelpItem
@ -295,7 +291,6 @@ JavaKeystoreModalProps) => {
aria-label={t("consoleDisplayName")}
onChange={(value) => {
onChange([value + ""]);
setDisplayName(value);
}}
data-testid="select-display-name"
></TextInput>
@ -303,7 +298,7 @@ JavaKeystoreModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:keyAlias")}
label={t("keyAlias")}
fieldId="kc-login-theme"
labelIcon={
<HelpItem
@ -329,7 +324,7 @@ JavaKeystoreModalProps) => {
/>
</FormGroup>
<FormGroup
label={t("realm-settings:keyPassword")}
label={t("keyPassword")}
fieldId="kc-login-theme"
labelIcon={
<HelpItem
@ -348,7 +343,6 @@ JavaKeystoreModalProps) => {
aria-label={t("consoleDisplayName")}
onChange={(value) => {
onChange([value + ""]);
setDisplayName(value);
}}
data-testid="select-display-name"
></TextInput>

View file

@ -37,7 +37,7 @@ import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { useRealm } from "../context/realm-context/RealmContext";
import { Link, useRouteMatch } from "react-router-dom";
import { AESGeneratedModal } from "./AESGeneratedModal";
import { AESGeneratedModal } from "./key-providers/aes-generated/AESGeneratedModal";
import { JavaKeystoreModal } from "./JavaKeystoreModal";
import { HMACGeneratedModal } from "./HMACGeneratedModal";
import { ECDSAGeneratedModal } from "./ECDSAGeneratedModal";
@ -369,6 +369,7 @@ export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
isOpen={actionListOpen[idx]}
toggle={
<KebabToggle
data-testid="provider-action"
onToggle={() => {
toggleActionList(idx);
}}
@ -378,13 +379,14 @@ export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => {
<DropdownItem
key="action"
component="button"
data-testid="delete-action"
onClick={() => {
setSelectedComponent(component);
toggleDeleteDialog();
toggleActionList(idx);
}}
>
Delete
{t("common:delete")}
</DropdownItem>,
]}
/>
@ -409,7 +411,7 @@ type KeysProps = {
refresh: () => void;
};
export const KeysProviderTab = ({
export const KeysProvidersTab = ({
keyProviderComponentTypes,
realmComponents,
refresh,

View file

@ -80,7 +80,6 @@ export const LocalizationTab = ({
});
return Object.keys(result).map((key) => [key, result[key]]);
}
return [[]];
};
@ -233,7 +232,6 @@ export const LocalizationTab = ({
onSelect={(_, value) => {
onChange(value as string);
setValueSelected(true);
// setSelectedLocale(value as string);
setKey(new Date().getTime());
setDefaultLocaleOpen(false);
}}

View file

@ -21,12 +21,11 @@ import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
type RSAGeneratedModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
@ -36,35 +35,33 @@ export const RSAGeneratedModal = ({
open,
refresh,
}: RSAGeneratedModalProps) => {
const { t } = useTranslation("groups");
const { t } = useTranslation("realm-settings");
const serverInfo = useServerInfo();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { handleSubmit, control } = useForm({});
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
handleModalToggle();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh();
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
@ -74,7 +71,7 @@ export const RSAGeneratedModal = ({
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
@ -106,7 +103,7 @@ export const RSAGeneratedModal = ({
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
label={t("consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
@ -126,7 +123,6 @@ export const RSAGeneratedModal = ({
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
@ -167,7 +163,7 @@ export const RSAGeneratedModal = ({
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
@ -202,7 +198,7 @@ export const RSAGeneratedModal = ({
{providerType === "rsa-generated" && (
<>
<FormGroup
label={t("realm-settings:algorithm")}
label={t("algorithm")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem
@ -246,7 +242,7 @@ export const RSAGeneratedModal = ({
/>
</FormGroup>
<FormGroup
label={t("realm-settings:AESKeySize")}
label={t("AESKeySize")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem

View file

@ -22,12 +22,12 @@ import { useAlerts } from "../components/alert/Alerts";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../components/help-enabler/HelpItem";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useRealm } from "../context/realm-context/RealmContext";
import { useParams } from "react-router-dom";
type RSAModalProps = {
providerType?: string;
handleModalToggle?: () => void;
refresh?: () => void;
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
@ -37,37 +37,50 @@ export const RSAModal = ({
open,
refresh,
}: RSAModalProps) => {
const { t } = useTranslation("groups");
const { t } = useTranslation("realm-settings");
const serverInfo = useServerInfo();
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { handleSubmit, control } = useForm({});
const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false);
const [displayName, setDisplayName] = useState("");
const realm = useRealm();
const { id } = useParams<{ id: string }>();
const [keyFileName, setKeyFileName] = useState("");
const [certificateFileName, setCertificateFileName] = useState("");
const allComponentTypes =
serverInfo.componentTypes!["org.keycloak.keys.KeyProvider"];
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const save = async (component: ComponentRepresentation) => {
try {
await adminClient.components.create({
parentId: realm.realm,
name: displayName !== "" ? displayName : providerType,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
...component,
});
refresh!();
addAlert(t("realm-settings:saveProviderSuccess"), AlertVariant.success);
handleModalToggle!();
if (id) {
await adminClient.components.update(
{ id },
{
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
}
);
addAlert(t("saveProviderSuccess"), AlertVariant.success);
} else {
await adminClient.components.create({
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
});
handleModalToggle();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh();
}
} catch (error) {
addAlert(
t("realm-settings:saveProviderError") +
error.response?.data?.errorMessage || error,
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
@ -77,7 +90,7 @@ export const RSAModal = ({
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("realm-settings:addProvider")}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
actions={[
@ -109,7 +122,7 @@ export const RSAModal = ({
onSubmit={handleSubmit(save!)}
>
<FormGroup
label={t("realm-settings:consoleDisplayName")}
label={t("consoleDisplayName")}
fieldId="kc-console-display-name"
labelIcon={
<HelpItem
@ -129,7 +142,6 @@ export const RSAModal = ({
defaultValue={providerType}
onChange={(value) => {
onChange(value);
setDisplayName(value);
}}
data-testid="display-name-input"
></TextInput>
@ -170,7 +182,7 @@ export const RSAModal = ({
/>
</FormGroup>
<FormGroup
label={t("realm-settings:active")}
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
@ -205,7 +217,7 @@ export const RSAModal = ({
{providerType === "rsa" && (
<>
<FormGroup
label={t("realm-settings:algorithm")}
label={t("algorithm")}
fieldId="kc-algorithm"
labelIcon={
<HelpItem
@ -248,7 +260,7 @@ export const RSAModal = ({
/>
</FormGroup>
<FormGroup
label={t("realm-settings:privateRSAKey")}
label={t("privateRSAKey")}
fieldId="kc-private-rsa-key"
labelIcon={
<HelpItem
@ -278,7 +290,7 @@ export const RSAModal = ({
/>
</FormGroup>
<FormGroup
label={t("realm-settings:x509Certificate")}
label={t("x509Certificate")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem

View file

@ -29,7 +29,7 @@ import { RealmSettingsEmailTab } from "./EmailTab";
import { KeysListTab } from "./KeysListTab";
import { EventsTab } from "./event-config/EventsTab";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { KeysProviderTab } from "./KeysProvidersTab";
import { KeysProvidersTab } from "./KeysProvidersTab";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { LocalizationTab } from "./LocalizationTab";
import { WhoAmIContext } from "../context/whoami/WhoAmI";
@ -266,7 +266,7 @@ export const RealmSettingsSection = () => {
eventKey={1}
title={<TabTitleText>{t("providers")}</TabTitleText>}
>
<KeysProviderTab
<KeysProvidersTab
realmComponents={realmComponents}
keyProviderComponentTypes={kpComponentTypes}
refresh={refresh}

View file

@ -0,0 +1,360 @@
import React, { useState } from "react";
import {
ActionGroup,
AlertVariant,
Button,
FormGroup,
PageSection,
Select,
SelectOption,
SelectVariant,
Switch,
TextInput,
ValidatedOptions,
} from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import { Controller, useForm } from "react-hook-form";
import type ComponentRepresentation from "keycloak-admin/lib/defs/componentRepresentation";
import { HelpItem } from "../../../components/help-enabler/HelpItem";
import { useServerInfo } from "../../../context/server-info/ServerInfoProvider";
import { useAdminClient, useFetch } from "../../../context/auth/AdminClient";
import { useParams, useRouteMatch } from "react-router-dom";
import { FormAccess } from "../../../components/form-access/FormAccess";
import { ViewHeader } from "../../../components/view-header/ViewHeader";
import { convertToFormValues } from "../../../util";
import { useAlerts } from "../../../components/alert/Alerts";
type AESGeneratedFormProps = {
handleModalToggle?: () => void;
refresh?: () => void;
editMode?: boolean;
providerType: string;
};
export interface MatchParams {
providerType: string;
}
export const AESGeneratedForm = ({
editMode,
providerType,
handleModalToggle,
refresh,
}: AESGeneratedFormProps) => {
const { t } = useTranslation("realm-settings");
const serverInfo = useServerInfo();
const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false);
const adminClient = useAdminClient();
const { addAlert } = useAlerts();
const { id } = useParams<{ id: string }>();
const providerId =
useRouteMatch<MatchParams>("/:providerType?")?.params.providerType;
const save = async (component: ComponentRepresentation) => {
try {
if (id) {
await adminClient.components.update(
{ id },
{
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
}
);
addAlert(t("saveProviderSuccess"), AlertVariant.success);
} else {
await adminClient.components.create({
...component,
parentId: component.parentId,
providerId: providerType,
providerType: "org.keycloak.keys.KeyProvider",
});
handleModalToggle?.();
addAlert(t("saveProviderSuccess"), AlertVariant.success);
refresh?.();
}
} catch (error) {
addAlert(
t("saveProviderError", {
error: error.response?.data?.errorMessage || error,
}),
AlertVariant.danger
);
}
};
const form = useForm<ComponentRepresentation>({ mode: "onChange" });
const setupForm = (component: ComponentRepresentation) => {
form.reset();
Object.entries(component).map(([key, value]) => {
if (
key === "config" &&
component.config?.secretSize &&
component.config?.active
) {
form.setValue("config.secretSize", value.secretSize[0]);
form.setValue("config.active", value.active[0]);
convertToFormValues(value, "config", form.setValue);
}
form.setValue(key, value);
});
};
useFetch(
async () => {
if (editMode) return await adminClient.components.findOne({ id: id });
},
(result) => {
if (result) {
setupForm(result);
}
},
[]
);
const allComponentTypes =
serverInfo.componentTypes?.["org.keycloak.keys.KeyProvider"] ?? [];
const aesSecretSizeOptions = allComponentTypes[0].properties[3].options;
return (
<FormAccess
isHorizontal
id="add-provider"
className="pf-u-mt-lg"
role="manage-realm"
onSubmit={form.handleSubmit(save)}
>
{editMode && (
<FormGroup
label={t("providerId")}
labelIcon={
<HelpItem
helpText="client-scopes-help:mapperName"
forLabel={t("common:name")}
forID="name"
/>
}
fieldId="id"
isRequired
validated={
form.errors.name ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
<TextInput
ref={form.register()}
id="id"
type="text"
name="id"
isReadOnly={editMode}
aria-label={t("consoleDisplayName")}
defaultValue={id}
data-testid="display-name-input"
/>
</FormGroup>
)}
<FormGroup
label={t("common:name")}
labelIcon={
<HelpItem
helpText="client-scopes-help:mapperName"
forLabel={t("common:name")}
forID="name"
/>
}
fieldId="name"
isRequired
validated={
form.errors.name ? ValidatedOptions.error : ValidatedOptions.default
}
helperTextInvalid={t("common:required")}
>
{!editMode && (
<Controller
name="name"
control={form.control}
defaultValue={providerType}
render={({ onChange, value }) => {
return (
<TextInput
id="name"
type="text"
aria-label={t("consoleDisplayName")}
defaultValue={providerType}
value={value}
onChange={(value) => onChange(value)}
data-testid="display-name-input"
/>
);
}}
/>
)}
{editMode && (
<>
<TextInput
ref={form.register()}
type="text"
id="name"
name="name"
defaultValue={providerId}
validated={
form.errors.name
? ValidatedOptions.error
: ValidatedOptions.default
}
/>
</>
)}
</FormGroup>
<FormGroup
label={t("common:enabled")}
fieldId="kc-enabled"
labelIcon={
<HelpItem
helpText={t("realm-settings-help:enabled")}
forLabel={t("enabled")}
forID="kc-enabled"
/>
}
>
<Controller
name="config.enabled"
control={form.control}
defaultValue={["true"]}
render={({ onChange, value }) => (
<Switch
id="kc-enabled"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value[0] === "true"}
data-testid={
value[0] === "true"
? "internationalization-enabled"
: "internationalization-disabled"
}
onChange={(value) => {
onChange([value.toString()]);
}}
/>
)}
/>
</FormGroup>
<FormGroup
label={t("active")}
fieldId="kc-active"
labelIcon={
<HelpItem
helpText="realm-settings-help:active"
forLabel={t("active")}
forID="kc-active"
/>
}
>
<Controller
name="config.active"
control={form.control}
defaultValue={["true"]}
render={({ onChange, value }) => {
return (
<Switch
id="kc-active"
label={t("common:on")}
labelOff={t("common:off")}
isChecked={value[0] === "true"}
data-testid={
value[0] === "true"
? "internationalization-enabled"
: "internationalization-disabled"
}
onChange={(value) => {
onChange([value.toString()]);
}}
/>
);
}}
/>
</FormGroup>
<FormGroup
label={t("AESKeySize")}
fieldId="kc-aes-keysize"
labelIcon={
<HelpItem
helpText="realm-settings-help:AESKeySize"
forLabel={t("AESKeySize")}
forID="kc-aes-key-size"
/>
}
>
<Controller
name="config.secretSize"
control={form.control}
defaultValue={["16"]}
render={({ onChange, value }) => (
<Select
toggleId="kc-aes-keysize"
onToggle={() => setIsKeySizeDropdownOpen(!isKeySizeDropdownOpen)}
onSelect={(_, value) => {
onChange([value.toString()]);
setIsKeySizeDropdownOpen(false);
}}
selections={[value.toString()]}
isOpen={isKeySizeDropdownOpen}
variant={SelectVariant.single}
aria-label={t("aesKeySize")}
data-testid="select-secret-size"
>
{aesSecretSizeOptions?.map((item) => (
<SelectOption
selected={item === value}
key={item}
value={item}
/>
))}
</Select>
)}
/>
</FormGroup>
<ActionGroup className="kc-AESform-buttons">
<Button
className="kc-AESform-save-button"
data-testid="add-provider-button"
variant="primary"
type="submit"
>
{t("common:save")}
</Button>
<Button
className="kc-AESform-cancel-button"
onClick={(!editMode && handleModalToggle) || undefined}
variant="link"
>
{t("common:cancel")}
</Button>
</ActionGroup>
</FormAccess>
);
};
export const AESGeneratedSettings = () => {
const { t } = useTranslation("realm-settings");
const providerId = useRouteMatch<MatchParams>(
"/:realm/realm-settings/keys/:id?/:providerType?/settings"
)?.params.providerType;
return (
<>
<ViewHeader titleKey={t("editProvider")} subKey={providerId} />
<PageSection variant="light">
<AESGeneratedForm providerType={providerId!} editMode />
</PageSection>
</>
);
};

View file

@ -0,0 +1,36 @@
import React from "react";
import { Modal, ModalVariant } from "@patternfly/react-core";
import { useTranslation } from "react-i18next";
import { AESGeneratedForm } from "./AESGeneratedForm";
type AESGeneratedModalProps = {
providerType: string;
handleModalToggle: () => void;
refresh: () => void;
open: boolean;
};
export const AESGeneratedModal = ({
providerType,
handleModalToggle,
open,
refresh,
}: AESGeneratedModalProps) => {
const { t } = useTranslation("realm-settings");
return (
<Modal
className="add-provider-modal"
variant={ModalVariant.medium}
title={t("addProvider")}
isOpen={open}
onClose={handleModalToggle}
>
<AESGeneratedForm
providerType={providerType!}
handleModalToggle={handleModalToggle}
refresh={refresh}
/>
</Modal>
);
};

View file

@ -36,6 +36,7 @@ import {
} from "./identity-providers/add/AddIdentityProvider";
import { AddOpenIdConnect } from "./identity-providers/add/AddOpenIdConnect";
import { DetailSettings } from "./identity-providers/add/DetailSettings";
import { AESGeneratedSettings } from "./realm-settings/key-providers/aes-generated/AESGeneratedForm";
export type RouteDef = BreadcrumbsRoute & {
access: AccessType;
@ -183,6 +184,12 @@ export const routes: RoutesFn = (t: TFunction) => [
breadcrumb: t("realmSettings"),
access: "view-realm",
},
{
path: "/:realm/realm-settings/keys/:id?/aes-generated/settings",
component: AESGeneratedSettings,
breadcrumb: t("realm-settings:editProvider"),
access: "view-realm",
},
{
path: "/:realm/authentication",
component: AuthenticationSection,