feat: Add 'delete user' option for admins
This commit is contained in:
@@ -2,6 +2,7 @@ import { PlusIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import stores from "~/stores";
|
||||
import Invite from "~/scenes/Invite";
|
||||
import { UserDeleteDialog } from "~/components/UserDialogs";
|
||||
import { createAction } from "~/actions";
|
||||
import { UserSection } from "~/actions/sections";
|
||||
|
||||
@@ -21,4 +22,31 @@ export const inviteUser = createAction({
|
||||
},
|
||||
});
|
||||
|
||||
export const deleteUserActionFactory = (userId: string) =>
|
||||
createAction({
|
||||
name: ({ t }) => `${t("Delete user")}…`,
|
||||
analyticsName: "Delete user",
|
||||
keywords: "leave",
|
||||
dangerous: true,
|
||||
section: UserSection,
|
||||
visible: ({ stores }) => stores.policies.abilities(userId).delete,
|
||||
perform: ({ t }) => {
|
||||
const user = stores.users.get(userId);
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
stores.dialogs.openModal({
|
||||
title: t("Delete user"),
|
||||
isCentered: true,
|
||||
content: (
|
||||
<UserDeleteDialog
|
||||
user={user}
|
||||
onSubmit={stores.dialogs.closeAllModals}
|
||||
/>
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const rootUserActions = [inviteUser];
|
||||
|
||||
@@ -58,6 +58,31 @@ export function UserChangeToMemberDialog({ user, onSubmit }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
export function UserDeleteDialog({ user, onSubmit }: Props) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await user.delete();
|
||||
onSubmit();
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfirmationDialog
|
||||
onSubmit={handleSubmit}
|
||||
submitText={t("I understand, delete")}
|
||||
savingText={`${t("Deleting")}…`}
|
||||
danger
|
||||
>
|
||||
{t(
|
||||
"Are you sure you want to permanently delete {{ userName }}? This operation is unrecoverable, consider suspending the user instead.",
|
||||
{
|
||||
userName: user.name,
|
||||
}
|
||||
)}
|
||||
</ConfirmationDialog>
|
||||
);
|
||||
}
|
||||
|
||||
export function UserChangeToAdminDialog({ user, onSubmit }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { users } = useStores();
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
UserChangeToViewerDialog,
|
||||
UserSuspendDialog,
|
||||
UserChangeNameDialog,
|
||||
} from "~/components/UserRoleDialogs";
|
||||
} from "~/components/UserDialogs";
|
||||
import { actionToMenuItem } from "~/actions";
|
||||
import { deleteUserActionFactory } from "~/actions/definitions/users";
|
||||
import useActionContext from "~/hooks/useActionContext";
|
||||
import usePolicy from "~/hooks/usePolicy";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import useToasts from "~/hooks/useToasts";
|
||||
@@ -29,6 +32,9 @@ function UserMenu({ user }: Props) {
|
||||
});
|
||||
const can = usePolicy(user.id);
|
||||
const { showToast } = useToasts();
|
||||
const context = useActionContext({
|
||||
isContextMenu: true,
|
||||
});
|
||||
|
||||
const handlePromote = React.useCallback(
|
||||
(ev: React.SyntheticEvent) => {
|
||||
@@ -99,7 +105,7 @@ function UserMenu({ user }: Props) {
|
||||
(ev: React.SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
dialogs.openModal({
|
||||
title: t("Suspend account"),
|
||||
title: t("Suspend user"),
|
||||
isCentered: true,
|
||||
content: (
|
||||
<UserSuspendDialog user={user} onSubmit={dialogs.closeAllModals} />
|
||||
@@ -199,11 +205,14 @@ function UserMenu({ user }: Props) {
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
title: `${t("Suspend account")}…`,
|
||||
dangerous: true,
|
||||
title: `${t("Suspend user")}…`,
|
||||
onClick: handleSuspend,
|
||||
visible: !user.isInvited && !user.isSuspended,
|
||||
},
|
||||
{
|
||||
type: "separator",
|
||||
},
|
||||
actionToMenuItem(deleteUserActionFactory(user.id), context),
|
||||
]}
|
||||
/>
|
||||
</ContextMenu>
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
"New workspace": "New workspace",
|
||||
"Create a workspace": "Create a workspace",
|
||||
"Invite people": "Invite people",
|
||||
"Delete user": "Delete user",
|
||||
"Collection": "Collection",
|
||||
"Debug": "Debug",
|
||||
"Document": "Document",
|
||||
@@ -227,6 +228,8 @@
|
||||
"Saving": "Saving",
|
||||
"Are you sure you want to make {{ userName }} a read-only viewer? They will not be able to edit any content": "Are you sure you want to make {{ userName }} a read-only viewer? They will not be able to edit any content",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
"I understand, delete": "I understand, delete",
|
||||
"Are you sure you want to permanently delete {{ userName }}? This operation is unrecoverable, consider suspending the user instead.": "Are you sure you want to permanently delete {{ userName }}? This operation is unrecoverable, consider suspending the user instead.",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to suspend {{ userName }}? Suspended users will be prevented from logging in.": "Are you sure you want to suspend {{ userName }}? Suspended users will be prevented from logging in.",
|
||||
"Save": "Save",
|
||||
@@ -360,7 +363,7 @@
|
||||
"Change role to member": "Change role to member",
|
||||
"Change role to viewer": "Change role to viewer",
|
||||
"Change name": "Change name",
|
||||
"Suspend account": "Suspend account",
|
||||
"Suspend user": "Suspend user",
|
||||
"An error occurred while sending the invite": "An error occurred while sending the invite",
|
||||
"User options": "User options",
|
||||
"Resend invite": "Resend invite",
|
||||
|
||||
Reference in New Issue
Block a user