diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index e1e4e7e701..7caa3c4e5c 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -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": "", - "admin_delete_organization_title": "Delete organization?", + "admin_delete_organization_title": "Delete {{organizationName}}?", "published": "Published", "unpublished": "Unpublished", "publish": "Publish", diff --git a/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx b/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx index 4bd6fef59c..7ce8c42ebe 100644 --- a/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx +++ b/packages/features/ee/organizations/pages/settings/admin/AdminOrgPage.tsx @@ -73,7 +73,7 @@ function AdminOrgTable() { }); }; - const [orgToDelete, setOrgToDelete] = useState(null); + const [orgToDelete, setOrgToDelete] = useState<(typeof data)[number] | null>(null); return (
@@ -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() {
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 - (open ? () => {} : onClose())}> + (open ? () => {} : onClose())}> , ul:
    }}> + components={{ li:
  • , ul:
      }}>
      • Teams that are member of this organization will also be deleted along with their event-types diff --git a/packages/lib/domainManager/deploymentServices/cloudflare.ts b/packages/lib/domainManager/deploymentServices/cloudflare.ts index c59552cba2..ccbd316d95 100644 --- a/packages/lib/domainManager/deploymentServices/cloudflare.ts +++ b/packages/lib/domainManager/deploymentServices/cloudflare.ts @@ -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 }) { diff --git a/packages/lib/domainManager/organization.ts b/packages/lib/domainManager/organization.ts index ab738b09e0..66bd6f7baa 100644 --- a/packages/lib/domainManager/organization.ts +++ b/packages/lib/domainManager/organization.ts @@ -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`); + } } }; diff --git a/packages/trpc/server/routers/viewer/organizations/adminDelete.handler.ts b/packages/trpc/server/routers/viewer/organizations/adminDelete.handler.ts index 2cb9cd423f..79cf114641 100644 --- a/packages/trpc/server/routers/viewer/organizations/adminDelete.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/adminDelete.handler.ts @@ -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));