fix: Organizations Admin improvements (#13656)

* Admin improvements

* chore: improve spacing

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
This commit is contained in:
Hariom Balhara
2024-02-14 10:34:45 -03:00
committed by GitHub
co-authored by Udit Takkar Udit Takkar
parent bb48ccbad9
commit bafa3c97ac
5 changed files with 38 additions and 16 deletions
@@ -2195,7 +2195,7 @@
"create_your_org_description": "Upgrade to Enterprise and receive a subdomain, unified billing, Insights, extensive whitelabeling and more",
"other_payment_app_enabled": "You can only enable one payment app per event type",
"admin_delete_organization_description": "<ul><li>Teams that are member of this organization will also be deleted along with their event-types</li><li>Users that were part of the organization will not be deleted and their event-types will also remain intact.</li><li>Usernames would be changed to allow them to exist outside the organization</li></ul>",
"admin_delete_organization_title": "Delete organization?",
"admin_delete_organization_title": "Delete {{organizationName}}?",
"published": "Published",
"unpublished": "Unpublished",
"publish": "Publish",
@@ -73,7 +73,7 @@ function AdminOrgTable() {
});
};
const [orgToDelete, setOrgToDelete] = useState<number | null>(null);
const [orgToDelete, setOrgToDelete] = useState<(typeof data)[number] | null>(null);
return (
<div>
<Table>
@@ -189,7 +189,7 @@ function AdminOrgTable() {
id: "delete",
label: t("delete"),
onClick: () => {
setOrgToDelete(org.id);
setOrgToDelete(org);
},
icon: Trash,
},
@@ -202,12 +202,12 @@ function AdminOrgTable() {
</Body>
</Table>
<DeleteOrgDialog
orgId={orgToDelete}
org={orgToDelete}
onClose={() => setOrgToDelete(null)}
onConfirm={() => {
if (!orgToDelete) return;
deleteMutation.mutate({
orgId: orgToDelete,
orgId: orgToDelete.id,
});
}}
/>
@@ -232,28 +232,35 @@ AdminOrgList.getLayout = getLayout;
export default AdminOrgList;
const DeleteOrgDialog = ({
orgId,
org,
onConfirm,
onClose,
}: {
orgId: number | null;
org: {
id: number;
name: string;
} | null;
onConfirm: () => void;
onClose: () => void;
}) => {
const { t } = useLocale();
if (!org) {
return null;
}
return (
// eslint-disable-next-line @typescript-eslint/no-empty-function -- noop
<Dialog name="delete-user" open={!!orgId} onOpenChange={(open) => (open ? () => {} : onClose())}>
<Dialog name="delete-user" open={!!org.id} onOpenChange={(open) => (open ? () => {} : onClose())}>
<ConfirmationDialogContent
title={t("admin_delete_organization_title")}
title={t("admin_delete_organization_title", {
organizationName: org.name,
})}
confirmBtnText={t("delete")}
cancelBtnText={t("cancel")}
variety="danger"
onConfirm={onConfirm}>
<Trans
i18nKey="admin_delete_organization_description"
components={{ li: <li />, ul: <ul className="ml-4 list-disc" /> }}>
components={{ li: <li />, ul: <ul className="ml-4 mt-5 list-disc space-y-2" /> }}>
<ul>
<li>
Teams that are member of this organization will also be deleted along with their event-types
@@ -80,9 +80,13 @@ export const deleteDnsRecord = async (domain: string) => {
assertCloudflareEnvVars(process.env);
const dnsRecordToDelete = await getDnsRecordToDelete();
await deleteDnsRecord(dnsRecordToDelete);
if (dnsRecordToDelete) {
await deleteDnsRecord(dnsRecordToDelete);
log.info(`Deleted dns-record in Cloudflare: ${domain}`);
} else {
log.info(`CNAME not found in Cloudflare: ${domain}. Nothing to delete`);
}
log.info(`Deleted dns-record in Cloudflare: ${domain}`);
return true;
async function getDnsRecordToDelete() {
@@ -134,7 +138,7 @@ export const deleteDnsRecord = async (domain: string) => {
});
}
return searchResult.result[0];
return searchResult.result[0] as (typeof searchResult.result)[0] | null;
}
async function deleteDnsRecord(dnsRecordToDelete: { id: string }) {
+8 -1
View File
@@ -1,4 +1,5 @@
import { subdomainSuffix } from "@calcom/ee/organizations/lib/orgDomains";
import logger from "@calcom/lib/logger";
import { deleteDnsRecord, addDnsRecord } from "./deploymentServices/cloudflare";
import {
@@ -6,6 +7,7 @@ import {
createDomain as createVercelDomain,
} from "./deploymentServices/vercel";
const log = logger.getSubLogger({ prefix: ["domainManager/organization"] });
export const deleteDomain = async (slug: string) => {
const domain = `${slug}.${subdomainSuffix()}`;
// We must have some domain deleted
@@ -22,6 +24,7 @@ export const deleteDomain = async (slug: string) => {
isDnsRecordDeleted = await deleteDnsRecord(domain);
}
return isDomainDeleted && isDnsRecordDeleted;
return false;
};
export const createDomain = async (slug: string) => {
@@ -48,6 +51,10 @@ export const renameDomain = async (oldSlug: string | null, newSlug: string) => {
// First create new domain so that if it fails we still have the old domain
await createDomain(newSlug);
if (oldSlug) {
await deleteDomain(oldSlug);
try {
await deleteDomain(oldSlug);
} catch (e) {
log.error(`renameDomain: Failed to delete old domain ${oldSlug}. Do a manual deletion if needed`);
}
}
};
@@ -40,7 +40,11 @@ export const adminDeleteHandler = async ({ input }: AdminDeleteOption) => {
});
if (foundOrg.slug) {
await deleteDomain(foundOrg.slug);
try {
await deleteDomain(foundOrg.slug);
} catch (e) {
log.error(`Failed to delete domain ${foundOrg.slug}. Do a manual deletion if needed`);
}
}
await renameUsersToAvoidUsernameConflicts(foundOrg.members.map((member) => member.user));