diff --git a/apps/web/pages/apps/categories/[category].tsx b/apps/web/pages/apps/categories/[category].tsx index a8a8dc5c46..bc7faeccbe 100644 --- a/apps/web/pages/apps/categories/[category].tsx +++ b/apps/web/pages/apps/categories/[category].tsx @@ -47,13 +47,7 @@ export default function Apps({ apps }: InferGetStaticPropsType { - const appStore = await getAppRegistry(); - const paths = appStore.reduce((categories, app) => { - if (!categories.includes(app.category)) { - categories.push(app.category); - } - return categories; - }, [] as string[]); + const paths = Object.keys(AppCategories); return { paths: paths.map((category) => ({ params: { category } })), diff --git a/apps/web/pages/apps/categories/index.tsx b/apps/web/pages/apps/categories/index.tsx index 98fe43ade3..94d17d8ac2 100644 --- a/apps/web/pages/apps/categories/index.tsx +++ b/apps/web/pages/apps/categories/index.tsx @@ -44,7 +44,9 @@ export default function Apps({ categories }: InferGetStaticPropsType { const appStore = await getAppRegistry(); const categories = appStore.reduce((c, app) => { - c[app.category] = c[app.category] ? c[app.category] + 1 : 1; + for (const category of app.categories) { + c[category] = c[category] ? c[category] + 1 : 1; + } return c; }, {} as Record); diff --git a/apps/web/pages/apps/index.tsx b/apps/web/pages/apps/index.tsx index 8381290721..8022d525c0 100644 --- a/apps/web/pages/apps/index.tsx +++ b/apps/web/pages/apps/index.tsx @@ -1,4 +1,4 @@ -import { GetServerSideProps, InferGetServerSidePropsType } from "next"; +import { GetServerSidePropsContext } from "next"; import { ChangeEventHandler, useState } from "react"; import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry"; @@ -6,6 +6,7 @@ import { classNames } from "@calcom/lib"; import { getSession } from "@calcom/lib/auth"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { AppCategories } from "@calcom/prisma/client"; +import { inferSSRProps } from "@calcom/types/inferSSRProps"; import { AllApps, AppsLayout, AppStoreCategories, Icon, TextField, TrendingAppsSlider } from "@calcom/ui"; import { ssgInit } from "@server/lib/ssg"; @@ -30,10 +31,7 @@ function AppsSearch({ ); } -export default function Apps({ - categories, - appStore, -}: InferGetServerSidePropsType) { +export default function Apps({ categories, appStore }: inferSSRProps) { const { t } = useLocale(); const [searchText, setSearchText] = useState(undefined); @@ -52,12 +50,16 @@ export default function Apps({ )} - + category.name)} + /> ); } -export const getServerSideProps: GetServerSideProps = async (context) => { +export const getServerSideProps = async (context: GetServerSidePropsContext) => { const ssg = await ssgInit(context); const session = await getSession(context); diff --git a/packages/app-store/_appRegistry.ts b/packages/app-store/_appRegistry.ts index b2bc447a74..60c424d882 100644 --- a/packages/app-store/_appRegistry.ts +++ b/packages/app-store/_appRegistry.ts @@ -1,7 +1,6 @@ -import type { Credential } from "@prisma/client"; - -import prisma from "@calcom/prisma"; -import { App } from "@calcom/types/App"; +import prisma, { safeAppSelect, safeCredentialSelect } from "@calcom/prisma"; +import { AppFrontendPayload as App } from "@calcom/types/App"; +import { CredentialFrontendPayload as Credential } from "@calcom/types/Credential"; export async function getAppWithMetadata(app: { dirName: string }) { let appMetadata: App | null = null; @@ -30,7 +29,7 @@ export async function getAppRegistry() { where: { enabled: true }, select: { dirName: true, slug: true, categories: true, enabled: true }, }); - const apps = [] as Omit[]; + const apps = [] as App[]; for await (const dbapp of dbApps) { const app = await getAppWithMetadata(dbapp); if (!app) continue; @@ -56,9 +55,15 @@ export async function getAppRegistry() { export async function getAppRegistryWithCredentials(userId: number) { const dbApps = await prisma.app.findMany({ where: { enabled: true }, - include: { credentials: { where: { userId } } }, + select: { + ...safeAppSelect, + credentials: { + where: { userId }, + select: safeCredentialSelect, + }, + }, }); - const apps = [] as (Omit & { + const apps = [] as (App & { credentials: Credential[]; })[]; for await (const dbapp of dbApps) { @@ -77,8 +82,7 @@ export async function getAppRegistryWithCredentials(userId: number) { ...remainingAppProps, categories: dbapp.categories, credentials: dbapp.credentials, - installed: - true /* All apps from DB are considered installed by default. @TODO: Add and filter our by `enabled` property */, + installed: true, }); } return apps; diff --git a/packages/app-store/applecalendar/_metadata.ts b/packages/app-store/applecalendar/_metadata.ts index ab84900af1..c186b7c72e 100644 --- a/packages/app-store/applecalendar/_metadata.ts +++ b/packages/app-store/applecalendar/_metadata.ts @@ -10,6 +10,7 @@ export const metadata = { title: "Apple Calendar", imageSrc: "/api/app-store/applecalendar/icon.svg", variant: "calendar", + categories: ["calendar"], category: "calendar", logo: "/api/app-store/applecalendar/icon.svg", publisher: "Cal.com", diff --git a/packages/app-store/around/_metadata.ts b/packages/app-store/around/_metadata.ts index 671ff49ce1..dcbfb1053b 100644 --- a/packages/app-store/around/_metadata.ts +++ b/packages/app-store/around/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "around", appData: { location: { diff --git a/packages/app-store/caldavcalendar/_metadata.ts b/packages/app-store/caldavcalendar/_metadata.ts index f3f6408f1c..89b6416a41 100644 --- a/packages/app-store/caldavcalendar/_metadata.ts +++ b/packages/app-store/caldavcalendar/_metadata.ts @@ -11,6 +11,7 @@ export const metadata = { imageSrc: "/api/app-store/caldavcalendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], logo: "/api/app-store/caldavcalendar/icon.svg", publisher: "Cal.com", rating: 5, diff --git a/packages/app-store/caldavcalendar/index.ts b/packages/app-store/caldavcalendar/index.ts index 24c468e15a..bca520a8ec 100644 --- a/packages/app-store/caldavcalendar/index.ts +++ b/packages/app-store/caldavcalendar/index.ts @@ -11,6 +11,7 @@ export const metadata = { imageSrc: "/api/app-store/caldavcalendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], logo: "/api/app-store/caldavcalendar/icon.svg", publisher: "Cal.com", rating: 5, diff --git a/packages/app-store/campfire/_metadata.ts b/packages/app-store/campfire/_metadata.ts index c255f913c1..87e5b7ffef 100644 --- a/packages/app-store/campfire/_metadata.ts +++ b/packages/app-store/campfire/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "caldavcalendar", ...config, } as AppMeta; diff --git a/packages/app-store/dailyvideo/_metadata.ts b/packages/app-store/dailyvideo/_metadata.ts index 49cc2f136d..8cebfb2895 100644 --- a/packages/app-store/dailyvideo/_metadata.ts +++ b/packages/app-store/dailyvideo/_metadata.ts @@ -10,6 +10,7 @@ export const metadata = { imageSrc: "/api/app-store/dailyvideo/icon.svg", variant: "conferencing", url: "https://daily.co", + categories: ["calendar"], trending: true, logo: "/api/app-store/dailyvideo/icon.svg", publisher: "Cal.com", diff --git a/packages/app-store/exchange2013calendar/_metadata.ts b/packages/app-store/exchange2013calendar/_metadata.ts index b7371da47d..10a8a98daa 100644 --- a/packages/app-store/exchange2013calendar/_metadata.ts +++ b/packages/app-store/exchange2013calendar/_metadata.ts @@ -11,6 +11,7 @@ export const metadata = { imageSrc: "/api/app-store/exchange2013calendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], label: "Exchange Calendar", logo: "/api/app-store/exchange2013calendar/icon.svg", publisher: "Cal.com", diff --git a/packages/app-store/exchange2016calendar/_metadata.ts b/packages/app-store/exchange2016calendar/_metadata.ts index ad7e028cfe..59126acde6 100644 --- a/packages/app-store/exchange2016calendar/_metadata.ts +++ b/packages/app-store/exchange2016calendar/_metadata.ts @@ -11,6 +11,7 @@ export const metadata = { imageSrc: "/api/app-store/exchange2016calendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], label: "Exchange Calendar", logo: "/api/app-store/exchange2016calendar/icon.svg", publisher: "Cal.com", diff --git a/packages/app-store/ga4/_metadata.ts b/packages/app-store/ga4/_metadata.ts index c77cfbbf99..799f01c480 100644 --- a/packages/app-store/ga4/_metadata.ts +++ b/packages/app-store/ga4/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "ga4", ...config, } as AppMeta; diff --git a/packages/app-store/giphy/_metadata.ts b/packages/app-store/giphy/_metadata.ts index c714136b2f..fa6dc9d01b 100644 --- a/packages/app-store/giphy/_metadata.ts +++ b/packages/app-store/giphy/_metadata.ts @@ -6,7 +6,7 @@ export const metadata = { name: "Giphy", description: _package.description, installed: true, - category: "other", + categories: ["other"], // If using static next public folder, can then be referenced from the base URL (/). imageSrc: "/api/app-store/giphy/icon.svg", logo: "/api/app-store/giphy/icon.svg", diff --git a/packages/app-store/googlecalendar/_metadata.ts b/packages/app-store/googlecalendar/_metadata.ts index dba292b667..f8ad911793 100644 --- a/packages/app-store/googlecalendar/_metadata.ts +++ b/packages/app-store/googlecalendar/_metadata.ts @@ -12,6 +12,7 @@ export const metadata = { imageSrc: "/api/app-store/googlecalendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], logo: "/api/app-store/googlecalendar/icon.svg", publisher: "Cal.com", rating: 5, diff --git a/packages/app-store/googlevideo/_metadata.ts b/packages/app-store/googlevideo/_metadata.ts index 7ff0b21ede..4ea165306b 100644 --- a/packages/app-store/googlevideo/_metadata.ts +++ b/packages/app-store/googlevideo/_metadata.ts @@ -9,6 +9,7 @@ export const metadata = { installed: !!(process.env.GOOGLE_API_CREDENTIALS && validJson(process.env.GOOGLE_API_CREDENTIALS)), slug: "google-meet", category: "video", + categories: ["video"], type: "google_video", title: "Google Meet", imageSrc: "/api/app-store/googlevideo/logo.webp", diff --git a/packages/app-store/hubspot/_metadata.ts b/packages/app-store/hubspot/_metadata.ts index 3ea08eef0c..013bade0aa 100644 --- a/packages/app-store/hubspot/_metadata.ts +++ b/packages/app-store/hubspot/_metadata.ts @@ -15,7 +15,7 @@ export const metadata = { verified: true, rating: 4.3, // TODO: placeholder for now, pull this from TrustPilot or G2 reviews: 69, // TODO: placeholder for now, pull this from TrustPilot or G2 - category: "other", + categories: ["other"], label: "HubSpot CRM", slug: "hubspot", title: "HubSpot CRM", diff --git a/packages/app-store/huddle01video/_metadata.ts b/packages/app-store/huddle01video/_metadata.ts index 1812dd29e7..c5b4b4002d 100644 --- a/packages/app-store/huddle01video/_metadata.ts +++ b/packages/app-store/huddle01video/_metadata.ts @@ -10,6 +10,7 @@ export const metadata = { type: "huddle01_video", imageSrc: "/api/app-store/huddle01video/icon.svg", variant: "conferencing", + categories: ["video", "web3"], logo: "/api/app-store/huddle01video/icon.svg", publisher: "huddle01.com", url: "https://huddle01.com", diff --git a/packages/app-store/jitsivideo/_metadata.ts b/packages/app-store/jitsivideo/_metadata.ts index ba16746d81..dd26e2eb82 100644 --- a/packages/app-store/jitsivideo/_metadata.ts +++ b/packages/app-store/jitsivideo/_metadata.ts @@ -9,13 +9,13 @@ export const metadata = { type: "jitsi_video", imageSrc: "/api/app-store/jitsivideo/icon.svg", variant: "conferencing", + categories: ["video"], logo: "/api/app-store/jitsivideo/icon.svg", publisher: "Cal.com", url: "https://jitsi.org/", verified: true, rating: 0, // TODO: placeholder for now, pull this from TrustPilot or G2 reviews: 0, // TODO: placeholder for now, pull this from TrustPilot or G2 - category: "video", slug: "jitsi", title: "Jitsi Meet", trending: true, diff --git a/packages/app-store/larkcalendar/_metadata.ts b/packages/app-store/larkcalendar/_metadata.ts index 81c174f73e..7e9781a2e0 100644 --- a/packages/app-store/larkcalendar/_metadata.ts +++ b/packages/app-store/larkcalendar/_metadata.ts @@ -10,7 +10,7 @@ export const metadata = { title: "Lark Calendar", imageSrc: "/api/app-store/larkcalendar/icon.svg", variant: "calendar", - category: "calendar", + categories: ["calendar"], logo: "/api/app-store/larkcalendar/icon.svg", publisher: "Lark", rating: 5, diff --git a/packages/app-store/office365calendar/_metadata.ts b/packages/app-store/office365calendar/_metadata.ts index 62df3e4752..42d45f7723 100644 --- a/packages/app-store/office365calendar/_metadata.ts +++ b/packages/app-store/office365calendar/_metadata.ts @@ -10,6 +10,7 @@ export const metadata = { imageSrc: "/api/app-store/office365calendar/icon.svg", variant: "calendar", category: "calendar", + categories: ["calendar"], logo: "/api/app-store/office365calendar/icon.svg", publisher: "Cal.com", rating: 5, diff --git a/packages/app-store/office365video/config.json b/packages/app-store/office365video/config.json index ec88857877..b29650927e 100644 --- a/packages/app-store/office365video/config.json +++ b/packages/app-store/office365video/config.json @@ -11,6 +11,7 @@ "rating": 4.3, "reviews": 69, "category": "video", + "categories": ["video"], "slug": "msteams", "title": "MS Teams (Requires work/school account)", "trending": true, diff --git a/packages/app-store/ping/_metadata.ts b/packages/app-store/ping/_metadata.ts index cd629e91f9..45334f190a 100644 --- a/packages/app-store/ping/_metadata.ts +++ b/packages/app-store/ping/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", // FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here installed: true, rating: 0, diff --git a/packages/app-store/pipedream/_metadata.ts b/packages/app-store/pipedream/_metadata.ts index fae46693c0..d0a81296e2 100644 --- a/packages/app-store/pipedream/_metadata.ts +++ b/packages/app-store/pipedream/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "pipedream", ...config, } as AppMeta; diff --git a/packages/app-store/rainbow/_metadata.ts b/packages/app-store/rainbow/_metadata.ts index e7c2745dd9..860c91c24e 100644 --- a/packages/app-store/rainbow/_metadata.ts +++ b/packages/app-store/rainbow/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "rainbow", ...config, } as AppMeta; diff --git a/packages/app-store/riverside/_metadata.ts b/packages/app-store/riverside/_metadata.ts index 7b1c590735..4d429e62f8 100644 --- a/packages/app-store/riverside/_metadata.ts +++ b/packages/app-store/riverside/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", // FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here installed: true, rating: 0, diff --git a/packages/app-store/salesforce/_metadata.ts b/packages/app-store/salesforce/_metadata.ts index 5336e9b798..031ec22e3d 100644 --- a/packages/app-store/salesforce/_metadata.ts +++ b/packages/app-store/salesforce/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "salesforce", ...config, } as AppMeta; diff --git a/packages/app-store/sendgrid/_metadata.ts b/packages/app-store/sendgrid/_metadata.ts index 1811df8a21..590bac19ae 100644 --- a/packages/app-store/sendgrid/_metadata.ts +++ b/packages/app-store/sendgrid/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "sendgrid", ...config, } as AppMeta; diff --git a/packages/app-store/signal/_metadata.ts b/packages/app-store/signal/_metadata.ts index 3265637d31..72a96e122a 100644 --- a/packages/app-store/signal/_metadata.ts +++ b/packages/app-store/signal/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "signal", ...config, } as AppMeta; diff --git a/packages/app-store/sirius_video/_metadata.ts b/packages/app-store/sirius_video/_metadata.ts index d507b79142..dce7ba1924 100644 --- a/packages/app-store/sirius_video/_metadata.ts +++ b/packages/app-store/sirius_video/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "sirius_video", ...config, } as AppMeta; diff --git a/packages/app-store/stripepayment/_metadata.ts b/packages/app-store/stripepayment/_metadata.ts index 8e928a45a7..f3992d3406 100644 --- a/packages/app-store/stripepayment/_metadata.ts +++ b/packages/app-store/stripepayment/_metadata.ts @@ -12,6 +12,7 @@ export const metadata = { ), slug: "stripe", category: "payment", + categories: ["payment"], logo: "/api/app-store/stripepayment/icon.svg", rating: 4.6, trending: true, diff --git a/packages/app-store/tandemvideo/_metadata.ts b/packages/app-store/tandemvideo/_metadata.ts index 30c30a4d80..c99041dc16 100644 --- a/packages/app-store/tandemvideo/_metadata.ts +++ b/packages/app-store/tandemvideo/_metadata.ts @@ -9,6 +9,7 @@ export const metadata = { title: "Tandem Video", imageSrc: "/api/app-store/tandemvideo/icon.svg", variant: "conferencing", + categories: ["video"], slug: "tandem", category: "video", logo: "/api/app-store/tandemvideo/icon.svg", diff --git a/packages/app-store/telegram/_metadata.ts b/packages/app-store/telegram/_metadata.ts index feeed54b84..06179994da 100644 --- a/packages/app-store/telegram/_metadata.ts +++ b/packages/app-store/telegram/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "telegram", ...config, } as AppMeta; diff --git a/packages/app-store/utils.ts b/packages/app-store/utils.ts index bde67c3294..637e55c9de 100644 --- a/packages/app-store/utils.ts +++ b/packages/app-store/utils.ts @@ -76,7 +76,10 @@ export function getLocationGroupedOptions(integrations: ReturnType = {}; integrations.forEach((app) => { if (app.locationOption) { - const category = app.category; + // All apps that are labeled as a locationOption are video apps. Extract the secondary category if available + let category = + app.categories.length >= 2 ? app.categories.find((category) => category !== "video") : app.category; + if (!category) category = "video"; const option = { ...app.locationOption, icon: app.imageSrc }; if (apps[category]) { apps[category] = [...apps[category], option]; diff --git a/packages/app-store/vital/_metadata.ts b/packages/app-store/vital/_metadata.ts index 92ac7ff29c..0860dedd78 100644 --- a/packages/app-store/vital/_metadata.ts +++ b/packages/app-store/vital/_metadata.ts @@ -7,6 +7,7 @@ export const metadata = { description: _package.description, installed: true, category: "other", + categories: ["other"], // If using static next public folder, can then be referenced from the base URL (/). imageSrc: "/api/app-store/vital/icon.svg", logo: "/api/app-store/vital/icon.svg", diff --git a/packages/app-store/whatsapp/_metadata.ts b/packages/app-store/whatsapp/_metadata.ts index d03408c42b..1cea62f750 100644 --- a/packages/app-store/whatsapp/_metadata.ts +++ b/packages/app-store/whatsapp/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", dirName: "whatsapp", ...config, } as AppMeta; diff --git a/packages/app-store/whereby/_metadata.ts b/packages/app-store/whereby/_metadata.ts index 97574d63ad..627fdb55ab 100644 --- a/packages/app-store/whereby/_metadata.ts +++ b/packages/app-store/whereby/_metadata.ts @@ -3,7 +3,6 @@ import type { AppMeta } from "@calcom/types/App"; import config from "./config.json"; export const metadata = { - category: "other", // FIXME: Currently for an app to be shown as installed, it must have this variable set. Either hardcoded or if it depends on some env variable, that should be checked here installed: true, rating: 0, diff --git a/packages/app-store/wipemycalother/_metadata.ts b/packages/app-store/wipemycalother/_metadata.ts index 32e196685a..dbc038883d 100644 --- a/packages/app-store/wipemycalother/_metadata.ts +++ b/packages/app-store/wipemycalother/_metadata.ts @@ -7,6 +7,7 @@ export const metadata = { description: _package.description, installed: true, category: "other", + categories: ["other"], // If using static next public folder, can then be referenced from the base URL (/). imageSrc: "/api/app-store/wipemycalother/icon-dark.svg", logo: "/api/app-store/wipemycalother/icon-dark.svg", diff --git a/packages/app-store/zapier/_metadata.ts b/packages/app-store/zapier/_metadata.ts index 8d7015f90a..cddef338da 100644 --- a/packages/app-store/zapier/_metadata.ts +++ b/packages/app-store/zapier/_metadata.ts @@ -7,6 +7,7 @@ export const metadata = { description: _package.description, installed: true, category: "automation", + categories: ["automation"], imageSrc: "/api/app-store/zapier/icon.svg", logo: "/api/app-store/zapier/icon.svg", publisher: "Cal.com", diff --git a/packages/app-store/zoomvideo/_metadata.ts b/packages/app-store/zoomvideo/_metadata.ts index 309456b896..cf2232aad4 100644 --- a/packages/app-store/zoomvideo/_metadata.ts +++ b/packages/app-store/zoomvideo/_metadata.ts @@ -7,6 +7,7 @@ export const metadata = { name: "Zoom Video", description: _package.description, type: "zoom_video", + categories: ["video"], imageSrc: "/api/app-store/zoomvideo/icon.svg", variant: "conferencing", logo: "/api/app-store/zoomvideo/icon.svg", diff --git a/packages/prisma/selects/app.ts b/packages/prisma/selects/app.ts new file mode 100644 index 0000000000..80cb306293 --- /dev/null +++ b/packages/prisma/selects/app.ts @@ -0,0 +1,12 @@ +import { Prisma } from "@prisma/client"; + +export const safeAppSelect = Prisma.validator()({ + slug: true, + dirName: true, + /** Omitting to avoid frontend leaks */ + // keys: true, + categories: true, + createdAt: true, + updatedAt: true, + enabled: true, +}); diff --git a/packages/prisma/selects/credential.ts b/packages/prisma/selects/credential.ts new file mode 100644 index 0000000000..a48d4b7e95 --- /dev/null +++ b/packages/prisma/selects/credential.ts @@ -0,0 +1,11 @@ +import { Prisma } from "@prisma/client"; + +export const safeCredentialSelect = Prisma.validator()({ + id: true, + type: true, + /** Omitting to avoid frontend leaks */ + // key: true, + userId: true, + appId: true, + invalid: true, +}); diff --git a/packages/prisma/selects/index.ts b/packages/prisma/selects/index.ts index 8376ce7e82..bfe665fa5e 100644 --- a/packages/prisma/selects/index.ts +++ b/packages/prisma/selects/index.ts @@ -1,3 +1,5 @@ +export { safeAppSelect } from "./app"; export * from "./booking"; +export { safeCredentialSelect } from "./credential"; export * from "./event-types"; export * from "./user"; diff --git a/packages/types/App.d.ts b/packages/types/App.d.ts index 6c22c0fd29..783bd514be 100644 --- a/packages/types/App.d.ts +++ b/packages/types/App.d.ts @@ -89,10 +89,10 @@ export interface App { /* * @deprecated Use categories */ - category: string; + category?: string; /** The category to which this app belongs, currently we have `calendar`, `payment` or `video` */ - categories?: string[]; + categories: string[]; /** * `User` is the broadest category. `EventType` is when you want to add features to EventTypes. * See https://app.gitbook.com/o/6snd8PyPYMhg0wUw6CeQ/s/VXRprBTuMlihk37NQgUU/~/changes/6xkqZ4qvJ3Xh9k8UaWaZ/engineering/product-specs/app-store#user-apps for more details @@ -121,9 +121,6 @@ export interface App { isGlobal?: boolean; /** A contact email, mainly to ask for support */ email: string; - - /** Needed API Keys (usually for global apps) */ - key?: Prisma.JsonValue; /** Needed API Keys (usually for global apps) */ key?: Prisma.JsonValue; /** If not free, what kind of fees does the app have */ @@ -138,4 +135,9 @@ export interface App { dirName?: string; } +export type AppFrontendPayload = Omit & { + /** We should type error if keys are leaked to the frontend */ + key?: never; +}; + export type AppMeta = Optional; diff --git a/packages/types/Credential.d.ts b/packages/types/Credential.d.ts index bd357fe32f..265d4ca978 100644 --- a/packages/types/Credential.d.ts +++ b/packages/types/Credential.d.ts @@ -16,4 +16,9 @@ export type CredentialPayload = Prisma.CredentialGetPayload<{ }; }>; +export type CredentialFrontendPayload = Omit & { + /** We should type error if keys are leaked to the frontend */ + key?: never; +}; + export type CredentialWithAppName = CredentialPayload & { appName: string }; diff --git a/packages/ui/v2/core/apps/AllApps.tsx b/packages/ui/v2/core/apps/AllApps.tsx index 5f551b57d4..e8c4605b20 100644 --- a/packages/ui/v2/core/apps/AllApps.tsx +++ b/packages/ui/v2/core/apps/AllApps.tsx @@ -1,11 +1,11 @@ import { useAutoAnimate } from "@formkit/auto-animate/react"; -import type { Credential } from "@prisma/client"; import { useRouter } from "next/router"; import { UIEvent, useEffect, useRef, useState } from "react"; import { classNames } from "@calcom/lib"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import type { App } from "@calcom/types/App"; +import type { AppFrontendPayload as App } from "@calcom/types/App"; +import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential"; import { Icon } from "@calcom/ui"; import EmptyScreen from "../EmptyScreen"; @@ -37,7 +37,11 @@ export function useShouldShowArrows() { return { ref, calculateScroll, leftVisible: showArrowScroll.left, rightVisible: showArrowScroll.right }; } -type AllAppsPropsType = { apps: (App & { credentials: Credential[] | undefined })[]; searchText?: string }; +type AllAppsPropsType = { + apps: (App & { credentials?: Credential[] })[]; + searchText?: string; + categories: string[]; +}; interface CategoryTabProps { selectedCategory: string | null; @@ -125,18 +129,12 @@ function CategoryTab({ selectedCategory, categories, searchText }: CategoryTabPr ); } -export default function AllApps({ apps, searchText }: AllAppsPropsType) { +export default function AllApps({ apps, searchText, categories }: AllAppsPropsType) { const router = useRouter(); const { t } = useLocale(); const [selectedCategory, setSelectedCategory] = useState(null); const [appsContainerRef, enableAnimation] = useAutoAnimate(); - const categories = apps - .map((app) => app.category) - .filter((cat, pos, self) => { - return self.indexOf(cat) === pos; - }); - if (searchText) { enableAnimation && enableAnimation(false); } diff --git a/packages/ui/v2/core/apps/AppCard.tsx b/packages/ui/v2/core/apps/AppCard.tsx index c9f842ff8a..72e6ae0d49 100644 --- a/packages/ui/v2/core/apps/AppCard.tsx +++ b/packages/ui/v2/core/apps/AppCard.tsx @@ -1,11 +1,11 @@ -import type { Credential } from "@prisma/client"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation"; import { InstallAppButton } from "@calcom/app-store/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { App } from "@calcom/types/App"; +import { AppFrontendPayload as App } from "@calcom/types/App"; +import type { CredentialFrontendPayload as Credential } from "@calcom/types/Credential"; import { Button, Icon } from "../../.."; import { showToast } from "../notifications"; @@ -123,8 +123,6 @@ export default function AppCard({ app, credentials, searchText }: AppCardProps) }, }; } - props.color; - // ^? return (