From 5c64ab6a4ae013b0cf9b9359952799737ba842e1 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Mon, 28 Feb 2022 16:22:00 +0100 Subject: [PATCH] refacored the keys tab removed duplication (#2146) --- .../manage/realm_settings/KeysTab.ts | 25 + .../realm_settings/RealmSettingsPage.ts | 6 +- .../components/DraggableTable.tsx | 14 +- .../authorization/AuthorizationEvaluate.tsx | 4 +- src/components/table-toolbar/TableToolbar.tsx | 3 +- src/realm-settings/JavaKeystoreModal.tsx | 347 ------------- src/realm-settings/KeysProvidersTab.tsx | 479 ------------------ src/realm-settings/RSAGeneratedModal.tsx | 286 ----------- src/realm-settings/RSAModal.tsx | 319 ------------ src/realm-settings/RealmSettingsSection.tsx | 46 +- src/realm-settings/RealmSettingsTabs.tsx | 44 +- .../aes-generated/AESGeneratedForm.tsx | 336 ------------ .../aes-generated/AESGeneratedModal.tsx | 36 -- .../ecdsa-generated/ECDSAGeneratedForm.tsx | 327 ------------ .../ecdsa-generated/ECDSAGeneratedModal.tsx | 36 -- .../hmac-generated/HMACGeneratedForm.tsx | 374 -------------- .../hmac-generated/HMACGeneratedModal.tsx | 36 -- .../java-keystore/JavaKeystoreForm.tsx | 430 ---------------- .../java-keystore/JavaKeystoreModal.tsx | 36 -- .../rsa-enc-generated/RSAEncGeneratedForm.tsx | 26 - .../RSAEncGeneratedModal.tsx | 37 -- .../rsa-generated/RSAGeneratedForm.tsx | 392 -------------- .../rsa-generated/RSAGeneratedModal.tsx | 36 -- .../key-providers/rsa/RSAForm.tsx | 394 -------------- .../key-providers/rsa/RSAModal.tsx | 36 -- src/realm-settings/{ => keys}/KeysListTab.tsx | 167 ++---- src/realm-settings/keys/KeysProvidersTab.tsx | 283 +++++++++++ src/realm-settings/keys/KeysTab.tsx | 92 ++++ .../keys/key-providers/KeyProviderForm.tsx | 257 ++++++++++ .../keys/key-providers/KeyProviderModal.tsx | 28 + .../keys/key-providers/aes-generated/View.tsx | 64 +++ .../key-providers/ecdsa-generated/View.tsx | 64 +++ .../key-providers/hmac-generated/View.tsx | 109 ++++ .../keys/key-providers/java-keystore/View.tsx | 167 ++++++ .../keys/key-providers/rsa-generated/View.tsx | 123 +++++ .../keys/key-providers/rsa/View.tsx | 127 +++++ src/realm-settings/messages.ts | 13 +- src/realm-settings/routes.ts | 16 +- .../routes/AesGeneratedSettings.ts | 24 - .../routes/EcdsaGeneratedSettings.ts | 24 - .../routes/HmacGeneratedSettings.ts | 24 - .../routes/JavaKeystoreSettings.ts | 24 - src/realm-settings/routes/KeyProvider.ts | 32 ++ .../routes/RsaEncGeneratedSettings.ts | 24 - .../routes/RsaGeneratedSettings.ts | 24 - src/realm-settings/routes/RsaSettings.ts | 22 - 46 files changed, 1462 insertions(+), 4351 deletions(-) create mode 100644 cypress/support/pages/admin_console/manage/realm_settings/KeysTab.ts delete mode 100644 src/realm-settings/JavaKeystoreModal.tsx delete mode 100644 src/realm-settings/KeysProvidersTab.tsx delete mode 100644 src/realm-settings/RSAGeneratedModal.tsx delete mode 100644 src/realm-settings/RSAModal.tsx delete mode 100644 src/realm-settings/key-providers/aes-generated/AESGeneratedForm.tsx delete mode 100644 src/realm-settings/key-providers/aes-generated/AESGeneratedModal.tsx delete mode 100644 src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm.tsx delete mode 100644 src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedModal.tsx delete mode 100644 src/realm-settings/key-providers/hmac-generated/HMACGeneratedForm.tsx delete mode 100644 src/realm-settings/key-providers/hmac-generated/HMACGeneratedModal.tsx delete mode 100644 src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx delete mode 100644 src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx delete mode 100644 src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedForm.tsx delete mode 100644 src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedModal.tsx delete mode 100644 src/realm-settings/key-providers/rsa-generated/RSAGeneratedForm.tsx delete mode 100644 src/realm-settings/key-providers/rsa-generated/RSAGeneratedModal.tsx delete mode 100644 src/realm-settings/key-providers/rsa/RSAForm.tsx delete mode 100644 src/realm-settings/key-providers/rsa/RSAModal.tsx rename src/realm-settings/{ => keys}/KeysListTab.tsx (54%) create mode 100644 src/realm-settings/keys/KeysProvidersTab.tsx create mode 100644 src/realm-settings/keys/KeysTab.tsx create mode 100644 src/realm-settings/keys/key-providers/KeyProviderForm.tsx create mode 100644 src/realm-settings/keys/key-providers/KeyProviderModal.tsx create mode 100644 src/realm-settings/keys/key-providers/aes-generated/View.tsx create mode 100644 src/realm-settings/keys/key-providers/ecdsa-generated/View.tsx create mode 100644 src/realm-settings/keys/key-providers/hmac-generated/View.tsx create mode 100644 src/realm-settings/keys/key-providers/java-keystore/View.tsx create mode 100644 src/realm-settings/keys/key-providers/rsa-generated/View.tsx create mode 100644 src/realm-settings/keys/key-providers/rsa/View.tsx delete mode 100644 src/realm-settings/routes/AesGeneratedSettings.ts delete mode 100644 src/realm-settings/routes/EcdsaGeneratedSettings.ts delete mode 100644 src/realm-settings/routes/HmacGeneratedSettings.ts delete mode 100644 src/realm-settings/routes/JavaKeystoreSettings.ts create mode 100644 src/realm-settings/routes/KeyProvider.ts delete mode 100644 src/realm-settings/routes/RsaEncGeneratedSettings.ts delete mode 100644 src/realm-settings/routes/RsaGeneratedSettings.ts delete mode 100644 src/realm-settings/routes/RsaSettings.ts diff --git a/cypress/support/pages/admin_console/manage/realm_settings/KeysTab.ts b/cypress/support/pages/admin_console/manage/realm_settings/KeysTab.ts new file mode 100644 index 0000000000..672475db66 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/realm_settings/KeysTab.ts @@ -0,0 +1,25 @@ +export default class KeysTab { + private readonly keysTab = "rs-keys-tab"; + private readonly providersTab = "rs-providers-tab"; + private readonly addProviderDropdown = "addProviderDropdown"; + + goToKeysTab() { + cy.findByTestId(this.keysTab).click(); + + return this; + } + + goToProvidersTab() { + this.goToKeysTab(); + cy.findByTestId(this.providersTab).click(); + + return this; + } + + addProvider(provider: string) { + cy.findByTestId(this.addProviderDropdown).click(); + cy.findByTestId(`option-${provider}`).click(); + + return this; + } +} diff --git a/cypress/support/pages/admin_console/manage/realm_settings/RealmSettingsPage.ts b/cypress/support/pages/admin_console/manage/realm_settings/RealmSettingsPage.ts index dcf6655c10..632d263320 100644 --- a/cypress/support/pages/admin_console/manage/realm_settings/RealmSettingsPage.ts +++ b/cypress/support/pages/admin_console/manage/realm_settings/RealmSettingsPage.ts @@ -68,15 +68,15 @@ export default class RealmSettingsPage { enableStartTlsCheck = "enable-start-tls"; addProviderDropdown = "addProviderDropdown"; addProviderButton = "add-provider-button"; - displayName = "display-name-input"; + displayName = "name-input"; enableEvents = "eventsEnabled"; eventsUserSave = "save-user"; enableAdminEvents = "adminEventsEnabled"; eventsAdminSave = "save-admin"; eventTypeColumn = 'tbody > tr > [data-label="Event saved type"]'; filterSelectMenu = ".kc-filter-type-select"; - passiveKeysOption = "passive-keys-option"; - disabledKeysOption = "disabled-keys-option"; + passiveKeysOption = "PASSIVE-option"; + disabledKeysOption = "DISABLED-option"; testConnectionButton = "test-connection-button"; modalTestConnectionButton = "modal-test-connection-button"; emailAddressInput = "email-address-input"; diff --git a/src/authentication/components/DraggableTable.tsx b/src/authentication/components/DraggableTable.tsx index e9d8c1357d..3402977c61 100644 --- a/src/authentication/components/DraggableTable.tsx +++ b/src/authentication/components/DraggableTable.tsx @@ -2,7 +2,10 @@ import React, { ReactNode, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { get } from "lodash-es"; import { + ActionsColumn, + IAction, TableComposable, + TableComposableProps, Tbody, Td, Th, @@ -17,10 +20,11 @@ export type Field = { cellRenderer?: (row: T) => ReactNode; }; -type DraggableTableProps = { +type DraggableTableProps = Omit & { keyField: string; columns: Field[]; data: T[]; + actions?: IAction[]; onDragFinish: (dragged: string, newOrder: string[]) => void; }; @@ -28,7 +32,9 @@ export function DraggableTable({ keyField, columns, data, + actions, onDragFinish, + ...props }: DraggableTableProps) { const { t } = useTranslation("authentication"); const bodyRef = useRef(null); @@ -169,6 +175,7 @@ export function DraggableTable({ @@ -208,6 +215,11 @@ export function DraggableTable({ : get(row, column.name)} ))} + {actions && ( + + + + )} ))} diff --git a/src/clients/authorization/AuthorizationEvaluate.tsx b/src/clients/authorization/AuthorizationEvaluate.tsx index 93734ca2fd..4c61777740 100644 --- a/src/clients/authorization/AuthorizationEvaluate.tsx +++ b/src/clients/authorization/AuthorizationEvaluate.tsx @@ -1,5 +1,5 @@ import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation"; -import React, { useState } from "react"; +import React, { useState, KeyboardEvent } from "react"; import { useTranslation } from "react-i18next"; import { FormGroup, @@ -189,7 +189,7 @@ export const AuthorizationEvaluate = ({ } }; - const handleKeyDown = (e: any) => { + const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Enter") { onSearch(); } diff --git a/src/components/table-toolbar/TableToolbar.tsx b/src/components/table-toolbar/TableToolbar.tsx index daa9289c57..79347f2605 100644 --- a/src/components/table-toolbar/TableToolbar.tsx +++ b/src/components/table-toolbar/TableToolbar.tsx @@ -3,6 +3,7 @@ import React, { FunctionComponent, ReactNode, useState, + KeyboardEvent, } from "react"; import { Toolbar, @@ -55,7 +56,7 @@ export const TableToolbar: FunctionComponent = ({ } }; - const handleKeyDown = (e: any) => { + const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Enter") { onSearch(); } diff --git a/src/realm-settings/JavaKeystoreModal.tsx b/src/realm-settings/JavaKeystoreModal.tsx deleted file mode 100644 index 099e85748b..0000000000 --- a/src/realm-settings/JavaKeystoreModal.tsx +++ /dev/null @@ -1,347 +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/keycloak-admin-client/lib/defs/componentRepresentation"; -import { HelpItem } from "../components/help-enabler/HelpItem"; -import { useServerInfo } from "../context/server-info/ServerInfoProvider"; -import { KEY_PROVIDER_TYPE } from "../util"; - -type JavaKeystoreModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const JavaKeystoreModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: // save, -JavaKeystoreModalProps) => { - const { t } = useTranslation("groups"); - const serverInfo = useServerInfo(); - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - const { handleSubmit, control } = useForm({}); - const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] = - useState(false); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const save = async (component: ComponentRepresentation) => { - try { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh(); - } catch (error) { - addError("groups:saveProviderError", error); - } - }; - - return ( - - {t("common:Add")} - , - , - ]} - > -
- - } - > - ( - { - onChange(value); - }} - data-testid="display-name-input" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - {providerType === "java-keystore" && ( - <> - - } - > - ( - - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - data-testid="select-display-name" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - data-testid="select-display-name" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - data-testid="select-display-name" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - data-testid="select-display-name" - > - )} - /> - - - )} -
-
- ); -}; diff --git a/src/realm-settings/KeysProvidersTab.tsx b/src/realm-settings/KeysProvidersTab.tsx deleted file mode 100644 index a564cdaa6d..0000000000 --- a/src/realm-settings/KeysProvidersTab.tsx +++ /dev/null @@ -1,479 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { - AlertVariant, - Button, - ButtonVariant, - DataList, - DataListAction, - DataListCell, - DataListControl, - DataListDragButton, - DataListItem, - DataListItemCells, - DataListItemRow, - Dropdown, - DropdownItem, - DropdownPosition, - DropdownToggle, - InputGroup, - KebabToggle, - PageSection, - TextInput, - Toolbar, - ToolbarGroup, - ToolbarItem, - Tooltip, -} from "@patternfly/react-core"; -import { SearchIcon } from "@patternfly/react-icons"; - -import type { KeyMetadataRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/keyMetadataRepresentation"; -import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; -import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; - -import "./realm-settings-section.css"; -import { useServerInfo } from "../context/server-info/ServerInfoProvider"; -import { useAdminClient } from "../context/auth/AdminClient"; -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 "./key-providers/aes-generated/AESGeneratedModal"; -import { JavaKeystoreModal } from "./key-providers/java-keystore/JavaKeystoreModal"; -import { HMACGeneratedModal } from "./key-providers/hmac-generated/HMACGeneratedModal"; -import { ECDSAGeneratedModal } from "./key-providers/ecdsa-generated/ECDSAGeneratedModal"; -import { RSAModal } from "./RSAModal"; -import { RSAEncGeneratedModal } from "./key-providers/rsa-enc-generated/RSAEncGeneratedModal"; -import { RSAGeneratedModal } from "./key-providers/rsa-generated/RSAGeneratedModal"; -import { KEY_PROVIDER_TYPE } from "../util"; - -type ComponentData = KeyMetadataRepresentation & { - id?: string; - providerDescription?: string; - name?: string; - toggleHidden?: boolean; - config?: any; - parentId?: string; -}; - -type KeysTabInnerProps = { - components: ComponentData[]; - realmComponents: ComponentRepresentation[]; - keyProviderComponentTypes: ComponentTypeRepresentation[]; - refresh: () => void; -}; - -export const KeysTabInner = ({ components, refresh }: KeysTabInnerProps) => { - const { t } = useTranslation("realm-settings"); - const { addAlert, addError } = useAlerts(); - const adminClient = useAdminClient(); - const { realm } = useRealm(); - const { url } = useRouteMatch(); - - const [id, setId] = useState(""); - - const [searchVal, setSearchVal] = useState(""); - const [filteredComponents, setFilteredComponents] = useState( - [] - ); - const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); - - const serverInfo = useServerInfo(); - const providerTypes = ( - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? [] - ).map((item) => item.id); - - const [itemOrder, setItemOrder] = useState([]); - const [providerDropdownOpen, setProviderDropdownOpen] = useState(false); - - const [defaultConsoleDisplayName, setDefaultConsoleDisplayName] = - useState(""); - - const [selectedComponent, setSelectedComponent] = - useState(); - - const [liveText, setLiveText] = useState(""); - - useEffect(() => { - const itemIds = components.map((component) => component.id!); - setItemOrder(["data", ...itemIds]); - }, [components, searchVal]); - - const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ - titleKey: "realm-settings:deleteProviderTitle", - messageKey: t("deleteProviderConfirm") + selectedComponent?.name + "?", - continueButtonLabel: "common:delete", - continueButtonVariant: ButtonVariant.danger, - onConfirm: async () => { - try { - await adminClient.components.del({ - id: selectedComponent!.id!, - realm: realm, - }); - - refresh(); - - addAlert(t("deleteProviderSuccess"), AlertVariant.success); - } catch (error) { - addError("realm-settings:deleteProviderError", error); - } - }, - }); - - const onDragStart = async (id: string) => { - setLiveText(t("common:onDragStart", { item: id })); - setId(id); - }; - - const onDragMove = () => { - setLiveText(t("common:onDragMove", { item: id })); - }; - - const onDragCancel = () => { - setLiveText(t("common:onDragCancel")); - }; - - const onDragFinish = async (itemOrder: string[]) => { - setItemOrder(itemOrder); - setLiveText(t("common:onDragFinish")); - const updateAll = components.map((component: ComponentData) => { - const componentToSave = { ...component }; - delete componentToSave.providerDescription; - - return adminClient.components.update( - { id: component.id! }, - { - ...componentToSave, - config: { - priority: [ - ( - itemOrder.length - - itemOrder.indexOf(component.id!) + - 100 - ).toString(), - ], - }, - } - ); - }); - - try { - await Promise.all(updateAll); - refresh(); - addAlert( - t("realm-settings:saveProviderListSuccess"), - AlertVariant.success - ); - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const onSearch = () => { - if (searchVal !== "") { - setSearchVal(searchVal); - const x = components.filter((v) => { - return v.name?.includes(searchVal) || v.providerId?.includes(searchVal); - }); - setFilteredComponents(x); - } else { - setSearchVal(""); - setFilteredComponents(components); - } - }; - - const handleKeyDown = (e: any) => { - if (e.key === "Enter") { - onSearch(); - } - }; - - const handleInputChange = (value: string) => { - setSearchVal(value); - }; - - const handleModalToggle = () => { - setIsCreateModalOpen(!isCreateModalOpen); - }; - - const [actionListOpen, setActionListOpen] = useState( - components.map(() => false) - ); - const toggleActionList = (index: number) => { - actionListOpen[index] = !actionListOpen[index]; - setActionListOpen([...actionListOpen]); - }; - - return ( - <> - {defaultConsoleDisplayName === "aes-generated" && ( - - )} - {defaultConsoleDisplayName === "ecdsa-generated" && ( - - )} - {defaultConsoleDisplayName === "hmac-generated" && ( - - )} - {defaultConsoleDisplayName === "java-keystore" && ( - - )} - {defaultConsoleDisplayName === "rsa" && ( - - )} - {defaultConsoleDisplayName === "rsa-generated" && ( - - )} - {defaultConsoleDisplayName === "rsa-enc-generated" && ( - - )} - - - - - - - - - - - - setProviderDropdownOpen(val)} - isPrimary - > - {t("realm-settings:addProvider")} - - } - dropdownItems={[ - providerTypes.map((item) => ( - { - handleModalToggle(); - - setProviderDropdownOpen(false); - setDefaultConsoleDisplayName(item); - }} - data-testid={`option-${item}`} - key={item} - > - {item} - - )), - ]} - /> - - - - - - - - - <>{t("realm-settings:name")} - , - - <>{t("realm-settings:provider")} - , - - <>{t("realm-settings:providerDescription")} - , - ]} - /> - - - {(filteredComponents.length === 0 - ? components - : filteredComponents - ).map((component, idx) => ( - - - - - - - - - - {component.name} - - , - - {component.providerId} - , - - {component.providerDescription} - , - - { - toggleActionList(idx); - }} - /> - } - dropdownItems={[ - { - setSelectedComponent(component); - toggleDeleteDialog(); - toggleActionList(idx); - }} - > - {t("common:delete")} - , - ]} - /> - , - ]} - /> - - - ))} - -
- {liveText} -
-
- - ); -}; - -type KeysProps = { - realmComponents: ComponentRepresentation[]; - keyProviderComponentTypes: ComponentTypeRepresentation[]; - refresh: () => void; -}; - -export const KeysProvidersTab = ({ - keyProviderComponentTypes, - realmComponents, - refresh, - ...props -}: KeysProps) => { - return ( - { - const provider = keyProviderComponentTypes.find( - (componentType: ComponentTypeRepresentation) => - component.providerId === componentType.id - ); - - return { - ...component, - providerDescription: provider?.helpText, - }; - })} - keyProviderComponentTypes={keyProviderComponentTypes} - refresh={refresh} - realmComponents={realmComponents} - {...props} - /> - ); -}; diff --git a/src/realm-settings/RSAGeneratedModal.tsx b/src/realm-settings/RSAGeneratedModal.tsx deleted file mode 100644 index b6dcecb1de..0000000000 --- a/src/realm-settings/RSAGeneratedModal.tsx +++ /dev/null @@ -1,286 +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/keycloak-admin-client/lib/defs/componentRepresentation"; -import { HelpItem } from "../components/help-enabler/HelpItem"; -import { useServerInfo } from "../context/server-info/ServerInfoProvider"; -import { KEY_PROVIDER_TYPE } from "../util"; - -type RSAGeneratedModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const RSAGeneratedModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: RSAGeneratedModalProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - const { handleSubmit, control } = useForm({}); - const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false); - const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const save = async (component: ComponentRepresentation) => { - try { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh(); - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - return ( - - {t("common:Add")} - , - , - ]} - > -
- - } - > - ( - { - onChange(value); - }} - data-testid="display-name-input" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - {providerType === "rsa-generated" && ( - <> - - } - > - ( - - )} - /> - - - } - > - ( - - )} - /> - - - )} -
-
- ); -}; diff --git a/src/realm-settings/RSAModal.tsx b/src/realm-settings/RSAModal.tsx deleted file mode 100644 index a898f16b8c..0000000000 --- a/src/realm-settings/RSAModal.tsx +++ /dev/null @@ -1,319 +0,0 @@ -import React, { useState } from "react"; -import { - AlertVariant, - Button, - ButtonVariant, - FileUpload, - 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/keycloak-admin-client/lib/defs/componentRepresentation"; -import { HelpItem } from "../components/help-enabler/HelpItem"; -import { useServerInfo } from "../context/server-info/ServerInfoProvider"; -import { useParams } from "react-router-dom"; -import { KEY_PROVIDER_TYPE } from "../util"; - -type RSAModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const RSAModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: RSAModalProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - const { handleSubmit, control } = useForm({}); - const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false); - - const { id } = useParams<{ id: string }>(); - - const [keyFileName, setKeyFileName] = useState(""); - const [certificateFileName, setCertificateFileName] = useState(""); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - return ( - - {t("common:Add")} - , - , - ]} - > -
- - } - > - ( - { - onChange(value); - }} - data-testid="display-name-input" - > - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - - } - > - ( - { - onChange([value + ""]); - }} - /> - )} - /> - - {providerType === "rsa" && ( - <> - - } - > - ( - - )} - /> - - - } - > - ( - { - setKeyFileName(fileName); - onChange([value]); - }} - /> - )} - /> - - - } - > - ( - { - setCertificateFileName(fileName); - onChange([value]); - }} - /> - )} - /> - - - )} -
-
- ); -}; diff --git a/src/realm-settings/RealmSettingsSection.tsx b/src/realm-settings/RealmSettingsSection.tsx index c82c285bad..1a3e39c1e2 100644 --- a/src/realm-settings/RealmSettingsSection.tsx +++ b/src/realm-settings/RealmSettingsSection.tsx @@ -1,63 +1,27 @@ import React, { useState } from "react"; -import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner"; import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useRealm } from "../context/realm-context/RealmContext"; -import { KEY_PROVIDER_TYPE } from "../util"; import { RealmSettingsTabs } from "./RealmSettingsTabs"; -const sortByPriority = (components: ComponentRepresentation[]) => { - const sortedComponents = [...components].sort((a, b) => { - const priorityA = Number(a.config?.priority); - const priorityB = Number(b.config?.priority); - - return ( - (!isNaN(priorityB) ? priorityB : 0) - (!isNaN(priorityA) ? priorityA : 0) - ); - }); - - return sortedComponents; -}; - export default function RealmSettingsSection() { const adminClient = useAdminClient(); const { realm: realmName } = useRealm(); const [realm, setRealm] = useState(); - const [realmComponents, setRealmComponents] = - useState(); const [key, setKey] = useState(0); const refresh = () => { setKey(key + 1); }; - useFetch( - async () => { - const realm = await adminClient.realms.findOne({ realm: realmName }); - const realmComponents = await adminClient.components.find({ - type: KEY_PROVIDER_TYPE, - realm: realmName, - }); + useFetch(() => adminClient.realms.findOne({ realm: realmName }), setRealm, [ + key, + ]); - return { realm, realmComponents }; - }, - ({ realm, realmComponents }) => { - setRealmComponents(sortByPriority(realmComponents)); - setRealm(realm); - }, - [key] - ); - - if (!realm || !realmComponents) { + if (!realm) { return ; } - return ( - - ); + return ; } diff --git a/src/realm-settings/RealmSettingsTabs.tsx b/src/realm-settings/RealmSettingsTabs.tsx index 995da51e38..b6a98c4770 100644 --- a/src/realm-settings/RealmSettingsTabs.tsx +++ b/src/realm-settings/RealmSettingsTabs.tsx @@ -13,7 +13,6 @@ import { } from "@patternfly/react-core"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; -import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { @@ -24,20 +23,16 @@ import { useRealm } from "../context/realm-context/RealmContext"; import { useRealms } from "../context/RealmsContext"; import { ViewHeader } from "../components/view-header/ViewHeader"; import { useAdminClient } from "../context/auth/AdminClient"; -import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useAlerts } from "../components/alert/Alerts"; import { convertFormValuesToObject, convertToFormValues, - KEY_PROVIDER_TYPE, toUpperCase, } from "../util"; import { RealmSettingsEmailTab } from "./EmailTab"; import { EventsTab } from "./event-config/EventsTab"; import { RealmSettingsGeneralTab } from "./GeneralTab"; -import { KeysListTab } from "./KeysListTab"; -import { KeysProvidersTab } from "./KeysProvidersTab"; import { RealmSettingsLoginTab } from "./LoginTab"; import { SecurityDefences } from "./security-defences/SecurityDefences"; import { RealmSettingsSessionsTab } from "./SessionsTab"; @@ -57,7 +52,7 @@ import helpUrls from "../help-urls"; import { UserProfileTab } from "./user-profile/UserProfileTab"; import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import { ClientPoliciesTab, toClientPolicies } from "./routes/ClientPolicies"; -import { KeySubTab, toKeysTab } from "./routes/KeysTab"; +import { KeysTab } from "./keys/KeysTab"; type RealmSettingsHeaderProps = { onChange: (value: boolean) => void; @@ -166,12 +161,10 @@ const RealmSettingsHeader = ({ type RealmSettingsTabsProps = { realm: RealmRepresentation; refresh: () => void; - realmComponents: ComponentRepresentation[]; }; export const RealmSettingsTabs = ({ realm, - realmComponents, refresh, }: RealmSettingsTabsProps) => { const { t } = useTranslation("realm-settings"); @@ -182,9 +175,6 @@ export const RealmSettingsTabs = ({ const history = useHistory(); const isFeatureEnabled = useIsFeatureEnabled(); - const kpComponentTypes = - useServerInfo().componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - const form = useForm({ mode: "onChange", shouldUnregister: false }); const { control, getValues, setValue, reset: resetForm } = form; @@ -247,11 +237,6 @@ export const RealmSettingsTabs = ({ history, }); - const keysRoute = (tab: KeySubTab) => - routableTab({ - to: toKeysTab({ realm: realmName, tab }), - history, - }); return ( <> - - {t("keysList")}} - {...keysRoute("list")} - > - - - {t("providers")}} - {...keysRoute("providers")} - > - - - + {t("events")}} diff --git a/src/realm-settings/key-providers/aes-generated/AESGeneratedForm.tsx b/src/realm-settings/key-providers/aes-generated/AESGeneratedForm.tsx deleted file mode 100644 index 4324eee183..0000000000 --- a/src/realm-settings/key-providers/aes-generated/AESGeneratedForm.tsx +++ /dev/null @@ -1,336 +0,0 @@ -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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } 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, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - } - }, - [] - ); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const aesSecretSizeOptions = allComponentTypes[0].properties[3].options; - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - { - return ( - onChange(value)} - data-testid="display-name-input" - /> - ); - }} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - - - - - ); -}; - -export default function AESGeneratedSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/aes-generated/AESGeneratedModal.tsx b/src/realm-settings/key-providers/aes-generated/AESGeneratedModal.tsx deleted file mode 100644 index 9e02588e93..0000000000 --- a/src/realm-settings/key-providers/aes-generated/AESGeneratedModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -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 ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm.tsx b/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm.tsx deleted file mode 100644 index 9d623eec1a..0000000000 --- a/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm.tsx +++ /dev/null @@ -1,327 +0,0 @@ -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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } from "../../../util"; -import { useAlerts } from "../../../components/alert/Alerts"; - -type ECDSAGeneratedFormProps = { - handleModalToggle?: () => void; - refresh?: () => void; - editMode?: boolean; - providerType?: string; -}; - -export interface MatchParams { - providerType: string; -} - -export const ECDSAGeneratedForm = ({ - editMode, - providerType, - handleModalToggle, - refresh, -}: ECDSAGeneratedFormProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false); - - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - } - }, - [] - ); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const ecdsaEllipticCurveOptions = allComponentTypes[1].properties[3].options; - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - { - return ( - onChange(value)} - data-testid="display-name-input" - /> - ); - }} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - - - - - ); -}; - -export default function ECDSAGeneratedSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedModal.tsx b/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedModal.tsx deleted file mode 100644 index f60a418359..0000000000 --- a/src/realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { ECDSAGeneratedForm } from "./ECDSAGeneratedForm"; - -type ECDSAGeneratedModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const ECDSAGeneratedModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: ECDSAGeneratedModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/hmac-generated/HMACGeneratedForm.tsx b/src/realm-settings/key-providers/hmac-generated/HMACGeneratedForm.tsx deleted file mode 100644 index 231ba38998..0000000000 --- a/src/realm-settings/key-providers/hmac-generated/HMACGeneratedForm.tsx +++ /dev/null @@ -1,374 +0,0 @@ -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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } from "../../../util"; -import { useAlerts } from "../../../components/alert/Alerts"; - -type HMACGeneratedFormProps = { - handleModalToggle?: () => void; - refresh?: () => void; - editMode?: boolean; - providerType?: string; -}; - -export interface MatchParams { - providerType: string; -} - -export const HMACGeneratedForm = ({ - editMode, - providerType, - handleModalToggle, - refresh, -}: HMACGeneratedFormProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false); - const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] = - useState(false); - - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - } - }, - [] - ); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const hmacSecretSizeOptions = allComponentTypes[2].properties[3].options; - - const hmacAlgorithmOptions = allComponentTypes[2].properties[4].options; - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - { - return ( - onChange(value)} - data-testid="display-name-input" - /> - ); - }} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - } - > - ( - - )} - /> - - - - - - - ); -}; - -export default function HMACGeneratedSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/hmac-generated/HMACGeneratedModal.tsx b/src/realm-settings/key-providers/hmac-generated/HMACGeneratedModal.tsx deleted file mode 100644 index 1257b0928b..0000000000 --- a/src/realm-settings/key-providers/hmac-generated/HMACGeneratedModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { HMACGeneratedForm } from "./HMACGeneratedForm"; - -type HMACGeneratedModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const HMACGeneratedModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: HMACGeneratedModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx b/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx deleted file mode 100644 index 302d8fe9c8..0000000000 --- a/src/realm-settings/key-providers/java-keystore/JavaKeystoreForm.tsx +++ /dev/null @@ -1,430 +0,0 @@ -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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } from "../../../util"; -import { useAlerts } from "../../../components/alert/Alerts"; - -type JavaKeystoreFormProps = { - handleModalToggle?: () => void; - refresh?: () => void; - editMode?: boolean; - providerType?: string; -}; - -export interface MatchParams { - providerType: string; -} - -export const JavaKeystoreForm = ({ - editMode, - providerType, - handleModalToggle, - refresh, -}: JavaKeystoreFormProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - const [isAlgorithmDropdownOpen, setIsAlgorithmDropdownOpen] = useState(false); - - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - } - }, - [] - ); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const javaKeystoreAlgorithmOptions = - allComponentTypes[3].properties[3].options; - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - { - return ( - onChange(value)} - data-testid="display-name-input" - /> - ); - }} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - } - > - ( - { - onChange([value.toString()]); - }} - data-testid="select-display-name" - > - )} - /> - - - } - > - ( - { - onChange([value.toString()]); - }} - data-testid="select-display-name" - > - )} - /> - - - } - > - ( - { - onChange([value.toString()]); - }} - data-testid="key-alias" - > - )} - /> - - - } - > - ( - { - onChange([value.toString()]); - }} - data-testid="key-password" - > - )} - /> - - - - - - - ); -}; - -export default function JavaKeystoreSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx b/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx deleted file mode 100644 index 8514e0151f..0000000000 --- a/src/realm-settings/key-providers/java-keystore/JavaKeystoreModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { JavaKeystoreForm } from "./JavaKeystoreForm"; - -type JavaKeystoreModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const JavaKeystoreModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: JavaKeystoreModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedForm.tsx b/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedForm.tsx deleted file mode 100644 index 9c7ecdda5c..0000000000 --- a/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedForm.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import { PageSection } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { useRouteMatch } from "react-router-dom"; - -import { ViewHeader } from "../../../components/view-header/ViewHeader"; -import { - MatchParams, - RSAGeneratedForm, -} from "../rsa-generated/RSAGeneratedForm"; - -export default function RSAEncGeneratedSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedModal.tsx b/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedModal.tsx deleted file mode 100644 index a46e8351b9..0000000000 --- a/src/realm-settings/key-providers/rsa-enc-generated/RSAEncGeneratedModal.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { RSAGeneratedForm } from "../rsa-generated/RSAGeneratedForm"; - -type RSAEncGeneratedModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const RSAEncGeneratedModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: RSAEncGeneratedModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/rsa-generated/RSAGeneratedForm.tsx b/src/realm-settings/key-providers/rsa-generated/RSAGeneratedForm.tsx deleted file mode 100644 index cb382abe1e..0000000000 --- a/src/realm-settings/key-providers/rsa-generated/RSAGeneratedForm.tsx +++ /dev/null @@ -1,392 +0,0 @@ -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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } from "../../../util"; -import { useAlerts } from "../../../components/alert/Alerts"; - -type RSAGeneratedFormProps = { - handleModalToggle?: () => void; - refresh?: () => void; - editMode?: boolean; - providerType?: string; - isRSAEncGenerated?: boolean; -}; - -export interface MatchParams { - providerType: string; -} - -export const RSAGeneratedForm = ({ - editMode, - providerType, - handleModalToggle, - refresh, - isRSAEncGenerated, -}: RSAGeneratedFormProps) => { - const { t } = useTranslation("realm-settings"); - const [isKeySizeDropdownOpen, setIsKeySizeDropdownOpen] = useState(false); - const [isEllipticCurveDropdownOpen, setIsEllipticCurveDropdownOpen] = - useState(false); - - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - const { url } = useRouteMatch(); - - const serverInfo = useServerInfo(); - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const isTypeRSAEncGenerated = - url.includes("rsa-enc-generated") || isRSAEncGenerated; - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const rsaGeneratedKeySizeOptions = - allComponentTypes[6].properties[3].options ?? []; - - const rsaGeneratedAlgorithmOptions = - allComponentTypes[6].properties[4].options ?? []; - - const rsaEncGeneratedKeySizeOptions = - allComponentTypes[5].properties[3].options ?? []; - - const rsaEncGeneratedAlgorithmOptions = - allComponentTypes[5].properties[4].options ?? []; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - } - }, - [] - ); - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - ( - onChange(value)} - data-testid="display-name-input" - /> - )} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - } - > - ( - - )} - /> - - - - - - - ); -}; - -export default function RSAGeneratedSettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/rsa-generated/RSAGeneratedModal.tsx b/src/realm-settings/key-providers/rsa-generated/RSAGeneratedModal.tsx deleted file mode 100644 index ce9a4423ab..0000000000 --- a/src/realm-settings/key-providers/rsa-generated/RSAGeneratedModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { RSAGeneratedForm } from "./RSAGeneratedForm"; - -type RSAGeneratedModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const RSAGeneratedModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: RSAGeneratedModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/key-providers/rsa/RSAForm.tsx b/src/realm-settings/key-providers/rsa/RSAForm.tsx deleted file mode 100644 index 2886520406..0000000000 --- a/src/realm-settings/key-providers/rsa/RSAForm.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import React, { useState } from "react"; -import { - ActionGroup, - AlertVariant, - Button, - FileUpload, - 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/keycloak-admin-client/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, KEY_PROVIDER_TYPE } from "../../../util"; -import { useAlerts } from "../../../components/alert/Alerts"; - -type RSAFormProps = { - handleModalToggle?: () => void; - refresh?: () => void; - editMode?: boolean; - providerType?: string; -}; - -export interface MatchParams { - providerType: string; -} - -export const RSAForm = ({ - editMode, - providerType, - handleModalToggle, - refresh, -}: RSAFormProps) => { - const { t } = useTranslation("realm-settings"); - const serverInfo = useServerInfo(); - - const [component, setComponent] = useState(); - - const [isRSAalgDropdownOpen, setIsRSAalgDropdownOpen] = useState(false); - - const [keyFileName, setKeyFileName] = useState(""); - const [certificateFileName, setCertificateFileName] = useState(""); - - const adminClient = useAdminClient(); - const { addAlert, addError } = useAlerts(); - - const { id } = useParams<{ id: string }>(); - - const providerId = - useRouteMatch("/:providerType?")?.params.providerType; - - const save = async (component: ComponentRepresentation) => { - try { - if (id) { - await adminClient.components.update( - { id }, - { - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - } - ); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - } else { - await adminClient.components.create({ - ...component, - parentId: component.parentId, - providerId: providerType, - providerType: KEY_PROVIDER_TYPE, - config: { priority: ["0"] }, - }); - handleModalToggle?.(); - addAlert(t("saveProviderSuccess"), AlertVariant.success); - refresh?.(); - } - } catch (error) { - addError("realm-settings:saveProviderError", error); - } - }; - - const form = useForm({ mode: "onChange" }); - - const setupForm = (component: ComponentRepresentation) => { - form.reset(); - convertToFormValues(component, form.setValue); - }; - - useFetch( - async () => { - if (editMode) return await adminClient.components.findOne({ id: id }); - }, - (result) => { - if (result) { - setupForm(result); - setComponent(result); - } - }, - [] - ); - - const allComponentTypes = - serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; - - const rsaAlgOptions = allComponentTypes[4].properties[3].options; - - return ( - - {editMode && ( - - } - fieldId="id" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - - - )} - - } - fieldId="name" - isRequired - validated={ - form.errors.name ? ValidatedOptions.error : ValidatedOptions.default - } - helperTextInvalid={t("common:required")} - > - {!editMode && ( - { - return ( - onChange(value)} - data-testid="display-name-input" - /> - ); - }} - /> - )} - {editMode && ( - - )} - - - } - > - ( - { - onChange([value.toString()]); - }} - /> - )} - /> - - - } - > - { - return ( - { - onChange([value.toString()]); - }} - /> - ); - }} - /> - - - } - > - ( - - )} - /> - - - } - > - ( - { - setKeyFileName(fileName); - onChange([value]); - }} - /> - )} - /> - - - } - > - ( - { - setCertificateFileName(fileName); - onChange([value]); - }} - /> - )} - /> - - - - - - - ); -}; - -export default function RSASettings() { - const { t } = useTranslation("realm-settings"); - const providerId = useRouteMatch( - "/:realm/realm-settings/keys/:id?/:providerType?/settings" - )?.params.providerType; - return ( - <> - - - - - - ); -} diff --git a/src/realm-settings/key-providers/rsa/RSAModal.tsx b/src/realm-settings/key-providers/rsa/RSAModal.tsx deleted file mode 100644 index 89b6cda8ff..0000000000 --- a/src/realm-settings/key-providers/rsa/RSAModal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { Modal, ModalVariant } from "@patternfly/react-core"; -import { useTranslation } from "react-i18next"; -import { RSAForm } from "./RSAForm"; - -type RSAModalProps = { - providerType: string; - handleModalToggle: () => void; - refresh: () => void; - open: boolean; -}; - -export const RSAModal = ({ - providerType, - handleModalToggle, - open, - refresh, -}: RSAModalProps) => { - const { t } = useTranslation("realm-settings"); - - return ( - - - - ); -}; diff --git a/src/realm-settings/KeysListTab.tsx b/src/realm-settings/keys/KeysListTab.tsx similarity index 54% rename from src/realm-settings/KeysListTab.tsx rename to src/realm-settings/keys/KeysListTab.tsx index ab8b1b3640..f8a5765ce0 100644 --- a/src/realm-settings/KeysListTab.tsx +++ b/src/realm-settings/keys/KeysListTab.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { useHistory, useRouteMatch } from "react-router-dom"; +import { useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Button, @@ -10,18 +10,21 @@ import { SelectVariant, } from "@patternfly/react-core"; import { cellWidth } from "@patternfly/react-table"; +import { FilterIcon } from "@patternfly/react-icons"; import type { KeyMetadataRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/keyMetadataRepresentation"; import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; -import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; -import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; -import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; -import { emptyFormatter } from "../util"; -import { useAdminClient } from "../context/auth/AdminClient"; -import { useRealm } from "../context/realm-context/RealmContext"; +import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState"; +import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable"; +import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; +import { emptyFormatter } from "../../util"; +import { useAdminClient } from "../../context/auth/AdminClient"; +import { useRealm } from "../../context/realm-context/RealmContext"; +import { toKeysTab } from "../routes/KeysTab"; -import "./realm-settings-section.css"; -import { FilterIcon } from "@patternfly/react-icons"; +import "../realm-settings-section.css"; + +const FILTER_OPTIONS = ["ACTIVE", "PASSIVE", "DISABLED"] as const; type KeyData = KeyMetadataRepresentation & { provider?: string; @@ -32,18 +35,19 @@ type KeysListTabProps = { }; export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { - const { t } = useTranslation("roles"); + const { t } = useTranslation("realm-settings"); const history = useHistory(); - const { url } = useRouteMatch(); const [key, setKey] = useState(0); const [publicKey, setPublicKey] = useState(""); const [certificate, setCertificate] = useState(""); const [filterDropdownOpen, setFilterDropdownOpen] = useState(false); - const [filterType, setFilterType] = useState("Active keys"); + const [filterType, setFilterType] = useState( + FILTER_OPTIONS[0] + ); const refresh = () => { - setKey(new Date().getTime()); + setKey(key + 1); }; const adminClient = useAdminClient(); @@ -55,8 +59,12 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { }); const keys = keysMetaData.keys; + const filtered = + filterType !== FILTER_OPTIONS[0] + ? keys?.filter(({ status }) => status === filterType) + : keys; - return keys?.map((key) => { + return filtered?.map((key) => { const provider = realmComponents.find( (component: ComponentRepresentation) => component.id === key.providerId ); @@ -64,56 +72,8 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { })!; }; - const activeKeysLoader = async () => { - const keysMetaData = await adminClient.realms.getKeys({ - realm: realmName, - }); - const keys = keysMetaData.keys; - - const activeKeysCopy = keys!.filter((i) => i.status === "ACTIVE"); - - return activeKeysCopy.map((key) => { - const provider = realmComponents.find( - (component: ComponentRepresentation) => component.id === key.providerId - ); - return { ...key, provider: provider?.name } as KeyData; - })!; - }; - - const passiveKeysLoader = async () => { - const keysMetaData = await adminClient.realms.getKeys({ - realm: realmName, - }); - const keys = keysMetaData.keys; - - const passiveKeys = keys!.filter((i) => i.status === "PASSIVE"); - - return passiveKeys.map((key) => { - const provider = realmComponents.find( - (component: ComponentRepresentation) => component.id === key.providerId - ); - return { ...key, provider: provider?.name } as KeyData; - })!; - }; - - const disabledKeysLoader = async () => { - const keysMetaData = await adminClient.realms.getKeys({ - realm: realmName, - }); - const keys = keysMetaData.keys; - - const disabledKeys = keys!.filter((i) => i.status === "DISABLED"); - - return disabledKeys.map((key) => { - const provider = realmComponents!.find( - (component: ComponentRepresentation) => component.id === key.providerId - ); - return { ...key, provider: provider?.name } as KeyData; - })!; - }; - const [togglePublicKeyDialog, PublicKeyDialog] = useConfirmDialog({ - titleKey: t("realm-settings:publicKeys").slice(0, -1), + titleKey: t("publicKeys").slice(0, -1), messageKey: publicKey, continueButtonLabel: "common:close", continueButtonVariant: ButtonVariant.primary, @@ -121,15 +81,13 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { }); const [toggleCertificateDialog, CertificateDialog] = useConfirmDialog({ - titleKey: t("realm-settings:certificate"), + titleKey: t("certificate"), messageKey: certificate, continueButtonLabel: "common:close", continueButtonVariant: ButtonVariant.primary, onConfirm: () => Promise.resolve(), }); - const goToCreate = () => history.push(`${url}/add-role`); - const ProviderRenderer = ({ provider }: KeyData) => provider; const ButtonRenderer = ({ type, publicKey, certificate }: KeyData) => { @@ -143,7 +101,7 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { variant="secondary" id="kc-public-key" > - {t("realm-settings:publicKeys").slice(0, -1)} + {t("publicKeys").slice(0, -1)} ); } else if (type === "RSA") { @@ -157,7 +115,7 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { variant="secondary" id="kc-rsa-public-key" > - {t("realm-settings:publicKeys").slice(0, -1)} + {t("publicKeys").slice(0, -1)} ); } }; - const options = [ - , - , - , - ]; - return ( @@ -200,16 +139,8 @@ export const KeysListTab = ({ realmComponents }: KeysListTabProps) => { { onToggle={() => setFilterDropdownOpen(!filterDropdownOpen)} toggleIcon={} onSelect={(_, value) => { - setFilterType(value as string); + setFilterType( + FILTER_OPTIONS.find((o) => o === value.toString()) || + FILTER_OPTIONS[0] + ); refresh(); setFilterDropdownOpen(false); }} selections={filterType} > - {options} + {FILTER_OPTIONS.map((option) => ( + + {t(`keysFilter.${option}`)} + + ))} } canSelectAll columns={[ { name: "algorithm", - displayKey: "realm-settings:algorithm", + displayKey: "algorithm", cellFormatters: [emptyFormatter()], transforms: [cellWidth(15)], }, { name: "type", - displayKey: "realm-settings:type", + displayKey: "type", cellFormatters: [emptyFormatter()], transforms: [cellWidth(10)], }, { name: "kid", - displayKey: "realm-settings:kid", + displayKey: "kid", cellFormatters: [emptyFormatter()], transforms: [cellWidth(10)], }, { name: "provider", - displayKey: "realm-settings:provider", + displayKey: "provider", cellRenderer: ProviderRenderer, cellFormatters: [emptyFormatter()], transforms: [cellWidth(10)], }, { name: "publicKeys", - displayKey: "realm-settings:publicKeys", + displayKey: "publicKeys", cellRenderer: ButtonRenderer, cellFormatters: [], transforms: [cellWidth(20)], }, ]} - isSearching={!!filterType} + isSearching={filterType !== FILTER_OPTIONS[0]} emptyState={ + history.push(toKeysTab({ realm: realmName, tab: "providers" })) } - primaryActionText={t("createRole")} - onPrimaryAction={goToCreate} /> } /> diff --git a/src/realm-settings/keys/KeysProvidersTab.tsx b/src/realm-settings/keys/KeysProvidersTab.tsx new file mode 100644 index 0000000000..cb21e4f863 --- /dev/null +++ b/src/realm-settings/keys/KeysProvidersTab.tsx @@ -0,0 +1,283 @@ +import React, { useMemo, useState, KeyboardEvent } from "react"; +import { useTranslation } from "react-i18next"; +import { + AlertVariant, + Button, + ButtonVariant, + Dropdown, + DropdownItem, + DropdownToggle, + InputGroup, + PageSection, + TextInput, + Toolbar, + ToolbarGroup, + ToolbarItem, +} from "@patternfly/react-core"; +import { SearchIcon } from "@patternfly/react-icons"; + +import type { KeyMetadataRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/keyMetadataRepresentation"; +import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; +import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; + +import type { ProviderType } from "../routes/KeyProvider"; +import { useServerInfo } from "../../context/server-info/ServerInfoProvider"; +import { useAdminClient } from "../../context/auth/AdminClient"; +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 { KEY_PROVIDER_TYPE } from "../../util"; +import { DraggableTable } from "../../authentication/components/DraggableTable"; +import { KeyProviderModal } from "./key-providers/KeyProviderModal"; +import useToggle from "../../utils/useToggle"; + +import "../realm-settings-section.css"; + +type ComponentData = KeyMetadataRepresentation & { + id?: string; + providerDescription?: string; + name?: string; + toggleHidden?: boolean; + config?: any; + parentId?: string; +}; + +type KeysProvidersTabProps = { + realmComponents: ComponentRepresentation[]; + refresh: () => void; +}; + +export const KeysProvidersTab = ({ + realmComponents, + refresh, +}: KeysProvidersTabProps) => { + const { t } = useTranslation("realm-settings"); + const { addAlert, addError } = useAlerts(); + const adminClient = useAdminClient(); + const { realm } = useRealm(); + const { url } = useRouteMatch(); + + const [searchVal, setSearchVal] = useState(""); + const [filteredComponents, setFilteredComponents] = useState( + [] + ); + + const [isCreateModalOpen, handleModalToggle] = useToggle(); + const serverInfo = useServerInfo(); + const keyProviderComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + const providerTypes = keyProviderComponentTypes.map((item) => item.id); + + const [providerDropdownOpen, setProviderDropdownOpen] = useState(false); + const [defaultConsoleDisplayName, setDefaultConsoleDisplayName] = + useState(); + + const [selectedComponent, setSelectedComponent] = + useState(); + + const components = useMemo( + () => + realmComponents.map((component) => { + const provider = keyProviderComponentTypes.find( + (componentType: ComponentTypeRepresentation) => + component.providerId === componentType.id + ); + + return { + ...component, + providerDescription: provider?.helpText, + }; + }), + [realmComponents] + ); + + const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ + titleKey: "realm-settings:deleteProviderTitle", + messageKey: t("deleteProviderConfirm", { + provider: selectedComponent?.name, + }), + continueButtonLabel: "common:delete", + continueButtonVariant: ButtonVariant.danger, + onConfirm: async () => { + try { + await adminClient.components.del({ + id: selectedComponent!.id!, + realm: realm, + }); + + refresh(); + + addAlert(t("deleteProviderSuccess"), AlertVariant.success); + } catch (error) { + addError("realm-settings:deleteProviderError", error); + } + }, + }); + + const onSearch = () => { + if (searchVal !== "") { + setSearchVal(searchVal); + const filteredComponents = components.filter( + (component) => + component.name?.includes(searchVal) || + component.providerId?.includes(searchVal) + ); + setFilteredComponents(filteredComponents); + } else { + setSearchVal(""); + setFilteredComponents(components); + } + }; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Enter") { + onSearch(); + } + }; + + const handleInputChange = (value: string) => { + setSearchVal(value); + }; + + return ( + <> + {isCreateModalOpen && defaultConsoleDisplayName && ( + { + handleModalToggle(); + refresh(); + }} + /> + )} + + + + + + + + + + + + setProviderDropdownOpen(val)} + isPrimary + > + {t("addProvider")} + + } + dropdownItems={[ + providerTypes.map((item) => ( + { + handleModalToggle(); + + setProviderDropdownOpen(false); + setDefaultConsoleDisplayName(item as ProviderType); + }} + data-testid={`option-${item}`} + key={item} + > + {item} + + )), + ]} + /> + + + + { + const updateAll = components.map((component: ComponentData) => { + const componentToSave = { ...component }; + delete componentToSave.providerDescription; + + return adminClient.components.update( + { id: component.id! }, + { + ...componentToSave, + config: { + priority: [ + ( + itemOrder.length - + itemOrder.indexOf(component.id!) + + 100 + ).toString(), + ], + }, + } + ); + }); + + try { + await Promise.all(updateAll); + refresh(); + addAlert(t("saveProviderListSuccess"), AlertVariant.success); + } catch (error) { + addError("realm-settings:saveProviderError", error); + } + }} + columns={[ + { + name: "name", + displayKey: "realm-settings:name", + cellRenderer: (component) => ( + + {component.name} + + ), + }, + { + name: "providerId", + displayKey: "realm-settings:provider", + }, + { + name: "providerDescription", + displayKey: "realm-settings:providerDescription", + }, + ]} + actions={[ + { + title: t("common:delete"), + onClick: (_key, _idx, component) => { + setSelectedComponent(component as ComponentRepresentation); + toggleDeleteDialog(); + }, + }, + ]} + /> + + + ); +}; diff --git a/src/realm-settings/keys/KeysTab.tsx b/src/realm-settings/keys/KeysTab.tsx new file mode 100644 index 0000000000..c2824437b4 --- /dev/null +++ b/src/realm-settings/keys/KeysTab.tsx @@ -0,0 +1,92 @@ +import React, { useState } from "react"; +import { useHistory } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { Tab, TabTitleText } from "@patternfly/react-core"; + +import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; +import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; +import { useRealm } from "../../context/realm-context/RealmContext"; +import { KEY_PROVIDER_TYPE } from "../../util"; +import { + routableTab, + RoutableTabs, +} from "../../components/routable-tabs/RoutableTabs"; +import { KeySubTab, toKeysTab } from "../routes/KeysTab"; +import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; +import { KeysListTab } from "./KeysListTab"; +import { KeysProvidersTab } from "./KeysProvidersTab"; + +const sortByPriority = (components: ComponentRepresentation[]) => { + const sortedComponents = [...components].sort((a, b) => { + const priorityA = Number(a.config?.priority); + const priorityB = Number(b.config?.priority); + + return ( + (!isNaN(priorityB) ? priorityB : 0) - (!isNaN(priorityA) ? priorityA : 0) + ); + }); + + return sortedComponents; +}; + +export const KeysTab = () => { + const { t } = useTranslation("realm-settings"); + const history = useHistory(); + + const adminClient = useAdminClient(); + const { realm: realmName } = useRealm(); + + const [realmComponents, setRealmComponents] = + useState(); + const [key, setKey] = useState(0); + const refresh = () => { + setKey(key + 1); + }; + + useFetch( + () => + adminClient.components.find({ + type: KEY_PROVIDER_TYPE, + realm: realmName, + }), + (components) => setRealmComponents(sortByPriority(components)), + [key] + ); + + if (!realmComponents) { + return ; + } + + const keysRoute = (tab: KeySubTab) => + routableTab({ + to: toKeysTab({ realm: realmName, tab }), + history, + }); + + return ( + + {t("keysList")}} + {...keysRoute("list")} + > + + + {t("providers")}} + {...keysRoute("providers")} + > + + + + ); +}; diff --git a/src/realm-settings/keys/key-providers/KeyProviderForm.tsx b/src/realm-settings/keys/key-providers/KeyProviderForm.tsx new file mode 100644 index 0000000000..1921a49ce6 --- /dev/null +++ b/src/realm-settings/keys/key-providers/KeyProviderForm.tsx @@ -0,0 +1,257 @@ +import React from "react"; +import { useParams } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { Controller, FormProvider, useForm } from "react-hook-form"; +import { + AlertVariant, + FormGroup, + ValidatedOptions, + Switch, + TextInput, + PageSection, + ActionGroup, + Button, +} from "@patternfly/react-core"; + +import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation"; +import type { KeyProviderParams, ProviderType } from "../../routes/KeyProvider"; +import { useAlerts } from "../../../components/alert/Alerts"; +import { useAdminClient, useFetch } from "../../../context/auth/AdminClient"; +import { FormAccess } from "../../../components/form-access/FormAccess"; +import { HelpItem } from "../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../util"; +import { ViewHeader } from "../../../components/view-header/ViewHeader"; +import AesView from "./aes-generated/View"; +import EcdsaView from "./ecdsa-generated/View"; +import HmacView from "./hmac-generated/View"; +import JavaKeystoreView from "./java-keystore/View"; +import RsaView from "./rsa/View"; +import RsaGeneratedView from "./rsa-generated/View"; + +type KeyProviderFormProps = { + id?: string; + providerType: ProviderType; + onClose?: () => void; +}; + +const SubView = ({ providerType }: { providerType: ProviderType }) => { + switch (providerType) { + case "aes-generated": + return ; + case "ecdsa-generated": + return ; + case "hmac-generated": + return ; + case "java-keystore": + return ; + case "rsa": + return ; + case "rsa-enc-generated": + return ; + case "rsa-generated": + return ; + + default: + return <>invalid view type; + } +}; + +export const KeyProviderForm = ({ + providerType, + onClose, +}: KeyProviderFormProps) => { + const { t } = useTranslation("realm-settings"); + const { id } = useParams<{ id: string }>(); + const adminClient = useAdminClient(); + const { addAlert, addError } = useAlerts(); + + const form = useForm({ + shouldUnregister: false, + mode: "onChange", + }); + const { register, control, handleSubmit, errors, reset } = form; + + const save = async (component: ComponentRepresentation) => { + try { + if (id) { + await adminClient.components.update( + { id }, + { + ...component, + providerType: KEY_PROVIDER_TYPE, + } + ); + addAlert(t("saveProviderSuccess"), AlertVariant.success); + } else { + await adminClient.components.create({ + ...component, + providerId: providerType, + providerType: KEY_PROVIDER_TYPE, + config: { ...component.config, priority: ["0"] }, + }); + addAlert(t("saveProviderSuccess"), AlertVariant.success); + onClose?.(); + } + } catch (error) { + addError("realm-settings:saveProviderError", error); + } + }; + + useFetch( + async () => { + if (id) return await adminClient.components.findOne({ id }); + }, + (result) => { + if (result) { + reset({ ...result }); + } + }, + [] + ); + + return ( + + {id && ( + + } + fieldId="providerId" + isRequired + > + + + )} + + } + fieldId="name" + isRequired + validated={ + errors.name ? ValidatedOptions.error : ValidatedOptions.default + } + helperTextInvalid={t("common:required")} + > + ( + + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + /> + )} + /> + + + } + > + { + return ( + { + onChange([value.toString()]); + }} + /> + ); + }} + /> + + + + + + + + + + ); +}; + +export default function KeyProviderFormPage() { + const { t } = useTranslation("realm-settings"); + const params = useParams(); + return ( + <> + + + + + + ); +} diff --git a/src/realm-settings/keys/key-providers/KeyProviderModal.tsx b/src/realm-settings/keys/key-providers/KeyProviderModal.tsx new file mode 100644 index 0000000000..e86a14fb43 --- /dev/null +++ b/src/realm-settings/keys/key-providers/KeyProviderModal.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { Modal, ModalVariant } from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; +import { KeyProviderForm } from "./KeyProviderForm"; +import type { ProviderType } from "../../routes/KeyProvider"; + +type KeyProviderModalProps = { + providerType: ProviderType; + onClose: () => void; +}; + +export const KeyProviderModal = ({ + providerType, + onClose, +}: KeyProviderModalProps) => { + const { t } = useTranslation("realm-settings"); + return ( + + + + ); +}; diff --git a/src/realm-settings/keys/key-providers/aes-generated/View.tsx b/src/realm-settings/keys/key-providers/aes-generated/View.tsx new file mode 100644 index 0000000000..eac81a1b03 --- /dev/null +++ b/src/realm-settings/keys/key-providers/aes-generated/View.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FormGroup, + Select, + SelectOption, + SelectVariant, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View() { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + + const [isKeySizeDropdownOpen, toggleDropdown] = useToggle(); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + const aesSecretSizeOptions = allComponentTypes[0].properties[3].options ?? []; + + return ( + + } + > + ( + + )} + /> + + ); +} diff --git a/src/realm-settings/keys/key-providers/ecdsa-generated/View.tsx b/src/realm-settings/keys/key-providers/ecdsa-generated/View.tsx new file mode 100644 index 0000000000..296bf5a8c3 --- /dev/null +++ b/src/realm-settings/keys/key-providers/ecdsa-generated/View.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FormGroup, + Select, + SelectOption, + SelectVariant, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View() { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + const [isKeySizeDropdownOpen, toggleDropdown] = useToggle(); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + + const ecdsaEllipticCurveOptions = allComponentTypes[1].properties[3].options!; + + return ( + + } + > + ( + + )} + /> + + ); +} diff --git a/src/realm-settings/keys/key-providers/hmac-generated/View.tsx b/src/realm-settings/keys/key-providers/hmac-generated/View.tsx new file mode 100644 index 0000000000..c1278006df --- /dev/null +++ b/src/realm-settings/keys/key-providers/hmac-generated/View.tsx @@ -0,0 +1,109 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FormGroup, + Select, + SelectOption, + SelectVariant, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View() { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + + const [isKeySizeDropdownOpen, toggleKeySizeDropdown] = useToggle(); + const [isEllipticCurveDropdownOpen, toggleEllipticDropdown] = useToggle(); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + + const hmacSecretSizeOptions = + allComponentTypes[2].properties[3].options ?? []; + + const hmacAlgorithmOptions = allComponentTypes[2].properties[4].options ?? []; + + return ( + <> + + } + > + ( + + )} + /> + + + } + > + ( + + )} + /> + + + ); +} diff --git a/src/realm-settings/keys/key-providers/java-keystore/View.tsx b/src/realm-settings/keys/key-providers/java-keystore/View.tsx new file mode 100644 index 0000000000..d1a940e2d4 --- /dev/null +++ b/src/realm-settings/keys/key-providers/java-keystore/View.tsx @@ -0,0 +1,167 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FormGroup, + Select, + SelectOption, + SelectVariant, + TextInput, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View() { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + const [isAlgorithmDropdownOpen, toggleDropdown] = useToggle(); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + + const javaKeystoreAlgorithmOptions = + allComponentTypes[3].properties[3].options ?? []; + + return ( + <> + + } + > + ( + + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="keystore" + /> + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="keystorePassword" + /> + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="key-alias" + /> + )} + /> + + + } + > + ( + { + onChange([value.toString()]); + }} + data-testid="key-password" + /> + )} + /> + + + ); +} diff --git a/src/realm-settings/keys/key-providers/rsa-generated/View.tsx b/src/realm-settings/keys/key-providers/rsa-generated/View.tsx new file mode 100644 index 0000000000..6fa9317c6d --- /dev/null +++ b/src/realm-settings/keys/key-providers/rsa-generated/View.tsx @@ -0,0 +1,123 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FormGroup, + Select, + SelectOption, + SelectVariant, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View({ isEnc = false }: { isEnc?: boolean }) { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + + const [isKeySizeDropdownOpen, toggleKeySizeDropdown] = useToggle(); + const [isEllipticCurveDropdownOpen, toggleEllipticCurveDropdown] = + useToggle(); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + + const rsaGeneratedKeySizeOptions = + allComponentTypes[6].properties[3].options ?? []; + + const rsaGeneratedAlgorithmOptions = + allComponentTypes[6].properties[4].options ?? []; + + const rsaEncGeneratedKeySizeOptions = + allComponentTypes[5].properties[3].options ?? []; + + const rsaEncGeneratedAlgorithmOptions = + allComponentTypes[5].properties[4].options ?? []; + + return ( + <> + + } + > + ( + + )} + /> + + + } + > + ( + + )} + /> + + + ); +} diff --git a/src/realm-settings/keys/key-providers/rsa/View.tsx b/src/realm-settings/keys/key-providers/rsa/View.tsx new file mode 100644 index 0000000000..f1f4876da7 --- /dev/null +++ b/src/realm-settings/keys/key-providers/rsa/View.tsx @@ -0,0 +1,127 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useFormContext, Controller } from "react-hook-form"; +import { + FileUpload, + FormGroup, + Select, + SelectOption, + SelectVariant, +} from "@patternfly/react-core"; + +import { useServerInfo } from "../../../../context/server-info/ServerInfoProvider"; +import { HelpItem } from "../../../../components/help-enabler/HelpItem"; +import { KEY_PROVIDER_TYPE } from "../../../../util"; +import useToggle from "../../../../utils/useToggle"; + +export default function View() { + const { t } = useTranslation("realm-settings"); + const { control } = useFormContext(); + const [isRSAalgDropdownOpen, toggleDropdown] = useToggle(); + const [privateKey, setPrivateKey] = useState(""); + const [certificate, setCertificate] = useState(""); + + const serverInfo = useServerInfo(); + const allComponentTypes = + serverInfo.componentTypes?.[KEY_PROVIDER_TYPE] ?? []; + + const rsaAlgOptions = allComponentTypes[4].properties[3].options ?? []; + + return ( + <> + + } + > + ( + + )} + /> + + + } + > + ( + { + onChange(value); + setPrivateKey(filename); + }} + filenamePlaceholder={t("filenamePlaceholder")} + /> + )} + /> + + + } + > + ( + { + onChange(value); + setCertificate(filename); + }} + filenamePlaceholder={t("filenamePlaceholder")} + /> + )} + /> + + + ); +} diff --git a/src/realm-settings/messages.ts b/src/realm-settings/messages.ts index afba9de389..1bb388f898 100644 --- a/src/realm-settings/messages.ts +++ b/src/realm-settings/messages.ts @@ -10,7 +10,7 @@ export default { "If you delete this realm, all associated data will be removed.", deleteProviderTitle: "Delete key provider?", deleteProviderConfirm: - "Are you sure you want to permanently delete the key provider ", + "Are you sure you want to permanently delete the key provider {{provider}}?", deleteProviderSuccess: "Success. The provider has been deleted.", deleteProviderError: "Error deleting the provider", deletedSuccess: "The realm has been deleted", @@ -84,6 +84,7 @@ export default { AESKeySize: "AES Key Size", active: "Active", privateRSAKey: "Private RSA Key", + filenamePlaceholder: "Upload a PEM file or paste key below", x509Certificate: "X509 Certificate", ellipticCurve: "Elliptic Curve", secretSize: "Secret size", @@ -96,11 +97,13 @@ export default { providerDescription: "Provider description", addProvider: "Add provider", publicKeys: "Public keys", - activeKeys: "Active keys", - passiveKeys: "Passive keys", - disabledKeys: "Disabled keys", + keysFilter: { + ACTIVE: "Active keys", + PASSIVE: "Passive keys", + DISABLED: "Disabled keys", + }, noKeys: "No keys", - noKeysDescription: "You haven't created any ", + noKeysDescription: "You haven't created any active keys", certificate: "Certificate", loginScreenCustomization: "Login screen customization", userRegistration: "User registration", diff --git a/src/realm-settings/routes.ts b/src/realm-settings/routes.ts index 54edf5ebc8..40393dfbc1 100644 --- a/src/realm-settings/routes.ts +++ b/src/realm-settings/routes.ts @@ -1,11 +1,6 @@ import type { RouteDef } from "../route-config"; -import { AesGeneratedSettingsRoute } from "./routes/AesGeneratedSettings"; -import { EcdsaGeneratedSettingsRoute } from "./routes/EcdsaGeneratedSettings"; -import { HmacGeneratedSettingsRoute } from "./routes/HmacGeneratedSettings"; -import { JavaKeystoreSettingsRoute } from "./routes/JavaKeystoreSettings"; +import { KeyProviderFormRoute } from "./routes/KeyProvider"; import { RealmSettingsRoute } from "./routes/RealmSettings"; -import { RsaGeneratedSettingsRoute } from "./routes/RsaGeneratedSettings"; -import { RsaSettingsRoute } from "./routes/RsaSettings"; import { ClientPoliciesRoute } from "./routes/ClientPolicies"; import { AddClientProfileRoute } from "./routes/AddClientProfile"; import { ClientProfileRoute } from "./routes/ClientProfile"; @@ -18,18 +13,11 @@ import { EditClientPolicyConditionRoute } from "./routes/EditCondition"; import { UserProfileRoute } from "./routes/UserProfile"; import { AddAttributeRoute } from "./routes/AddAttribute"; import { KeysRoute } from "./routes/KeysTab"; -import { RsaEncGeneratedSettingsRoute } from "./routes/RsaEncGeneratedSettings"; const routes: RouteDef[] = [ RealmSettingsRoute, KeysRoute, - AesGeneratedSettingsRoute, - EcdsaGeneratedSettingsRoute, - HmacGeneratedSettingsRoute, - JavaKeystoreSettingsRoute, - RsaEncGeneratedSettingsRoute, - RsaGeneratedSettingsRoute, - RsaSettingsRoute, + KeyProviderFormRoute, ClientPoliciesRoute, AddClientProfileRoute, AddExecutorRoute, diff --git a/src/realm-settings/routes/AesGeneratedSettings.ts b/src/realm-settings/routes/AesGeneratedSettings.ts deleted file mode 100644 index c5e979563a..0000000000 --- a/src/realm-settings/routes/AesGeneratedSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type KeyProviderParams = { - realm: string; - id: string; -}; - -export const AesGeneratedSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/aes-generated/settings", - component: lazy( - () => import("../key-providers/aes-generated/AESGeneratedForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toAesGeneratedSettings = ( - params: KeyProviderParams -): LocationDescriptorObject => ({ - pathname: generatePath(AesGeneratedSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/EcdsaGeneratedSettings.ts b/src/realm-settings/routes/EcdsaGeneratedSettings.ts deleted file mode 100644 index b25e55c69f..0000000000 --- a/src/realm-settings/routes/EcdsaGeneratedSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type EcdsaGeneratedSettingsParams = { - realm: string; - id: string; -}; - -export const EcdsaGeneratedSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/ecdsa-generated/settings", - component: lazy( - () => import("../key-providers/ecdsa-generated/ECDSAGeneratedForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toEcdsaGeneratedSettings = ( - params: EcdsaGeneratedSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(EcdsaGeneratedSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/HmacGeneratedSettings.ts b/src/realm-settings/routes/HmacGeneratedSettings.ts deleted file mode 100644 index 4bb30aa538..0000000000 --- a/src/realm-settings/routes/HmacGeneratedSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type HmacGeneratedSettingsParams = { - realm: string; - id: string; -}; - -export const HmacGeneratedSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/hmac-generated/settings", - component: lazy( - () => import("../key-providers/hmac-generated/HMACGeneratedForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toHmacGeneratedSettings = ( - params: HmacGeneratedSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(HmacGeneratedSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/JavaKeystoreSettings.ts b/src/realm-settings/routes/JavaKeystoreSettings.ts deleted file mode 100644 index 4005efd215..0000000000 --- a/src/realm-settings/routes/JavaKeystoreSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type JavaKeystoreSettingsParams = { - realm: string; - id: string; -}; - -export const JavaKeystoreSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/java-keystore/settings", - component: lazy( - () => import("../key-providers/java-keystore/JavaKeystoreForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toJavaKeystoreSettings = ( - params: JavaKeystoreSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(JavaKeystoreSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/KeyProvider.ts b/src/realm-settings/routes/KeyProvider.ts new file mode 100644 index 0000000000..e150731b74 --- /dev/null +++ b/src/realm-settings/routes/KeyProvider.ts @@ -0,0 +1,32 @@ +import type { LocationDescriptorObject } from "history"; +import { lazy } from "react"; +import { generatePath } from "react-router-dom"; +import type { RouteDef } from "../../route-config"; + +export type ProviderType = + | "aes-generated" + | "ecdsa-generated" + | "hmac-generated" + | "java-keystore" + | "rsa" + | "rsa-enc-generated" + | "rsa-generated"; + +export type KeyProviderParams = { + id: string; + providerType: ProviderType; + realm: string; +}; + +export const KeyProviderFormRoute: RouteDef = { + path: "/:realm/realm-settings/keys/providers/:id/:providerType/settings", + component: lazy(() => import("../keys/key-providers/KeyProviderForm")), + breadcrumb: (t) => t("realm-settings:editProvider"), + access: "view-realm", +}; + +export const toKeyProvider = ( + params: KeyProviderParams +): LocationDescriptorObject => ({ + pathname: generatePath(KeyProviderFormRoute.path, params), +}); diff --git a/src/realm-settings/routes/RsaEncGeneratedSettings.ts b/src/realm-settings/routes/RsaEncGeneratedSettings.ts deleted file mode 100644 index ca61716863..0000000000 --- a/src/realm-settings/routes/RsaEncGeneratedSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type RsaGeneratedSettingsParams = { - realm: string; - id: string; -}; - -export const RsaEncGeneratedSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/rsa-enc-generated/settings", - component: lazy( - () => import("../key-providers/rsa-generated/RSAGeneratedForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toRsaEncGeneratedSettings = ( - params: RsaGeneratedSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(RsaEncGeneratedSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/RsaGeneratedSettings.ts b/src/realm-settings/routes/RsaGeneratedSettings.ts deleted file mode 100644 index b0aa536ebd..0000000000 --- a/src/realm-settings/routes/RsaGeneratedSettings.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type RsaGeneratedSettingsParams = { - realm: string; - id: string; -}; - -export const RsaGeneratedSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/rsa-generated/settings", - component: lazy( - () => import("../key-providers/rsa-generated/RSAGeneratedForm") - ), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toRsaGeneratedSettings = ( - params: RsaGeneratedSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(RsaGeneratedSettingsRoute.path, params), -}); diff --git a/src/realm-settings/routes/RsaSettings.ts b/src/realm-settings/routes/RsaSettings.ts deleted file mode 100644 index 517bb8899b..0000000000 --- a/src/realm-settings/routes/RsaSettings.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { LocationDescriptorObject } from "history"; -import { lazy } from "react"; -import { generatePath } from "react-router-dom"; -import type { RouteDef } from "../../route-config"; - -export type RsaSettingsParams = { - realm: string; - id: string; -}; - -export const RsaSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/keys/providers/:id/rsa/settings", - component: lazy(() => import("../key-providers/rsa/RSAForm")), - breadcrumb: (t) => t("realm-settings:editProvider"), - access: "view-realm", -}; - -export const toRsaSettings = ( - params: RsaSettingsParams -): LocationDescriptorObject => ({ - pathname: generatePath(RsaSettingsRoute.path, params), -});