perf: remove me fetching from teams by refactoring (#22444)

This commit is contained in:
Benny Joo
2025-07-15 23:23:34 +00:00
committed by GitHub
parent bfc6d6e1e9
commit e6da5c85e0
6 changed files with 39 additions and 24 deletions
@@ -1,13 +1,12 @@
import { createRouterCaller } from "app/_trpc/context";
import type { SearchParams } from "app/_types";
import type { Session } from "next-auth";
import { unstable_cache } from "next/cache";
import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
import { TeamsListing } from "@calcom/features/ee/teams/components/TeamsListing";
import { TeamRepository } from "@calcom/lib/server/repository/team";
import { TeamService } from "@calcom/lib/server/service/team";
import prisma from "@calcom/prisma";
import { meRouter } from "@calcom/trpc/server/routers/viewer/me/_router";
import { TRPCError } from "@trpc/server";
@@ -47,18 +46,24 @@ export const ServerTeamsListing = async ({
}
}
const meCaller = await createRouterCaller(meRouter);
const [user, teams] = await Promise.all([meCaller.get(), getCachedTeams(userId)]);
const teams = await getCachedTeams(userId);
const userProfile = session?.user?.profile;
const orgId = userProfile?.organizationId ?? session?.user.org?.id;
const orgRole =
session?.user?.org?.role ??
userProfile?.organization?.members.find((m: { userId: number }) => m.userId === userId)?.role;
const isOrgAdminOrOwner = checkAdminOrOwner(orgRole);
return {
Main: (
<TeamsListing
teams={teams}
user={user}
orgId={orgId ?? null}
isOrgAdmin={isOrgAdminOrOwner}
teamNameFromInvite={teamNameFromInvite ?? null}
errorMsgFromInvite={errorMsgFromInvite}
/>
),
CTA: !user.organizationId || user.organization.isOrgAdmin ? <TeamsCTA /> : null,
CTA: !orgId || isOrgAdminOrOwner ? <TeamsCTA /> : null,
};
};
@@ -8,7 +8,12 @@ import { buildLegacyRequest } from "@lib/buildLegacyCtx";
const OrgAdminOnlyLayout = async ({ children }: { children: React.ReactNode }) => {
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
const isOrgAdminOrOwner = checkAdminOrOwner(session?.user?.org?.role);
const userProfile = session?.user?.profile;
const userId = session?.user?.id;
const orgRole =
session?.user?.org?.role ??
userProfile?.organization?.members.find((m: { userId: number }) => m.userId === userId)?.role;
const isOrgAdminOrOwner = checkAdminOrOwner(orgRole);
if (!isOrgAdminOrOwner) {
return redirect("/settings/organizations/profile");
@@ -8,7 +8,12 @@ import { buildLegacyRequest } from "@lib/buildLegacyCtx";
const OrgAdminOnlyLayout = async ({ children }: { children: React.ReactNode }) => {
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
const isOrgAdminOrOwner = checkAdminOrOwner(session?.user?.org?.role);
const userProfile = session?.user?.profile;
const userId = session?.user?.id;
const orgRole =
session?.user?.org?.role ??
userProfile?.organization?.members.find((m: { userId: number }) => m.userId === userId)?.role;
const isOrgAdminOrOwner = checkAdminOrOwner(orgRole);
if (!isOrgAdminOrOwner) {
return redirect("/settings/organizations/profile");
@@ -17,7 +17,7 @@ import TeamListItem from "./TeamListItem";
interface Props {
teams: RouterOutputs["viewer"]["teams"]["list"];
user: RouterOutputs["viewer"]["me"]["get"];
orgId: number | null;
/**
* True for teams that are pending invite acceptance
*/
@@ -28,7 +28,7 @@ export default function TeamList(props: Props) {
const utils = trpc.useUtils();
const { t } = useLocale();
const { user } = props;
const { orgId } = props;
const [hideDropdown, setHideDropdown] = useState(false);
@@ -56,13 +56,11 @@ export default function TeamList(props: Props) {
deleteTeamMutation.mutate({ teamId });
}
if (!user) return null;
const isUserAlreadyInAnOrganization = user.profile.organization;
return (
<ul className="bg-default divide-subtle border-subtle mb-2 divide-y overflow-hidden rounded-md border">
{ORG_SELF_SERVE_ENABLED &&
!props.pending &&
!isUserAlreadyInAnOrganization &&
!orgId &&
props.teams.length >= ORG_MINIMUM_PUBLISHED_TEAMS_SELF_SERVE_HELPER_DIALOGUE &&
props.teams.map(
(team, i) =>
@@ -116,7 +114,7 @@ export default function TeamList(props: Props) {
<TeamListItem
key={team?.id as number}
team={team}
user={user}
orgId={orgId}
onActionSelect={(action: string) => selectAction(action, team?.id as number)}
isPending={deleteTeamMutation.isPending}
hideDropdown={hideDropdown}
@@ -36,7 +36,7 @@ import { TeamRole } from "./TeamPill";
interface Props {
team: RouterOutputs["viewer"]["teams"]["list"][number];
user: RouterOutputs["viewer"]["me"]["get"];
orgId: number | null;
key: number;
onActionSelect: (text: string) => void;
isPending?: boolean;
@@ -48,7 +48,7 @@ export default function TeamListItem(props: Props) {
const searchParams = useCompatSearchParams();
const { t } = useLocale();
const utils = trpc.useUtils();
const { team, user } = props;
const { team, orgId } = props;
const showDialog = searchParams?.get("inviteModal") === "true";
const [openMemberInvitationModal, setOpenMemberInvitationModal] = useState(showDialog);
@@ -63,7 +63,7 @@ export default function TeamListItem(props: Props) {
revalidateTeamsList();
utils.viewer.teams.hasTeamPlan.invalidate();
utils.viewer.teams.listInvites.invalidate();
const userOrganizationId = user?.profile?.organization?.id;
const userOrganizationId = orgId ?? undefined;
const isSubTeamOfDifferentOrg = team.parentId ? team.parentId != userOrganizationId : false;
const isDifferentOrg = team.isOrganization && team.id !== userOrganizationId;
// If the user team being accepted is a sub-team of different organization or the different organization itself then page must be reloaded to let the session change reflect reliably everywhere.
@@ -18,14 +18,16 @@ import { UpgradeTip } from "../../../tips";
import TeamList from "./TeamList";
type TeamsListingProps = {
user: RouterOutputs["viewer"]["me"]["get"];
orgId: number | null;
isOrgAdmin: boolean;
teams: RouterOutputs["viewer"]["teams"]["list"];
teamNameFromInvite: string | null;
errorMsgFromInvite: string | null;
};
export function TeamsListing({
user,
orgId,
isOrgAdmin,
teams: data,
teamNameFromInvite,
errorMsgFromInvite,
@@ -49,7 +51,7 @@ export function TeamsListing({
}
);
const isCreateTeamButtonDisabled = !!(user?.organizationId && !user?.organization?.isOrgAdmin);
const isCreateTeamButtonDisabled = !!(orgId && !isOrgAdmin);
const features = [
{
@@ -105,18 +107,18 @@ export function TeamsListing({
{organizationInvites.length > 0 && (
<div className="bg-subtle mb-6 rounded-md p-5">
<Label className="text-emphasis pb-2 font-semibold">{t("pending_organization_invites")}</Label>
<TeamList user={user} teams={organizationInvites} pending />
<TeamList orgId={orgId} teams={organizationInvites} pending />
</div>
)}
{teamInvites.length > 0 && (
<div className="bg-subtle mb-6 rounded-md p-5">
<Label className="text-emphasis pb-2 font-semibold">{t("pending_invites")}</Label>
<TeamList user={user} teams={teamInvites} pending />
<TeamList orgId={orgId} teams={teamInvites} pending />
</div>
)}
{teams.length > 0 && <TeamList user={user} teams={teams} />}
{teams.length > 0 && <TeamList orgId={orgId} teams={teams} />}
{teams.length === 0 && (
<UpgradeTip
@@ -126,7 +128,7 @@ export function TeamsListing({
features={features}
background="/tips/teams"
buttons={
!user?.organizationId || user?.organization.isOrgAdmin ? (
!orgId || isOrgAdmin ? (
<div className="space-y-2 rtl:space-x-reverse sm:space-x-2">
<ButtonGroup>
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>