add action menu to current user (#1094)

* add action menu to delete current user

* added impersonate user to action manu

* fixed spelling
This commit is contained in:
Erik Jan de Wit 2021-09-03 15:54:23 +02:00 committed by GitHub
parent 6e8ec947b5
commit f87463d036
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 81 additions and 22 deletions

14
package-lock.json generated
View file

@ -8,7 +8,7 @@
"version": "0.0.1", "version": "0.0.1",
"license": "Apache", "license": "Apache",
"dependencies": { "dependencies": {
"@keycloak/keycloak-admin-client": "^16.0.0-dev.0", "@keycloak/keycloak-admin-client": "^16.0.0-dev.2",
"@patternfly/patternfly": "^4.132.2", "@patternfly/patternfly": "^4.132.2",
"@patternfly/react-core": "4.152.4", "@patternfly/react-core": "4.152.4",
"@patternfly/react-icons": "4.11.14", "@patternfly/react-icons": "4.11.14",
@ -2541,9 +2541,9 @@
} }
}, },
"node_modules/@keycloak/keycloak-admin-client": { "node_modules/@keycloak/keycloak-admin-client": {
"version": "16.0.0-dev.0", "version": "16.0.0-dev.2",
"resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-16.0.0-dev.0.tgz", "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-16.0.0-dev.2.tgz",
"integrity": "sha512-o1gUKPn6Zeqe//1v2TF5VVvwDeeXktUFf/L70rQ8KJC/PudGPnV6luDu6Pyj/G32Yoc5iigSMWFly5Qlsd0bgw==", "integrity": "sha512-eLeN4/O5OWjU0fIIvndv0oLSRQN3q0bdMep19E+09/qL4jeNeBR4ltxLKd0mnW1FY53cZJ+QWLaq/lfgRXFfzA==",
"dependencies": { "dependencies": {
"axios": "^0.21.0", "axios": "^0.21.0",
"camelize": "^1.0.0", "camelize": "^1.0.0",
@ -19352,9 +19352,9 @@
} }
}, },
"@keycloak/keycloak-admin-client": { "@keycloak/keycloak-admin-client": {
"version": "16.0.0-dev.0", "version": "16.0.0-dev.2",
"resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-16.0.0-dev.0.tgz", "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-16.0.0-dev.2.tgz",
"integrity": "sha512-o1gUKPn6Zeqe//1v2TF5VVvwDeeXktUFf/L70rQ8KJC/PudGPnV6luDu6Pyj/G32Yoc5iigSMWFly5Qlsd0bgw==", "integrity": "sha512-eLeN4/O5OWjU0fIIvndv0oLSRQN3q0bdMep19E+09/qL4jeNeBR4ltxLKd0mnW1FY53cZJ+QWLaq/lfgRXFfzA==",
"requires": { "requires": {
"axios": "^0.21.0", "axios": "^0.21.0",
"camelize": "^1.0.0", "camelize": "^1.0.0",

View file

@ -24,7 +24,7 @@
"prepare": "husky install" "prepare": "husky install"
}, },
"dependencies": { "dependencies": {
"@keycloak/keycloak-admin-client": "^16.0.0-dev.0", "@keycloak/keycloak-admin-client": "^16.0.0-dev.2",
"@patternfly/patternfly": "^4.132.2", "@patternfly/patternfly": "^4.132.2",
"@patternfly/react-core": "4.152.4", "@patternfly/react-core": "4.152.4",
"@patternfly/react-icons": "4.11.14", "@patternfly/react-icons": "4.11.14",

View file

@ -59,7 +59,6 @@ export default {
searchForRole: "Search role", searchForRole: "Search role",
origin: "Origin", origin: "Origin",
user: "User", user: "User",
details: "Details",
noGeneratedAccessToken: "No generated access token", noGeneratedAccessToken: "No generated access token",
generatedAccessTokenIsDisabled: generatedAccessTokenIsDisabled:
"Generated access token is disabled when no user is selected", "Generated access token is disabled when no user is selected",

View file

@ -84,6 +84,7 @@ export default {
userFederation: "User federation", userFederation: "User federation",
settings: "Settings", settings: "Settings",
details: "Details",
required: "Required field", required: "Required field",
maxLength: "Max length {{length}}", maxLength: "Max length {{length}}",

View file

@ -144,11 +144,11 @@ export const DownloadDialog = ({
<StackItem isFilled> <StackItem isFilled>
<FormGroup <FormGroup
fieldId="details" fieldId="details"
label={t("clients:details")} label={t("details")}
labelIcon={ labelIcon={
<HelpItem <HelpItem
helpText={t("clients-help:details")} helpText={t("clients-help:details")}
forLabel={t("clients:details")} forLabel={t("details")}
forID="details" forID="details"
/> />
} }

View file

@ -331,7 +331,7 @@ export const RealmRoleTabs = () => {
<KeycloakTabs isBox> <KeycloakTabs isBox>
<Tab <Tab
eventKey="details" eventKey="details"
title={<TabTitleText>{t("details")}</TabTitleText>} title={<TabTitleText>{t("common:details")}</TabTitleText>}
> >
<PageSection variant="light"> <PageSection variant="light">
<RealmRoleForm <RealmRoleForm

View file

@ -22,7 +22,6 @@ export default {
roleDetails: "Role details", roleDetails: "Role details",
composite: "Composite", composite: "Composite",
deleteRole: "Delete this role", deleteRole: "Delete this role",
details: "Details",
inheritedFrom: "Inherited from", inheritedFrom: "Inherited from",
roleList: "Role list", roleList: "Role list",
searchFor: "Search role by name", searchFor: "Search role by name",

View file

@ -1,6 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { import {
AlertVariant, AlertVariant,
ButtonVariant,
DropdownItem,
PageSection, PageSection,
Tab, Tab,
TabTitleText, TabTitleText,
@ -20,10 +22,12 @@ import { UserGroups } from "./UserGroups";
import { UserConsents } from "./UserConsents"; import { UserConsents } from "./UserConsents";
import { useRealm } from "../context/realm-context/RealmContext"; import { useRealm } from "../context/realm-context/RealmContext";
import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks"; import { UserIdentityProviderLinks } from "./UserIdentityProviderLinks";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { toUser } from "./routes/User"; import { toUser } from "./routes/User";
import { toUsers } from "./routes/Users";
export const UsersTabs = () => { export const UsersTabs = () => {
const { t } = useTranslation("roles"); const { t } = useTranslation("users");
const { addAlert, addError } = useAlerts(); const { addAlert, addError } = useAlerts();
const history = useHistory(); const history = useHistory();
const { realm } = useRealm(); const { realm } = useRealm();
@ -70,7 +74,7 @@ export const UsersTabs = () => {
try { try {
if (id) { if (id) {
await adminClient.users.update({ id }, user); await adminClient.users.update({ id }, user);
addAlert(t("users:userSaved"), AlertVariant.success); addAlert(t("userSaved"), AlertVariant.success);
} else { } else {
const createdUser = await adminClient.users.create(user); const createdUser = await adminClient.users.create(user);
@ -81,7 +85,7 @@ export const UsersTabs = () => {
}); });
}); });
addAlert(t("users:userCreated"), AlertVariant.success); addAlert(t("userCreated"), AlertVariant.success);
history.push(toUser({ id: createdUser.id, realm, tab: "settings" })); history.push(toUser({ id: createdUser.id, realm, tab: "settings" }));
} }
} catch (error) { } catch (error) {
@ -89,11 +93,61 @@ export const UsersTabs = () => {
} }
}; };
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "users:deleteConfirm",
messageKey: "users:deleteConfirmCurrentUser",
continueButtonLabel: "common:delete",
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
try {
await adminClient.users.del({ id });
addAlert(t("userDeletedSuccess"), AlertVariant.success);
history.push(toUsers({ realm }));
} catch (error) {
addError("users:userDeletedError", error);
}
},
});
const [toggleImpersonateDialog, ImpersonateConfirm] = useConfirmDialog({
titleKey: "users:impersonateConfirm",
messageKey: "users:impersonateConfirmDialog",
continueButtonLabel: "users:impersonate",
onConfirm: async () => {
try {
const data = await adminClient.users.impersonation(
{ id },
{ user: id, realm }
);
if (data.sameRealm) {
window.location = data.redirect;
} else {
window.open(data.redirect, "_blank");
}
} catch (error) {
addError("users:impersonateError", error);
}
},
});
return ( return (
<> <>
<ImpersonateConfirm />
<DeleteConfirm />
<ViewHeader <ViewHeader
titleKey={user?.username || t("users:createUser")} titleKey={user?.username || t("users:createUser")}
divider={!id} divider={!id}
dropdownItems={[
<DropdownItem
key="impersonate"
onClick={() => toggleImpersonateDialog()}
>
{t("impersonate")}
</DropdownItem>,
<DropdownItem key="delete" onClick={() => toggleDeleteDialog()}>
{t("common:delete")}
</DropdownItem>,
]}
/> />
<PageSection variant="light" className="pf-u-p-0"> <PageSection variant="light" className="pf-u-p-0">
<FormProvider {...userForm}> <FormProvider {...userForm}>
@ -102,7 +156,7 @@ export const UsersTabs = () => {
<Tab <Tab
eventKey="settings" eventKey="settings"
data-testid="user-details-tab" data-testid="user-details-tab"
title={<TabTitleText>{t("details")}</TabTitleText>} title={<TabTitleText>{t("common:details")}</TabTitleText>}
> >
<PageSection variant="light"> <PageSection variant="light">
{bruteForced && ( {bruteForced && (
@ -118,14 +172,14 @@ export const UsersTabs = () => {
<Tab <Tab
eventKey="groups" eventKey="groups"
data-testid="user-groups-tab" data-testid="user-groups-tab"
title={<TabTitleText>{t("groups")}</TabTitleText>} title={<TabTitleText>{t("common:groups")}</TabTitleText>}
> >
<UserGroups user={user} /> <UserGroups user={user} />
</Tab> </Tab>
<Tab <Tab
eventKey="consents" eventKey="consents"
data-testid="user-consents-tab" data-testid="user-consents-tab"
title={<TabTitleText>{t("users:consents")}</TabTitleText>} title={<TabTitleText>{t("consents")}</TabTitleText>}
> >
<UserConsents /> <UserConsents />
</Tab> </Tab>
@ -133,9 +187,7 @@ export const UsersTabs = () => {
eventKey="identity-provider-links" eventKey="identity-provider-links"
data-testid="identity-provider-links-tab" data-testid="identity-provider-links-tab"
title={ title={
<TabTitleText> <TabTitleText>{t("identityProviderLinks")}</TabTitleText>
{t("users:identityProviderLinks")}
</TabTitleText>
} }
> >
<UserIdentityProviderLinks /> <UserIdentityProviderLinks />

View file

@ -46,8 +46,16 @@ export default {
notVerified: "Not verified", notVerified: "Not verified",
requiredUserActions: "Required user actions", requiredUserActions: "Required user actions",
addUser: "Add user", addUser: "Add user",
impersonate: "Impersonate",
impersonateConfirm: "Impersonate user?",
impersonateConfirmDialog:
"Are you sure you want to log in as this user? If this user is in the same realm with you, your current login session will be logged out before you log in as this user.",
impersonateError: "Could not impersonate the user: {{error}}",
deleteUser: "Delete user", deleteUser: "Delete user",
deleteConfirm: "Delete user?", deleteConfirm: "Delete user?",
deleteConfirmCurrentUser:
"Are you sure you want to permanently delete this user",
deleteConfirmDialog: deleteConfirmDialog:
"Are you sure you want to permanently delete {{count}} selected user", "Are you sure you want to permanently delete {{count}} selected user",
deleteConfirmDialog_plural: deleteConfirmDialog_plural: