import React, { useState } from "react"; import { Link, useHistory, useParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Controller, FormProvider, useForm, useWatch } from "react-hook-form"; import { ActionGroup, AlertVariant, Button, ButtonVariant, DropdownItem, FormGroup, PageSection, Radio, SelectVariant, Switch, TextArea, TextInput, } from "@patternfly/react-core"; import type PolicyRepresentation from "@keycloak/keycloak-admin-client/lib/defs/policyRepresentation"; import type { NewPermissionParams } from "../routes/NewPermission"; import { PermissionDetailsParams, toPermissionDetails, } from "../routes/PermissionDetails"; import { useAdminClient, useFetch } from "../../context/auth/AdminClient"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { ViewHeader } from "../../components/view-header/ViewHeader"; import { FormAccess } from "../../components/form-access/FormAccess"; import { useAlerts } from "../../components/alert/Alerts"; import { HelpItem } from "../../components/help-enabler/HelpItem"; import { ResourcesPolicySelect } from "./ResourcesPolicySelect"; import { toAuthorizationTab } from "../routes/AuthenticationTab"; import { ScopeSelect } from "./ScopeSelect"; import { toUpperCase } from "../../util"; import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner"; const DECISION_STRATEGIES = ["UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"] as const; export default function PermissionDetails() { const { t } = useTranslation("clients"); const form = useForm({ shouldUnregister: false, mode: "onChange", }); const { register, control, reset, errors, handleSubmit } = form; const history = useHistory(); const { id, realm, permissionType, permissionId, selectedId } = useParams< NewPermissionParams & PermissionDetailsParams >(); const adminClient = useAdminClient(); const { addAlert, addError } = useAlerts(); const [permission, setPermission] = useState(); const [applyToResourceTypeFlag, setApplyToResourceTypeFlag] = useState(false); useFetch( async () => { if (!permissionId) { return {}; } const [permission, resources, policies, scopes] = await Promise.all([ adminClient.clients.findOnePermission({ id, type: permissionType, permissionId, }), adminClient.clients.getAssociatedResources({ id, permissionId, }), adminClient.clients.getAssociatedPolicies({ id, permissionId, }), adminClient.clients.getAssociatedScopes({ id, permissionId, }), ]); if (!permission) { throw new Error(t("common:notFound")); } return { permission, resources: resources.map((r) => r._id), policies: policies.map((p) => p.id!), scopes: scopes.map((s) => s.id!), }; }, ({ permission, resources, policies, scopes }) => { reset({ ...permission, resources, policies, scopes }); if (permission && "resourceType" in permission) { setApplyToResourceTypeFlag( !!(permission as { resourceType: string }).resourceType ); } setPermission({ ...permission, resources, policies }); }, [] ); const save = async (permission: PolicyRepresentation) => { try { if (permissionId) { await adminClient.clients.updatePermission( { id, type: permissionType, permissionId }, permission ); } else { const result = await adminClient.clients.createPermission( { id, type: permissionType }, permission ); history.push( toPermissionDetails({ realm, id, permissionType, permissionId: result.id!, }) ); } addAlert( t((permissionId ? "update" : "create") + "PermissionSuccess"), AlertVariant.success ); } catch (error) { addError("clients:permissionSaveError", error); } }; const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: "clients:deletePermission", messageKey: t("deletePermissionConfirm", { permission: permission?.name, }), continueButtonVariant: ButtonVariant.danger, continueButtonLabel: "clients:confirm", onConfirm: async () => { try { await adminClient.clients.delPermission({ id, type: permissionType, permissionId: permissionId, }); addAlert(t("permissionDeletedSuccess"), AlertVariant.success); history.push( toAuthorizationTab({ realm, clientId: id, tab: "permissions" }) ); } catch (error) { addError("clients:permissionDeletedError", error); } }, }); const resourcesIds = useWatch({ control, name: "resources", defaultValue: [], }); if (!permission) { return ; } return ( <> toggleDeleteDialog()} > {t("common:delete")} , ] : undefined } /> } > } validated={errors.description ? "error" : "default"} helperTextInvalid={errors.description?.message} >