perf: Move apps procedures off of loggedInViewer (#20112)

* perf: Slim down loggedInViewer tRPC router

* Fixed trpc client calls for new routes

* Moved bookingUnconfirmedCount

* Moved getUserTopBanners to me router

* Moved shouldVerifyEmail to me router

* Moved i18n from public to its own router

* fix ssrInit

* fix ssrInit usage

* fix type check

* better naming

* fix

* fix

* Fix types

* Removed used of importHandler

* perf: Move apps procedures off of loggedInViewer

* Moved 2 more apps-related procedures

---------

Co-authored-by: hbjORbj <sldisek783@gmail.com>
This commit is contained in:
Keith Williams
2025-03-17 17:18:19 +00:00
committed by GitHub
co-authored by hbjORbj
parent 3be9e1bd38
commit 30dce7bacd
53 changed files with 209 additions and 182 deletions
@@ -18,7 +18,7 @@ interface AdditionalCalendarSelectorProps {
const AdditionalCalendarSelector = ({ isPending }: AdditionalCalendarSelectorProps): JSX.Element | null => {
const { t } = useLocale();
const [data] = trpc.viewer.integrations.useSuspenseQuery({ variant: "calendar", onlyInstalled: true });
const [data] = trpc.viewer.apps.integrations.useSuspenseQuery({ variant: "calendar", onlyInstalled: true });
const options = data.items.map((item) => ({
label: item.name,
+3 -3
View File
@@ -87,7 +87,7 @@ export const AppPage = ({
if (data?.setupPending) return;
setIsLoading(false);
showToast(data?.message || t("app_successfully_installed"), "success");
await utils.viewer.appCredentialsByType.invalidate({ appType: type });
await utils.viewer.apps.appCredentialsByType.invalidate({ appType: type });
},
onError: (error) => {
if (error instanceof Error) showToast(error.message || t("app_could_not_be_installed"), "error");
@@ -143,7 +143,7 @@ export const AppPage = ({
*/
const [appInstalledForAllTargets, setAppInstalledForAllTargets] = useState(false);
const appDbQuery = trpc.viewer.appCredentialsByType.useQuery({ appType: type });
const appDbQuery = trpc.viewer.apps.appCredentialsByType.useQuery({ appType: type });
useEffect(
function refactorMeWithoutEffect() {
@@ -161,7 +161,7 @@ export const AppPage = ({
[appDbQuery.data, availableForTeams]
);
const dependencyData = trpc.viewer.appsRouter.queryForDependencies.useQuery(dependencies, {
const dependencyData = trpc.viewer.apps.queryForDependencies.useQuery(dependencies, {
enabled: !!dependencies,
});
@@ -31,7 +31,7 @@ type Props = {
function CalendarList(props: Props) {
const { t } = useLocale();
const query = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
const query = trpc.viewer.apps.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
return (
<QueryCell
@@ -80,7 +80,7 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
const utils = trpc.useUtils();
const onChanged = () =>
Promise.allSettled([
utils.viewer.integrations.invalidate(
utils.viewer.apps.integrations.invalidate(
{ variant: "calendar", onlyInstalled: true },
{
exact: true,
@@ -89,7 +89,10 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
utils.viewer.connectedCalendars.invalidate(),
]);
const query = trpc.viewer.connectedCalendars.useQuery();
const installedCalendars = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: true });
const installedCalendars = trpc.viewer.apps.integrations.useQuery({
variant: "calendar",
onlyInstalled: true,
});
const mutation = trpc.viewer.setDestinationCalendar.useMutation({
onSuccess: () => {
utils.viewer.connectedCalendars.invalidate();
@@ -11,7 +11,7 @@ export const InstallAppButtonChild = ({
...props
}: {
multiInstall?: boolean;
credentials?: RouterOutputs["viewer"]["appCredentialsByType"]["credentials"];
credentials?: RouterOutputs["viewer"]["apps"]["appCredentialsByType"]["credentials"];
paid?: AppFrontendPayload["paid"];
} & ButtonProps) => {
const { t } = useLocale();
@@ -19,7 +19,7 @@ import {
import type { inferRouterOutputs } from "@trpc/server";
type RouterOutput = inferRouterOutputs<AppRouter>;
type Credentials = RouterOutput["viewer"]["appCredentialsByType"]["credentials"];
type Credentials = RouterOutput["viewer"]["apps"]["appCredentialsByType"]["credentials"];
interface Props {
credentials: Credentials;
@@ -48,7 +48,7 @@ export function MultiDisconnectIntegration({ credentials, onSuccess }: Props) {
},
async onSettled() {
await utils.viewer.connectedCalendars.invalidate();
await utils.viewer.integrations.invalidate();
await utils.viewer.apps.integrations.invalidate();
},
});
@@ -25,7 +25,7 @@ const AppConnectionItem = (props: IAppConnectionItem) => {
const { title, logo, type, installed, isDefault, defaultInstall, slug } = props;
const { t } = useLocale();
const utils = trpc.useUtils();
const setDefaultConferencingApp = trpc.viewer.appsRouter.setDefaultConferencingApp.useMutation({
const setDefaultConferencingApp = trpc.viewer.apps.setDefaultConferencingApp.useMutation({
onSuccess: async () => {
await utils.viewer.me.invalidate();
},
@@ -54,7 +54,7 @@ const AppConnectionItem = (props: IAppConnectionItem) => {
setDefaultConferencingApp.mutate({ slug });
}
setInstalling(false);
utils.viewer.integrations.invalidate();
utils.viewer.apps.integrations.invalidate();
showToast(t("app_successfully_installed"), "success");
},
onError: (error) => {
@@ -19,7 +19,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
eventTypeId: null,
});
const { t } = useLocale();
const queryIntegrations = trpc.viewer.integrations.useQuery({
const queryIntegrations = trpc.viewer.apps.integrations.useQuery({
variant: "calendar",
onlyInstalled: false,
sortByMostPopular: true,
@@ -14,7 +14,7 @@ interface ConnectedAppStepProps {
const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
const { nextStep } = props;
const { data: queryConnectedVideoApps, isPending } = trpc.viewer.integrations.useQuery({
const { data: queryConnectedVideoApps, isPending } = trpc.viewer.apps.integrations.useQuery({
variant: "conferencing",
onlyInstalled: false,
@@ -38,16 +38,16 @@ const IntegrationsContainer = ({
}: IntegrationsContainerProps): JSX.Element => {
const { t } = useLocale();
const utils = trpc.useUtils();
const query = trpc.viewer.integrations.useQuery({
const query = trpc.viewer.apps.integrations.useQuery({
variant,
exclude,
onlyInstalled: true,
includeTeamInstalledApps: true,
});
const { data: defaultConferencingApp } = trpc.viewer.getUsersDefaultConferencingApp.useQuery();
const { data: defaultConferencingApp } = trpc.viewer.apps.getUsersDefaultConferencingApp.useQuery();
const updateDefaultAppMutation = trpc.viewer.updateUserDefaultConferencingApp.useMutation();
const updateDefaultAppMutation = trpc.viewer.apps.updateUserDefaultConferencingApp.useMutation();
const updateLocationsMutation = trpc.viewer.eventTypes.bulkUpdateToDefaultLocation.useMutation();
@@ -65,7 +65,7 @@ const IntegrationsContainer = ({
{
onSuccess: () => {
showToast("Default app updated successfully", "success");
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
onSuccessCallback();
},
onError: (error) => {
@@ -83,7 +83,7 @@ const IntegrationsContainer = ({
},
{
onSuccess: () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
callback();
},
}
@@ -91,11 +91,11 @@ const IntegrationsContainer = ({
};
const handleConnectDisconnectIntegrationMenuToggle = () => {
utils.viewer.integrations.invalidate();
utils.viewer.apps.integrations.invalidate();
};
const handleBulkEditDialogToggle = () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
};
// TODO: Refactor and reuse getAppCategories?
@@ -218,7 +218,7 @@ export default function InstalledApps({ category }: PageProps) {
onSuccess: () => {
showToast(t("app_removed_successfully"), "success");
callback();
utils.viewer.integrations.invalidate();
utils.viewer.apps.integrations.invalidate();
utils.viewer.connectedCalendars.invalidate();
},
onError: () => {
@@ -70,7 +70,7 @@ export const AvailabilitySettingsWebWrapper = ({
};
const handleBulkEditDialogToggle = () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
};
const isDefaultSchedule = me.data?.defaultScheduleId === scheduleId;
@@ -101,7 +101,7 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
};
const handleBulkEditDialogToggle = () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
};
const duplicateMutation = trpc.viewer.availability.schedule.duplicate.useMutation({
+3 -1
View File
@@ -24,7 +24,9 @@ export default function AppCard({
hideSettingsIcon = false,
hideAppCardOptions = false,
}: {
app: RouterOutputs["viewer"]["integrations"]["items"][number] & { credentialOwner?: CredentialOwner };
app: RouterOutputs["viewer"]["apps"]["integrations"]["items"][number] & {
credentialOwner?: CredentialOwner;
};
description?: React.ReactNode;
switchChecked?: boolean;
switchOnClick?: (e: boolean) => void;
@@ -10,7 +10,7 @@ import { ErrorBoundary } from "@calcom/ui";
import type { EventTypeAppCardComponentProps, CredentialOwner } from "../types";
import { DynamicComponent } from "./DynamicComponent";
export type EventTypeApp = RouterOutputs["viewer"]["integrations"]["items"][number] & {
export type EventTypeApp = RouterOutputs["viewer"]["apps"]["integrations"]["items"][number] & {
credentialOwner?: CredentialOwner;
};
@@ -29,9 +29,8 @@ export default function OmniInstallAppButton({
const mutation = useAddAppMutation(null, {
returnTo,
onSuccess: (data) => {
//TODO: viewer.appById might be replaced with viewer.apps so that a single query needs to be invalidated.
utils.viewer.appById.invalidate({ appId });
utils.viewer.integrations.invalidate({
utils.viewer.apps.appById.invalidate({ appId });
utils.viewer.apps.integrations.invalidate({
extendsFeature: "EventType",
...(teamId && { teamId }),
});
@@ -26,7 +26,9 @@ const mockProps = {
name: "TestApp",
slug: "testapp",
credentialOwner: {},
} as RouterOutputs["viewer"]["integrations"]["items"][number] & { credentialOwner?: CredentialOwner },
} as RouterOutputs["viewer"]["apps"]["integrations"]["items"][number] & {
credentialOwner?: CredentialOwner;
},
eventType: {},
getAppData: getAppDataMock,
setAppData: setAppDataMock,
@@ -73,11 +73,11 @@ function AlbySetupCallback() {
function AlbySetupPage(props: IAlbySetupProps) {
const router = useRouter();
const { t } = useLocale();
const integrations = trpc.viewer.integrations.useQuery({ variant: "payment", appId: "alby" });
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "alby" });
const [albyPaymentAppCredentials] = integrations.data?.items || [];
const [credentialId] = albyPaymentAppCredentials?.userCredentialIds || [-1];
const showContent = !!integrations.data && integrations.isSuccess && !!credentialId;
const saveKeysMutation = trpc.viewer.appsRouter.updateAppCredentials.useMutation({
const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({
onSuccess: () => {
showToast(t("keys_have_been_saved"), "success");
router.push("/event-types");
+1 -1
View File
@@ -109,7 +109,7 @@ export const AppDependencyComponent = ({
dependencyData,
}: {
appName: string;
dependencyData: RouterOutputs["viewer"]["appsRouter"]["queryForDependencies"];
dependencyData: RouterOutputs["viewer"]["apps"]["queryForDependencies"];
}) => {
const { t } = useLocale();
@@ -100,12 +100,12 @@ function HitPaySetupPage(props: IHitPaySetupProps) {
}),
});
const integrations = trpc.viewer.integrations.useQuery({ variant: "payment", appId: "hitpay" });
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "hitpay" });
const [HitPayPaymentAppCredentials] = integrations.data?.items || [];
const [credentialId] = HitPayPaymentAppCredentials?.userCredentialIds || [-1];
const showContent = !!integrations.data && integrations.isSuccess && !!credentialId;
const saveKeysMutation = trpc.viewer.appsRouter.updateAppCredentials.useMutation({
const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({
onSuccess: () => {
showToast(t("keys_have_been_saved"), "success");
router.push("/event-types");
@@ -18,7 +18,7 @@ export default function MakeSetup({ inviteLink }: InferGetServerSidePropsType<ty
const { t } = useLocale();
const utils = trpc.useUtils();
const integrations = trpc.viewer.integrations.useQuery({ variant: "automation" });
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "automation" });
const oldApiKey = trpc.viewer.apiKeys.findKeyOfType.useQuery({ appId: MAKE });
const teamsList = trpc.viewer.teams.listOwnedTeams.useQuery(undefined, {
refetchOnWindowFocus: false,
@@ -13,11 +13,11 @@ export default function PayPalSetup() {
const [newSecretKey, setNewSecretKey] = useState("");
const router = useRouter();
const { t } = useLocale();
const integrations = trpc.viewer.integrations.useQuery({ variant: "payment", appId: "paypal" });
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "paypal" });
const [paypalPaymentAppCredentials] = integrations.data?.items || [];
const [credentialId] = paypalPaymentAppCredentials?.userCredentialIds || [-1];
const showContent = !!integrations.data && integrations.isSuccess && !!credentialId;
const saveKeysMutation = trpc.viewer.appsRouter.updateAppCredentials.useMutation({
const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({
onSuccess: () => {
showToast(t("keys_have_been_saved"), "success");
router.push("/event-types");
+1 -1
View File
@@ -22,7 +22,7 @@ export type CredentialOwner = {
readOnly?: boolean;
};
export type EventTypeAppCardApp = RouterOutputs["viewer"]["integrations"]["items"][number] & {
export type EventTypeAppCardApp = RouterOutputs["viewer"]["apps"]["integrations"]["items"][number] & {
credentialOwner?: CredentialOwner;
credentialIds?: number[];
};
@@ -13,7 +13,7 @@ interface IWipeMyCalActionButtonProps {
const WipeMyCalActionButton = (props: IWipeMyCalActionButtonProps) => {
const { bookingsEmpty, bookingStatus } = props;
const [openDialog, setOpenDialog] = useState(false);
const { isSuccess, isPending, data } = trpc.viewer.integrations.useQuery({
const { isSuccess, isPending, data } = trpc.viewer.apps.integrations.useQuery({
variant: "other",
onlyInstalled: undefined,
});
@@ -18,7 +18,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
const [newApiKeys, setNewApiKeys] = useState<Record<string, string>>({});
const { t } = useLocale();
const utils = trpc.useUtils();
const integrations = trpc.viewer.integrations.useQuery({ variant: "automation" });
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "automation" });
const oldApiKey = trpc.viewer.apiKeys.findKeyOfType.useQuery({ appId: ZAPIER });
const teamsList = trpc.viewer.teams.listOwnedTeams.useQuery(undefined, {
refetchOnWindowFocus: false,
+6 -6
View File
@@ -36,7 +36,7 @@ import {
} from "@calcom/ui";
import cs from "@calcom/ui/classNames";
type App = RouterOutputs["viewer"]["appsRouter"]["listLocal"][number];
type App = RouterOutputs["viewer"]["apps"]["listLocal"][number];
const IntegrationContainer = ({
app,
@@ -66,9 +66,9 @@ const IntegrationContainer = ({
}
};
const enableAppMutation = trpc.viewer.appsRouter.toggle.useMutation({
const enableAppMutation = trpc.viewer.apps.toggle.useMutation({
onSuccess: (enabled) => {
utils.viewer.appsRouter.listLocal.invalidate({ category });
utils.viewer.apps.listLocal.invalidate({ category });
setDisableDialog(false);
showToast(
enabled ? t("app_is_enabled", { appName: app.name }) : t("app_is_disabled", { appName: app.name }),
@@ -197,10 +197,10 @@ const EditKeysModal: FC<{
resolver: zodResolver(appKeySchema),
});
const saveKeysMutation = trpc.viewer.appsRouter.saveKeys.useMutation({
const saveKeysMutation = trpc.viewer.apps.saveKeys.useMutation({
onSuccess: () => {
showToast(fromEnabled ? t("app_is_enabled", { appName }) : t("keys_have_been_saved"), "success");
utils.viewer.appsRouter.listLocal.invalidate();
utils.viewer.apps.listLocal.invalidate();
handleModelClose();
},
onError: (error) => {
@@ -271,7 +271,7 @@ const AdminAppsListContainer = () => {
const { t } = useLocale();
const category = searchParams?.get("category") || AppCategories.calendar;
const { data: apps, isPending } = trpc.viewer.appsRouter.listLocal.useQuery(
const { data: apps, isPending } = trpc.viewer.apps.listLocal.useQuery(
{ category },
{ enabled: searchParams !== null }
);
@@ -33,10 +33,10 @@ export type HandleDisconnect = (credentialId: number, app: App["slug"], teamId?:
interface AppListProps {
variant?: AppCategories;
data: RouterOutputs["viewer"]["integrations"];
data: RouterOutputs["viewer"]["apps"]["integrations"];
handleDisconnect: HandleDisconnect;
listClassName?: string;
defaultConferencingApp: RouterOutputs["viewer"]["getUsersDefaultConferencingApp"];
defaultConferencingApp: RouterOutputs["viewer"]["apps"]["getUsersDefaultConferencingApp"];
handleUpdateUserDefaultConferencingApp: (params: UpdateUsersDefaultConferencingAppParams) => void;
handleBulkUpdateDefaultLocation: (params: BulkUpdatParams) => void;
isBulkUpdateDefaultLocationPending: boolean;
@@ -72,7 +72,7 @@ export const AppList = ({
const ChildAppCard = ({
item,
}: {
item: RouterOutputs["viewer"]["integrations"]["items"][number] & {
item: RouterOutputs["viewer"]["apps"]["integrations"]["items"][number] & {
credentialOwner?: CredentialOwner;
};
}) => {
@@ -34,7 +34,7 @@ export default function DisconnectIntegration(props: {
},
async onSettled() {
await utils.viewer.connectedCalendars.invalidate();
await utils.viewer.integrations.invalidate();
await utils.viewer.apps.integrations.invalidate();
},
});
@@ -80,7 +80,7 @@ const CalendarSwitch = (props: ICalendarSwitchProps) => {
}
},
async onSettled() {
await utils.viewer.integrations.invalidate();
await utils.viewer.apps.integrations.invalidate();
await utils.viewer.connectedCalendars.invalidate();
},
onError() {
@@ -41,7 +41,7 @@ export function GoogleWorkspaceInviteButton(
const teamId = Number(params.id);
const [googleWorkspaceLoading, setGoogleWorkspaceLoading] = useState(false);
const { data: credential } = trpc.viewer.googleWorkspace.checkForGWorkspace.useQuery();
const { data: hasGcalInstalled } = trpc.viewer.appsRouter.checkGlobalKeys.useQuery({
const { data: hasGcalInstalled } = trpc.viewer.apps.checkGlobalKeys.useQuery({
slug: "google-calendar",
});
const mutation = trpc.viewer.googleWorkspace.getUsersFromGWorkspace.useMutation({
@@ -17,7 +17,7 @@ export type EventType = Pick<EventTypeSetupProps, "eventType">["eventType"] &
export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
const { t } = useLocale();
const { data: eventTypeApps, isPending } = trpc.viewer.integrations.useQuery({
const { data: eventTypeApps, isPending } = trpc.viewer.apps.integrations.useQuery({
extendsFeature: "EventType",
teamId: eventType.team?.id || eventType.parent?.teamId,
});
@@ -270,7 +270,7 @@ const InstantMeetingWebhooks = ({ eventType }: { eventType: EventTypeSetup }) =>
eventTypeId: eventType.id,
eventTriggers: [WebhookTriggerEvents.INSTANT_MEETING],
});
const { data: installedApps, isPending } = trpc.viewer.integrations.useQuery({
const { data: installedApps, isPending } = trpc.viewer.apps.integrations.useQuery({
variant: "other",
onlyInstalled: true,
});
@@ -23,7 +23,7 @@ export const EventWebhooksTab = ({ eventType }: Pick<EventTypeSetupProps, "event
const { data: webhooks } = trpc.viewer.webhook.list.useQuery({ eventTypeId: eventType.id });
const { data: installedApps, isLoading } = trpc.viewer.integrations.useQuery({
const { data: installedApps, isLoading } = trpc.viewer.apps.integrations.useQuery({
variant: "other",
onlyInstalled: true,
});
+1 -1
View File
@@ -23,7 +23,7 @@ export type AvailabilityOption = {
};
export type EventTypeSetupProps = RouterOutputs["viewer"]["eventTypes"]["get"];
export type EventTypeSetup = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"];
export type EventTypeApps = RouterOutputs["viewer"]["integrations"];
export type EventTypeApps = RouterOutputs["viewer"]["apps"]["integrations"];
export type Host = {
isFixed: boolean;
userId: number;
@@ -27,7 +27,7 @@ export function EditWebhookView({ webhook }: { webhook?: WebhookProps }) {
const { t } = useLocale();
const utils = trpc.useUtils();
const router = useRouter();
const { data: installedApps, isPending } = trpc.viewer.integrations.useQuery(
const { data: installedApps, isPending } = trpc.viewer.apps.integrations.useQuery(
{ variant: "other", onlyInstalled: true },
{
suspense: true,
@@ -22,7 +22,7 @@ export const NewWebhookView = () => {
const teamId = searchParams?.get("teamId") ? Number(searchParams.get("teamId")) : undefined;
const platform = searchParams?.get("platform") ? Boolean(searchParams.get("platform")) : false;
const { data: installedApps, isPending } = trpc.viewer.integrations.useQuery(
const { data: installedApps, isPending } = trpc.viewer.apps.integrations.useQuery(
{ variant: "other", onlyInstalled: true },
{
suspense: true,
+32 -3
View File
@@ -1,3 +1,5 @@
import type { Prisma } from "@prisma/client";
import appStore from "@calcom/app-store";
import type { TDependencyData } from "@calcom/app-store/_appRegistry";
import type { CredentialOwner } from "@calcom/app-store/types";
@@ -8,14 +10,41 @@ import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
import type { PrismaClient } from "@calcom/prisma";
import type { User } from "@calcom/prisma/client";
import { MembershipRole } from "@calcom/prisma/enums";
import type { AppCategories } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import type { TeamQuery } from "@calcom/trpc/server/routers/loggedInViewer/integrations.handler";
import type { TIntegrationsInputSchema } from "@calcom/trpc/server/routers/loggedInViewer/integrations.schema";
import type { PaymentApp } from "@calcom/types/PaymentService";
import { buildNonDelegationCredentials } from "./delegationCredential/clientAndServer";
export type ConnectedApps = Awaited<ReturnType<typeof getConnectedApps>>;
type InputSchema = {
variant?: string | undefined;
exclude?: Array<string> | null;
onlyInstalled?: boolean | undefined;
includeTeamInstalledApps?: boolean | null;
extendsFeature?: "EventType" | null;
teamId?: number | null;
sortByMostPopular?: boolean | null;
sortByInstalledFirst?: boolean | null;
categories?: Array<AppCategories> | null;
appId?: string | null;
};
export type TeamQuery = Prisma.TeamGetPayload<{
select: {
id: true;
credentials: {
select: typeof import("@calcom/prisma/selects/credential").credentialForCalendarServiceSelect;
};
name: true;
logoUrl: true;
members: {
select: {
role: true;
};
};
};
}>;
export async function getConnectedApps({
user,
@@ -24,7 +53,7 @@ export async function getConnectedApps({
}: {
user: Pick<User, "id" | "name" | "avatarUrl" | "email"> & { avatar?: string };
prisma: PrismaClient;
input: TIntegrationsInputSchema;
input: InputSchema;
}) {
const {
variant,
+1 -1
View File
@@ -5,7 +5,7 @@ import { trpc } from "@calcom/trpc/react";
export default function useApp(appId: string) {
const { status } = useSession();
return trpc.viewer.appById.useQuery(
return trpc.viewer.apps.appById.useQuery(
{ appId },
{
enabled: status === "authenticated",
@@ -44,26 +44,26 @@ const InstalledConferencingApps = ({
const { t } = useLocale();
const utils = trpc.useUtils();
const { data: defaultConferencingApp } = trpc.viewer.getUsersDefaultConferencingApp.useQuery();
const { data: defaultConferencingApp } = trpc.viewer.apps.getUsersDefaultConferencingApp.useQuery();
const updateDefaultAppMutation = trpc.viewer.updateUserDefaultConferencingApp.useMutation();
const updateDefaultAppMutation = trpc.viewer.apps.updateUserDefaultConferencingApp.useMutation();
const updateLocationsMutation = trpc.viewer.eventTypes.bulkUpdateToDefaultLocation.useMutation();
const { data: eventTypesQueryData, isFetching: isEventTypesFetching } =
trpc.viewer.eventTypes.bulkEventFetch.useQuery();
const [result] = trpc.viewer.integrations.useSuspenseQuery({
const [result] = trpc.viewer.apps.integrations.useSuspenseQuery({
variant: "conferencing",
onlyInstalled: true,
});
const handleConnectDisconnectIntegrationMenuToggle = () => {
utils.viewer.integrations.invalidate();
utils.viewer.apps.integrations.invalidate();
};
const handleBulkEditDialogToggle = () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
};
const handleUpdateUserDefaultConferencingApp = ({
@@ -77,7 +77,7 @@ const InstalledConferencingApps = ({
{
onSuccess: () => {
showToast("Default app updated successfully", "success");
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
onSuccessCallback();
},
onError: (error) => {
@@ -95,7 +95,7 @@ const InstalledConferencingApps = ({
},
{
onSuccess: () => {
utils.viewer.getUsersDefaultConferencingApp.invalidate();
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
callback();
},
}
@@ -189,7 +189,7 @@ export const ConferencingAppsViewWebWrapper = ({
onSuccess: () => {
showToast(t("app_removed_successfully"), "success");
callback();
utils.viewer.integrations.invalidate();
utils.viewer.apps.integrations.invalidate();
utils.viewer.connectedCalendars.invalidate();
},
onError: () => {
@@ -109,7 +109,7 @@ const EventTypeWeb = ({ id, ...rest }: EventTypeSetupProps & { id: number }) =>
const [pendingRoute, setPendingRoute] = useState("");
const { eventType, locationOptions, team, teamMembers, destinationCalendar } = rest;
const [slugExistsChildrenDialogOpen, setSlugExistsChildrenDialogOpen] = useState<ChildrenEventType[]>([]);
const { data: eventTypeApps } = trpc.viewer.integrations.useQuery({
const { data: eventTypeApps } = trpc.viewer.apps.integrations.useQuery({
extendsFeature: "EventType",
teamId: eventType.team?.id || eventType.parent?.teamId,
onlyInstalled: true,
+16 -2
View File
@@ -15,7 +15,6 @@ import { getTranslation } from "@calcom/lib/server/i18n";
import { MembershipRole } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import { paymentDataSelect } from "@calcom/prisma/selects/payment";
import type { TeamQuery } from "@calcom/trpc/server/routers/loggedInViewer/integrations.handler";
import { createNewUsersConnectToOrgIfExists } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/utils";
export { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
@@ -78,7 +77,22 @@ export { roundRobinManualReassignment } from "@calcom/features/ee/round-robin/ro
export { ErrorCode } from "@calcom/lib/errorCodes";
export { validateCustomEventName } from "@calcom/lib/event";
export type { TeamQuery };
export type TeamQuery = Prisma.TeamGetPayload<{
select: {
id: true;
credentials: {
select: typeof import("@calcom/prisma/selects/credential").credentialForCalendarServiceSelect;
};
name: true;
logoUrl: true;
members: {
select: {
role: true;
};
};
};
}>;
export { credentialForCalendarServiceSelect };
export { MembershipRole };
-1
View File
@@ -28,7 +28,6 @@ export const ENDPOINTS = [
"viewer",
"webhook",
"workflows",
"appsRouter",
"googleWorkspace",
"oAuth",
"attributes",
@@ -2,15 +2,12 @@ import authedProcedure from "../../procedures/authedProcedure";
import { importHandler, router } from "../../trpc";
import { ZAddNotificationsSubscriptionInputSchema } from "./addNotificationsSubscription.schema";
import { ZAddSecondaryEmailInputSchema } from "./addSecondaryEmail.schema";
import { ZAppByIdInputSchema } from "./appById.schema";
import { ZAppCredentialsByTypeInputSchema } from "./appCredentialsByType.schema";
import { ZConnectAndJoinInputSchema } from "./connectAndJoin.schema";
import { ZConnectedCalendarsInputSchema } from "./connectedCalendars.schema";
import { ZDeleteCredentialInputSchema } from "./deleteCredential.schema";
import { ZEventTypeOrderInputSchema } from "./eventTypeOrder.schema";
import { ZGetCalVideoRecordingsInputSchema } from "./getCalVideoRecordings.schema";
import { ZGetDownloadLinkOfCalVideoRecordingsInputSchema } from "./getDownloadLinkOfCalVideoRecordings.schema";
import { ZIntegrationsInputSchema } from "./integrations.schema";
import { ZLocationOptionsInputSchema } from "./locationOptions.schema";
import { ZNoShowInputSchema } from "./markNoShow.schema";
import { ZOutOfOfficeInputSchema } from "./outOfOfficeCreateOrUpdate.schema";
@@ -22,7 +19,6 @@ import { ZRoutingFormOrderInputSchema } from "./routingFormOrder.schema";
import { ZSetDestinationCalendarInputSchema } from "./setDestinationCalendar.schema";
import { ZSubmitFeedbackInputSchema } from "./submitFeedback.schema";
import { ZUpdateProfileInputSchema } from "./updateProfile.schema";
import { ZUpdateUserDefaultConferencingAppInputSchema } from "./updateUserDefaultConferencingApp.schema";
import { ZWorkflowOrderInputSchema } from "./workflowOrder.schema";
const NAMESPACE = "loggedInViewer";
@@ -32,9 +28,6 @@ const namespaced = (s: string) => `${NAMESPACE}.${s}`;
type AppsRouterHandlerCache = {
connectedCalendars?: typeof import("./connectedCalendars.handler").connectedCalendarsHandler;
setDestinationCalendar?: typeof import("./setDestinationCalendar.handler").setDestinationCalendarHandler;
integrations?: typeof import("./integrations.handler").integrationsHandler;
appById?: typeof import("./appById.handler").appByIdHandler;
appCredentialsByType?: typeof import("./appCredentialsByType.handler").appCredentialsByTypeHandler;
stripeCustomer?: typeof import("./stripeCustomer.handler").stripeCustomerHandler;
updateProfile?: typeof import("./updateProfile.handler").updateProfileHandler;
eventTypeOrder?: typeof import("./eventTypeOrder.handler").eventTypeOrderHandler;
@@ -45,8 +38,6 @@ type AppsRouterHandlerCache = {
deleteCredential?: typeof import("./deleteCredential.handler").deleteCredentialHandler;
getCalVideoRecordings?: typeof import("./getCalVideoRecordings.handler").getCalVideoRecordingsHandler;
getDownloadLinkOfCalVideoRecordings?: typeof import("./getDownloadLinkOfCalVideoRecordings.handler").getDownloadLinkOfCalVideoRecordingsHandler;
getUsersDefaultConferencingApp?: typeof import("./getUsersDefaultConferencingApp.handler").getUsersDefaultConferencingAppHandler;
updateUserDefaultConferencingApp?: typeof import("./updateUserDefaultConferencingApp.handler").updateUserDefaultConferencingAppHandler;
teamsAndUserProfilesQuery?: typeof import("./teamsAndUserProfilesQuery.handler").teamsAndUserProfilesQuery;
connectAndJoin?: typeof import("./connectAndJoin.handler").Handler;
outOfOfficeCreateOrUpdate?: typeof import("./outOfOfficeCreateOrUpdate.handler").outOfOfficeCreateOrUpdate;
@@ -95,49 +86,6 @@ export const loggedInViewerRouter = router({
return UNSTABLE_HANDLER_CACHE.setDestinationCalendar({ ctx, input });
}),
integrations: authedProcedure.input(ZIntegrationsInputSchema).query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.integrations) {
UNSTABLE_HANDLER_CACHE.integrations = (await import("./integrations.handler")).integrationsHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.integrations) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.integrations({ ctx, input });
}),
appById: authedProcedure.input(ZAppByIdInputSchema).query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.appById) {
UNSTABLE_HANDLER_CACHE.appById = (await import("./appById.handler")).appByIdHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.appById) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.appById({ ctx, input });
}),
appCredentialsByType: authedProcedure
.input(ZAppCredentialsByTypeInputSchema)
.query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.appCredentialsByType) {
UNSTABLE_HANDLER_CACHE.appCredentialsByType = (
await import("./appCredentialsByType.handler")
).appCredentialsByTypeHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.appCredentialsByType) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.appCredentialsByType({ ctx, input });
}),
stripeCustomer: authedProcedure.query(async ({ ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.stripeCustomer) {
UNSTABLE_HANDLER_CACHE.stripeCustomer = (
@@ -296,38 +244,6 @@ export const loggedInViewerRouter = router({
return UNSTABLE_HANDLER_CACHE.getDownloadLinkOfCalVideoRecordings({ ctx, input });
}),
getUsersDefaultConferencingApp: authedProcedure.query(async ({ ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp) {
UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp = (
await import("./getUsersDefaultConferencingApp.handler")
).getUsersDefaultConferencingAppHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp({ ctx });
}),
updateUserDefaultConferencingApp: authedProcedure
.input(ZUpdateUserDefaultConferencingAppInputSchema)
.mutation(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp) {
UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp = (
await import("./updateUserDefaultConferencingApp.handler")
).updateUserDefaultConferencingAppHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp({ ctx, input });
}),
teamsAndUserProfilesQuery,
connectAndJoin: authedProcedure.input(ZConnectAndJoinInputSchema).mutation(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.connectAndJoin) {
@@ -37,6 +37,7 @@ export const viewerRouter = mergeRouters(
loggedInViewerRouter,
router({
apps: appsRouter,
me: meRouter,
public: publicViewerRouter,
auth: authRouter,
@@ -62,7 +63,6 @@ export const viewerRouter = mergeRouters(
appRoutingForms: app_RoutingForms,
appBasecamp3: app_Basecamp3,
features: featureFlagRouter,
appsRouter,
users: userAdminRouter,
oAuth: oAuthRouter,
googleWorkspace: googleWorkspaceRouter,
@@ -1,14 +1,22 @@
import authedProcedure, { authedAdminProcedure } from "../../../procedures/authedProcedure";
import { router } from "../../../trpc";
import { ZAppByIdInputSchema } from "./appById.schema";
import { ZAppCredentialsByTypeInputSchema } from "./appCredentialsByType.schema";
import { checkGlobalKeysSchema } from "./checkGlobalKeys.schema";
import { ZIntegrationsInputSchema } from "./integrations.schema";
import { ZListLocalInputSchema } from "./listLocal.schema";
import { ZQueryForDependenciesInputSchema } from "./queryForDependencies.schema";
import { ZSaveKeysInputSchema } from "./saveKeys.schema";
import { ZSetDefaultConferencingAppSchema } from "./setDefaultConferencingApp.schema";
import { ZToggleInputSchema } from "./toggle.schema";
import { ZUpdateAppCredentialsInputSchema } from "./updateAppCredentials.schema";
import { ZUpdateUserDefaultConferencingAppInputSchema } from "./updateUserDefaultConferencingApp.schema";
type AppsRouterHandlerCache = {
appById?: typeof import("./appById.handler").appByIdHandler;
appCredentialsByType?: typeof import("./appCredentialsByType.handler").appCredentialsByTypeHandler;
getUsersDefaultConferencingApp?: typeof import("./getUsersDefaultConferencingApp.handler").getUsersDefaultConferencingAppHandler;
integrations?: typeof import("./integrations.handler").integrationsHandler;
listLocal?: typeof import("./listLocal.handler").listLocalHandler;
toggle?: typeof import("./toggle.handler").toggleHandler;
saveKeys?: typeof import("./saveKeys.handler").saveKeysHandler;
@@ -17,11 +25,67 @@ type AppsRouterHandlerCache = {
queryForDependencies?: typeof import("./queryForDependencies.handler").queryForDependenciesHandler;
checkGlobalKeys?: typeof import("./checkGlobalKeys.handler").checkForGlobalKeysHandler;
setDefaultConferencingApp?: typeof import("./setDefaultConferencingApp.handler").setDefaultConferencingAppHandler;
updateUserDefaultConferencingApp?: typeof import("./updateUserDefaultConferencingApp.handler").updateUserDefaultConferencingAppHandler;
};
const UNSTABLE_HANDLER_CACHE: AppsRouterHandlerCache = {};
export const appsRouter = router({
appById: authedProcedure.input(ZAppByIdInputSchema).query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.appById) {
UNSTABLE_HANDLER_CACHE.appById = (await import("./appById.handler")).appByIdHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.appById) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.appById({ ctx, input });
}),
appCredentialsByType: authedProcedure
.input(ZAppCredentialsByTypeInputSchema)
.query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.appCredentialsByType) {
UNSTABLE_HANDLER_CACHE.appCredentialsByType = (
await import("./appCredentialsByType.handler")
).appCredentialsByTypeHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.appCredentialsByType) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.appCredentialsByType({ ctx, input });
}),
getUsersDefaultConferencingApp: authedProcedure.query(async ({ ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp) {
UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp = (
await import("./getUsersDefaultConferencingApp.handler")
).getUsersDefaultConferencingAppHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.getUsersDefaultConferencingApp({ ctx });
}),
integrations: authedProcedure.input(ZIntegrationsInputSchema).query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.integrations) {
UNSTABLE_HANDLER_CACHE.integrations = (await import("./integrations.handler")).integrationsHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.integrations) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.integrations({ ctx, input });
}),
listLocal: authedAdminProcedure.input(ZListLocalInputSchema).query(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.listLocal) {
UNSTABLE_HANDLER_CACHE.listLocal = await import("./listLocal.handler").then(
@@ -164,4 +228,20 @@ export const appsRouter = router({
input,
});
}),
updateUserDefaultConferencingApp: authedProcedure
.input(ZUpdateUserDefaultConferencingAppInputSchema)
.mutation(async ({ ctx, input }) => {
if (!UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp) {
UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp = (
await import("./updateUserDefaultConferencingApp.handler")
).updateUserDefaultConferencingAppHandler;
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.updateUserDefaultConferencingApp({ ctx, input });
}),
});
@@ -1,9 +1,9 @@
import getApps from "@calcom/app-store/utils";
import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../trpc";
import type { TAppByIdInputSchema } from "./appById.schema";
type AppByIdOptions = {
@@ -1,8 +1,8 @@
import { getAllDelegationCredentialsForUserByAppType } from "@calcom/lib/delegationCredential/server";
import { UserRepository } from "@calcom/lib/server/repository/user";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import type { TrpcSessionUser } from "../../../trpc";
import type { TAppCredentialsByTypeInputSchema } from "./appCredentialsByType.schema";
type AppCredentialsByTypeOptions = {
@@ -1,5 +1,6 @@
import { userMetadata } from "@calcom/prisma/zod-utils";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import type { TrpcSessionUser } from "../../../trpc";
type GetUsersDefaultConferencingAppOptions = {
ctx: {
@@ -1,5 +1,3 @@
import type { Prisma } from "@prisma/client";
import { getConnectedApps } from "@calcom/lib/getConnectedApps";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
@@ -13,22 +11,6 @@ type IntegrationsOptions = {
input: TIntegrationsInputSchema;
};
export type TeamQuery = Prisma.TeamGetPayload<{
select: {
id: true;
credentials: {
select: typeof import("@calcom/prisma/selects/credential").credentialForCalendarServiceSelect;
};
name: true;
logoUrl: true;
members: {
select: {
role: true;
};
};
};
}>;
export const integrationsHandler = async ({ ctx, input }: IntegrationsOptions) => {
const user = ctx.user;
return getConnectedApps({ user, input, prisma });
@@ -4,10 +4,10 @@ import getApps from "@calcom/app-store/utils";
import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
import { prisma } from "@calcom/prisma";
import { userMetadata } from "@calcom/prisma/zod-utils";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../trpc";
import type { TUpdateUserDefaultConferencingAppInputSchema } from "./updateUserDefaultConferencingApp.schema";
type UpdateUserDefaultConferencingAppOptions = {