diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx
index 1bf7aa08..8c9813fc 100644
--- a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx
+++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx
@@ -36,6 +36,9 @@ export const ShowInvitations = () => {
const { data, isLoading, refetch } =
api.organization.allInvitations.useQuery();
+ const { mutateAsync: removeInvitation } =
+ api.organization.removeInvitation.useMutation();
+
return (
@@ -182,6 +185,22 @@ export const ShowInvitations = () => {
Cancel Invitation
)}
+
+ {
+ await removeInvitation({
+ invitationId: invitation.id,
+ }).then(() => {
+ refetch();
+ toast.success(
+ "Invitation removed",
+ );
+ });
+ }}
+ >
+ Remove Invitation
+
>
)}
diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts
index 3d7753de..25498143 100644
--- a/apps/dokploy/server/api/routers/organization.ts
+++ b/apps/dokploy/server/api/routers/organization.ts
@@ -157,4 +157,31 @@ export const organizationRouter = createTRPCRouter({
orderBy: [desc(invitation.status), desc(invitation.expiresAt)],
});
}),
+ removeInvitation: adminProcedure
+ .input(z.object({ invitationId: z.string() }))
+ .mutation(async ({ ctx, input }) => {
+ const invitationResult = await db.query.invitation.findFirst({
+ where: eq(invitation.id, input.invitationId),
+ });
+
+ if (!invitationResult) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Invitation not found",
+ });
+ }
+
+ if (
+ invitationResult?.organizationId !== ctx.session.activeOrganizationId
+ ) {
+ throw new TRPCError({
+ code: "FORBIDDEN",
+ message: "You are not allowed to remove this invitation",
+ });
+ }
+
+ return await db
+ .delete(invitation)
+ .where(eq(invitation.id, input.invitationId));
+ }),
});