From fed39870282e90de19e5d08ef78e2469624b376c Mon Sep 17 00:00:00 2001 From: Somay Chauhan Date: Wed, 10 Jul 2024 16:04:14 +0530 Subject: [PATCH] fix: disable google-meet in user onboarding if google-calendar is not installed (#15702) * fix: disable google-meet in user onboarding if google-calendar is not installed * add tooltip * fix: type check * fix: type check for tooltip - allowed `ReactNode` for tooltip content prop --------- Co-authored-by: Hariom Balhara --- .../components/AppConnectionItem.tsx | 43 ++++++++++++++++++- .../steps-views/ConnectedVideoStep.tsx | 1 + packages/app-store/_appRegistry.ts | 10 +++-- .../loggedInViewer/integrations.handler.ts | 15 +++++++ packages/ui/components/button/Button.tsx | 4 +- 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/apps/web/components/getting-started/components/AppConnectionItem.tsx b/apps/web/components/getting-started/components/AppConnectionItem.tsx index cdaf308ee6..579a52a2a2 100644 --- a/apps/web/components/getting-started/components/AppConnectionItem.tsx +++ b/apps/web/components/getting-started/components/AppConnectionItem.tsx @@ -1,6 +1,11 @@ +import Link from "next/link"; + +import type { TDependencyData } from "@calcom/app-store/_appRegistry"; import { InstallAppButtonWithoutPlanCheck } from "@calcom/app-store/components"; +import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { App } from "@calcom/types/App"; +import { Icon } from "@calcom/ui"; import { Button } from "@calcom/ui"; interface IAppConnectionItem { @@ -9,11 +14,13 @@ interface IAppConnectionItem { logo: string; type: App["type"]; installed?: boolean; + dependencyData?: TDependencyData; } const AppConnectionItem = (props: IAppConnectionItem) => { const { title, logo, type, installed } = props; const { t } = useLocale(); + const dependency = props.dependencyData?.find((data) => !data.installed); return (
@@ -26,9 +33,43 @@ const AppConnectionItem = (props: IAppConnectionItem) => {
+ ) : undefined + } onClick={(event) => { // Save cookie key to return url step document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`; diff --git a/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx b/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx index 5be304eb28..0789555d7b 100644 --- a/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx +++ b/apps/web/components/getting-started/steps-views/ConnectedVideoStep.tsx @@ -37,6 +37,7 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => { type={item.type} title={item.name} description={item.description} + dependencyData={item.dependencyData} logo={item.logo} installed={item.userCredentialIds.length > 0} /> diff --git a/packages/app-store/_appRegistry.ts b/packages/app-store/_appRegistry.ts index a6b3d9d73a..0999a76e53 100644 --- a/packages/app-store/_appRegistry.ts +++ b/packages/app-store/_appRegistry.ts @@ -7,6 +7,11 @@ import { userMetadata } from "@calcom/prisma/zod-utils"; import type { AppFrontendPayload as App } from "@calcom/types/App"; import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential"; +export type TDependencyData = { + name?: string; + installed?: boolean; +}[]; + /** * Get App metdata either using dirName or slug */ @@ -96,10 +101,7 @@ export async function getAppRegistryWithCredentials(userId: number, userAdminTea /* This is now handled from the DB */ // if (!app.installed) return apps; app.createdAt = dbapp.createdAt.toISOString(); - let dependencyData: { - name?: string; - installed?: boolean; - }[] = []; + let dependencyData: TDependencyData = []; if (app.dependencies) { dependencyData = app.dependencies.map((dependency) => { const dependencyInstalled = dbApps.some( diff --git a/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts b/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts index 7f2bd190bb..ac9b06944c 100644 --- a/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts +++ b/packages/trpc/server/routers/loggedInViewer/integrations.handler.ts @@ -1,7 +1,9 @@ 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"; +import { getAppFromSlug } from "@calcom/app-store/utils"; import getEnabledAppsFromCredentials from "@calcom/lib/apps/getEnabledAppsFromCredentials"; import getInstallCountPerApp from "@calcom/lib/apps/getInstallCountPerApp"; import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials"; @@ -179,6 +181,18 @@ export const integrationsHandler = async ({ ctx, input }: IntegrationsOptions) = } } + let dependencyData: TDependencyData = []; + if (app.dependencies?.length) { + dependencyData = app.dependencies.map((dependency) => { + const dependencyInstalled = enabledApps.some( + (dbAppIterator) => dbAppIterator.credentials.length && dbAppIterator.slug === dependency + ); + // If the app marked as dependency is simply deleted from the codebase, we can have the situation where App is marked installed in DB but we couldn't get the app. + const dependencyName = getAppFromSlug(dependency)?.name; + return { name: dependencyName, installed: dependencyInstalled }; + }); + } + return { ...app, ...(teams.length && { @@ -189,6 +203,7 @@ export const integrationsHandler = async ({ ctx, input }: IntegrationsOptions) = teams, isInstalled: !!userCredentialIds.length || !!teams.length || app.isGlobal, isSetupAlready, + ...(app.dependencies && { dependencyData }), }; }) ); diff --git a/packages/ui/components/button/Button.tsx b/packages/ui/components/button/Button.tsx index 1a0495438b..4faa22569f 100644 --- a/packages/ui/components/button/Button.tsx +++ b/packages/ui/components/button/Button.tsx @@ -22,7 +22,7 @@ export type ButtonBaseProps = { EndIcon?: IconName; shallow?: boolean; /**Tool tip used when icon size is set to small */ - tooltip?: string; + tooltip?: string | React.ReactNode; tooltipSide?: "top" | "right" | "bottom" | "left"; tooltipOffset?: number; disabled?: boolean; @@ -240,7 +240,7 @@ const Wrapper = ({ tooltipSide, tooltipOffset, }: { - tooltip?: string; + tooltip?: string | React.ReactNode; children: React.ReactNode; tooltipSide?: "top" | "right" | "bottom" | "left"; tooltipOffset?: number;