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 * as React from "react";
|
||||||
import stores from "~/stores";
|
import stores from "~/stores";
|
||||||
import Invite from "~/scenes/Invite";
|
import Invite from "~/scenes/Invite";
|
||||||
|
import { UserDeleteDialog } from "~/components/UserDialogs";
|
||||||
import { createAction } from "~/actions";
|
import { createAction } from "~/actions";
|
||||||
import { UserSection } from "~/actions/sections";
|
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];
|
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) {
|
export function UserChangeToAdminDialog({ user, onSubmit }: Props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { users } = useStores();
|
const { users } = useStores();
|
||||||
@@ -12,7 +12,10 @@ import {
|
|||||||
UserChangeToViewerDialog,
|
UserChangeToViewerDialog,
|
||||||
UserSuspendDialog,
|
UserSuspendDialog,
|
||||||
UserChangeNameDialog,
|
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 usePolicy from "~/hooks/usePolicy";
|
||||||
import useStores from "~/hooks/useStores";
|
import useStores from "~/hooks/useStores";
|
||||||
import useToasts from "~/hooks/useToasts";
|
import useToasts from "~/hooks/useToasts";
|
||||||
@@ -29,6 +32,9 @@ function UserMenu({ user }: Props) {
|
|||||||
});
|
});
|
||||||
const can = usePolicy(user.id);
|
const can = usePolicy(user.id);
|
||||||
const { showToast } = useToasts();
|
const { showToast } = useToasts();
|
||||||
|
const context = useActionContext({
|
||||||
|
isContextMenu: true,
|
||||||
|
});
|
||||||
|
|
||||||
const handlePromote = React.useCallback(
|
const handlePromote = React.useCallback(
|
||||||
(ev: React.SyntheticEvent) => {
|
(ev: React.SyntheticEvent) => {
|
||||||
@@ -99,7 +105,7 @@ function UserMenu({ user }: Props) {
|
|||||||
(ev: React.SyntheticEvent) => {
|
(ev: React.SyntheticEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
dialogs.openModal({
|
dialogs.openModal({
|
||||||
title: t("Suspend account"),
|
title: t("Suspend user"),
|
||||||
isCentered: true,
|
isCentered: true,
|
||||||
content: (
|
content: (
|
||||||
<UserSuspendDialog user={user} onSubmit={dialogs.closeAllModals} />
|
<UserSuspendDialog user={user} onSubmit={dialogs.closeAllModals} />
|
||||||
@@ -199,11 +205,14 @@ function UserMenu({ user }: Props) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
title: `${t("Suspend account")}…`,
|
title: `${t("Suspend user")}…`,
|
||||||
dangerous: true,
|
|
||||||
onClick: handleSuspend,
|
onClick: handleSuspend,
|
||||||
visible: !user.isInvited && !user.isSuspended,
|
visible: !user.isInvited && !user.isSuspended,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "separator",
|
||||||
|
},
|
||||||
|
actionToMenuItem(deleteUserActionFactory(user.id), context),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
"New workspace": "New workspace",
|
"New workspace": "New workspace",
|
||||||
"Create a workspace": "Create a workspace",
|
"Create a workspace": "Create a workspace",
|
||||||
"Invite people": "Invite people",
|
"Invite people": "Invite people",
|
||||||
|
"Delete user": "Delete user",
|
||||||
"Collection": "Collection",
|
"Collection": "Collection",
|
||||||
"Debug": "Debug",
|
"Debug": "Debug",
|
||||||
"Document": "Document",
|
"Document": "Document",
|
||||||
@@ -227,6 +228,8 @@
|
|||||||
"Saving": "Saving",
|
"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 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?",
|
"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 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.",
|
"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",
|
"Save": "Save",
|
||||||
@@ -360,7 +363,7 @@
|
|||||||
"Change role to member": "Change role to member",
|
"Change role to member": "Change role to member",
|
||||||
"Change role to viewer": "Change role to viewer",
|
"Change role to viewer": "Change role to viewer",
|
||||||
"Change name": "Change name",
|
"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",
|
"An error occurred while sending the invite": "An error occurred while sending the invite",
|
||||||
"User options": "User options",
|
"User options": "User options",
|
||||||
"Resend invite": "Resend invite",
|
"Resend invite": "Resend invite",
|
||||||
|
|||||||
Reference in New Issue
Block a user