perf: Slim down trpc queries in Settings Layout (#20918)

* slim down settings layout by removing server queries

* add check method

* fix type check

* refactor
This commit is contained in:
Benny Joo
2025-04-23 20:13:26 +00:00
committed by GitHub
parent 513f54f4fe
commit d844fd6ef7
5 changed files with 33 additions and 54 deletions
@@ -16,7 +16,6 @@ import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { OrganizationRepository } from "@calcom/lib/server/repository/organization";
import { IdentityProvider, UserPermissionRole } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
import classNames from "@calcom/ui/classNames";
@@ -273,8 +272,6 @@ interface SettingsSidebarContainerProps {
className?: string;
navigationIsOpenedOnMobile?: boolean;
bannersHeight?: number;
currentOrg: SettingsLayoutProps["currentOrg"];
otherTeams: SettingsLayoutProps["otherTeams"];
}
const TeamListCollapsible = () => {
@@ -441,10 +438,9 @@ const SettingsSidebarContainer = ({
className = "",
navigationIsOpenedOnMobile,
bannersHeight,
currentOrg: currentOrgProp,
otherTeams: otherTeamsProp,
}: SettingsSidebarContainerProps) => {
const searchParams = useCompatSearchParams();
const orgBranding = useOrgBranding();
const { t } = useLocale();
const [otherTeamMenuState, setOtherTeamMenuState] = useState<
{
@@ -453,19 +449,17 @@ const SettingsSidebarContainer = ({
}[]
>();
const session = useSession();
const { data: _currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
enabled: !!session.data?.user?.org && !currentOrgProp,
const { data } = trpc.viewer.delegationCredential.check.useQuery(undefined, {
enabled: !!session.data?.user?.org,
});
const tabsWithPermissions = useTabs({
isDelegationCredentialEnabled: !!_currentOrg?.features?.delegationCredential,
isDelegationCredentialEnabled: data?.hasDelegationCredential ?? false,
});
const { data: _otherTeams } = trpc.viewer.organizations.listOtherTeams.useQuery(undefined, {
enabled: !!session.data?.user?.org && !otherTeamsProp,
const { data: otherTeams } = trpc.viewer.organizations.listOtherTeams.useQuery(undefined, {
enabled: !!session.data?.user?.org,
});
const currentOrg = currentOrgProp ?? _currentOrg;
const otherTeams = otherTeamsProp ?? _otherTeams;
// Same as above but for otherTeams
useEffect(() => {
if (otherTeams) {
@@ -485,8 +479,7 @@ const SettingsSidebarContainer = ({
}
}, [searchParams?.get("id"), otherTeams]);
const isOrgAdminOrOwner =
currentOrg && currentOrg?.user?.role && ["OWNER", "ADMIN"].includes(currentOrg?.user?.role);
const isOrgAdminOrOwner = checkAdminOrOwner(orgBranding?.role);
return (
<nav
@@ -569,7 +562,7 @@ const SettingsSidebarContainer = ({
</div>
</Link>
<TeamListCollapsible />
{(!currentOrg || (currentOrg && currentOrg?.user?.role !== "MEMBER")) && (
{(!orgBranding?.id || isOrgAdminOrOwner) && (
<VerticalTabItem
name={t("add_a_team")}
href={`${WEBAPP_URL}/settings/teams/new`}
@@ -733,17 +726,10 @@ const MobileSettingsContainer = (props: { onSideContainerOpen?: () => void }) =>
export type SettingsLayoutProps = {
children: React.ReactNode;
currentOrg: Awaited<ReturnType<typeof OrganizationRepository.findCurrentOrg>> | null;
otherTeams: Awaited<ReturnType<typeof OrganizationRepository.findTeamsInOrgIamNotPartOf>> | null;
containerClassName?: string;
} & ComponentProps<typeof Shell>;
export default function SettingsLayoutAppDirClient({
children,
currentOrg,
otherTeams,
...rest
}: SettingsLayoutProps) {
export default function SettingsLayoutAppDirClient({ children, ...rest }: SettingsLayoutProps) {
const pathname = usePathname();
const state = useState(false);
const [sideContainerOpen, setSideContainerOpen] = state;
@@ -773,8 +759,6 @@ export default function SettingsLayoutAppDirClient({
{...rest}
SidebarContainer={
<SidebarContainerElement
currentOrg={currentOrg}
otherTeams={otherTeams}
sideContainerOpen={sideContainerOpen}
setSideContainerOpen={setSideContainerOpen}
/>
@@ -798,8 +782,6 @@ const SidebarContainerElement = ({
sideContainerOpen,
bannersHeight,
setSideContainerOpen,
currentOrg,
otherTeams,
}: SidebarContainerElementProps) => {
const { t } = useLocale();
return (
@@ -815,8 +797,6 @@ const SidebarContainerElement = ({
<SettingsSidebarContainer
navigationIsOpenedOnMobile={sideContainerOpen}
bannersHeight={bannersHeight}
currentOrg={currentOrg}
otherTeams={otherTeams}
/>
</>
);
@@ -826,6 +806,4 @@ type SidebarContainerElementProps = {
sideContainerOpen: boolean;
bannersHeight?: number;
setSideContainerOpen: React.Dispatch<React.SetStateAction<boolean>>;
currentOrg: SettingsLayoutProps["currentOrg"];
otherTeams: SettingsLayoutProps["otherTeams"];
};
@@ -1,38 +1,24 @@
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import React from "react";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
import type { SettingsLayoutProps } from "./SettingsLayoutAppDirClient";
import SettingsLayoutAppDirClient from "./SettingsLayoutAppDirClient";
type SettingsLayoutAppDirProps = Omit<SettingsLayoutProps, "currentOrg" | "otherTeams">;
export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDirProps) {
export default async function SettingsLayoutAppDir(props: SettingsLayoutProps) {
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
const userId = session?.user?.id ?? -1;
const orgId = session?.user?.org?.id ?? -1;
let currentOrg = null;
let otherTeams = null;
try {
currentOrg = await OrganizationRepository.findCurrentOrg({ userId, orgId });
} catch (err) {}
try {
otherTeams = await OrganizationRepository.findTeamsInOrgIamNotPartOf({
userId,
parentId: orgId,
});
} catch (err) {}
const userId = session?.user?.id;
if (!userId) {
return redirect("/auth/login");
}
return (
<>
<SettingsLayoutAppDirClient {...props} currentOrg={currentOrg} otherTeams={otherTeams} />
<SettingsLayoutAppDirClient {...props} />
</>
);
}
@@ -1,8 +1,8 @@
import SkeletonLoaderTeamList from "@calcom/ee/teams/components/SkeletonloaderTeamList";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { Alert } from "@calcom/ui/components/alert";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import OtherTeamList from "./OtherTeamList";
@@ -305,6 +305,13 @@ export class OrganizationRepository {
},
},
},
select: {
parentId: true,
id: true,
name: true,
logoUrl: true,
slug: true,
},
});
return teamsInOrgIamNotPartOf;
@@ -44,6 +44,14 @@ const checkDelegationCredentialFeature = async ({
};
export const delegationCredentialRouter = router({
check: authedOrgAdminProcedure.query(async (opts) => {
return await checkDelegationCredentialFeature({
ctx: opts.ctx,
next: async () => ({
hasDelegationCredential: true,
}),
});
}),
list: authedOrgAdminProcedure.use(checkDelegationCredentialFeature).query(async (opts) => {
const handler = await import("./list.handler").then((mod) => mod.default);
return handler(opts);