Merge branch 'dev' into alerting-rules

This commit is contained in:
Owen
2026-04-17 14:29:36 -07:00
3 changed files with 45 additions and 40 deletions

View File

@@ -1,7 +1,7 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db, orgs, userOrgs, users } from "@server/db";
import { eq, and, inArray } from "drizzle-orm";
import { eq, and, inArray, not } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
@@ -17,11 +17,10 @@ import { verifyTotpCode } from "@server/auth/totp";
import { calculateUserClientsForOrgs } from "@server/lib/calculateUserClientsForOrgs";
import { build } from "@server/build";
import { getOrgTierData } from "#dynamic/lib/billing";
import {
deleteOrgById,
sendTerminationMessages
} from "@server/lib/deleteOrg";
import { deleteOrgById, sendTerminationMessages } from "@server/lib/deleteOrg";
import { UserType } from "@server/types/UserTypes";
import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing";
const deleteMyAccountBody = z.strictObject({
password: z.string().optional(),
@@ -98,9 +97,9 @@ export async function deleteMyAccount(
and(eq(userOrgs.userId, userId), eq(userOrgs.isOwner, true))
);
const orgIds = ownedOrgsRows.map((r) => r.orgId);
const ownedOrgIds = ownedOrgsRows.map((r) => r.orgId);
if (build === "saas" && orgIds.length > 0) {
if (build === "saas" && ownedOrgIds.length > 0) {
const primaryOrgId = ownedOrgsRows.find(
(r) => r.isBillingOrg && r.isOwner
)?.orgId;
@@ -119,14 +118,14 @@ export async function deleteMyAccount(
if (!password) {
const orgsWithNames =
orgIds.length > 0
ownedOrgIds.length > 0
? await db
.select({
orgId: orgs.orgId,
name: orgs.name
})
.from(orgs)
.where(inArray(orgs.orgId, orgIds))
.where(inArray(orgs.orgId, ownedOrgIds))
: [];
return response<DeleteMyAccountPreviewResponse>(res, {
data: {
@@ -206,9 +205,23 @@ export async function deleteMyAccount(
olmsToTerminate: allOlmsToTerminate
});
const otherOrgsTheUserWasIn = await db
.select()
.from(userOrgs)
.where(
and(
eq(userOrgs.userId, userId),
not(inArray(userOrgs.orgId, ownedOrgIds))
)
);
await db.transaction(async (trx) => {
await trx.delete(users).where(eq(users.userId, userId));
await calculateUserClientsForOrgs(userId, trx);
// loop through the other orgs and decrement the count
for (const userOrg of otherOrgsTheUserWasIn) {
await usageService.add(userOrg.orgId, FeatureId.USERS, -1, trx);
}
});
try {
@@ -233,10 +246,7 @@ export async function deleteMyAccount(
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"An error occurred"
)
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}

View File

@@ -24,10 +24,8 @@ import dynamic from "next/dynamic";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import { FaGithub } from "react-icons/fa";
import SidebarLicenseButton from "./SidebarLicenseButton";
import { SidebarSupportButton } from "./SidebarSupportButton";
import { is } from "drizzle-orm";
const ProductUpdates = dynamic(() => import("./ProductUpdates"), {
ssr: false
@@ -291,7 +289,6 @@ export function LayoutSidebar({
: build === "enterprise"
? t("enterpriseEdition")
: "Pangolin Cloud"}
<FaGithub size={12} />
</Link>
</div>
{build === "enterprise" &&

View File

@@ -103,29 +103,27 @@ export default function ProductUpdates({
)}
>
<div className="flex flex-col gap-1">
<small
className={cn(
"text-xs text-muted-foreground flex items-center gap-1 mt-2 empty:mt-0",
showMoreUpdatesText
? "animate-in fade-in duration-300"
: "opacity-0"
)}
>
{filteredUpdates.length > 1 && (
<>
<BellIcon className="flex-none size-3" />
<span>
{showNewVersionPopup
? t("productUpdateMoreInfo", {
noOfUpdates: filteredUpdates.length
})
: t("productUpdateInfo", {
noOfUpdates: filteredUpdates.length
})}
</span>
</>
)}
</small>
{filteredUpdates.length > 1 && (
<small
className={cn(
"text-xs text-muted-foreground flex items-center gap-1 mt-2",
showMoreUpdatesText
? "animate-in fade-in duration-300"
: "opacity-0"
)}
>
<BellIcon className="flex-none size-3" />
<span>
{showNewVersionPopup
? t("productUpdateMoreInfo", {
noOfUpdates: filteredUpdates.length
})
: t("productUpdateInfo", {
noOfUpdates: filteredUpdates.length
})}
</span>
</small>
)}
<ProductUpdatesListPopup
updates={filteredUpdates}
show={filteredUpdates.length > 0}
@@ -378,7 +376,7 @@ function NewVersionAvailable({
<span>
{t("pangolinUpdateAvailableReleaseNotes")}
</span>
<ArrowRight className="flex-none size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-1" />
<ArrowRight className="flex-none size-3" />
</div>
</div>
</a>