chore: migrate /apps/[slug] page (#18848)

* migrate apps/[slug] page

* remove future/apps/[slug]
This commit is contained in:
Benny Joo
2025-01-24 15:57:52 +01:00
committed by GitHub
parent 84df8dc6eb
commit beb542e7cb
10 changed files with 86 additions and 117 deletions
-1
View File
@@ -357,7 +357,6 @@ E2E_TEST_OIDC_USER_PASSWORD=
# redirected from the legacy to the future pages
AB_TEST_BUCKET_PROBABILITY=50
APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED=0
APP_ROUTER_APPS_SLUG_ENABLED=0
APP_ROUTER_APPS_SLUG_SETUP_ENABLED=0
# whether we redirect to the future/apps/categories from /apps/categories or not
APP_ROUTER_APPS_CATEGORIES_ENABLED=0
-1
View File
@@ -6,7 +6,6 @@ import { FUTURE_ROUTES_ENABLED_COOKIE_NAME, FUTURE_ROUTES_OVERRIDE_COOKIE_NAME }
const ROUTES: [URLPattern, boolean][] = [
["/apps/installed/:category", process.env.APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED === "1"] as const,
["/apps/:slug", process.env.APP_ROUTER_APPS_SLUG_ENABLED === "1"] as const,
["/apps/:slug/setup", process.env.APP_ROUTER_APPS_SLUG_SETUP_ENABLED === "1"] as const,
["/apps/categories", process.env.APP_ROUTER_APPS_CATEGORIES_ENABLED === "1"] as const,
["/apps/categories/:category", process.env.APP_ROUTER_APPS_CATEGORIES_CATEGORY_ENABLED === "1"] as const,
@@ -0,0 +1,51 @@
import type { PageProps as _PageProps } from "app/_types";
import { generateAppMetadata } from "app/_utils";
import { notFound } from "next/navigation";
import { z } from "zod";
import { getStaticProps } from "@lib/apps/[slug]/getStaticProps";
import AppView from "~/apps/[slug]/slug-view";
const paramsSchema = z.object({
slug: z.string(),
});
export const generateMetadata = async ({ params }: _PageProps) => {
const p = paramsSchema.safeParse(params);
if (!p.success) {
return notFound();
}
const props = await getStaticProps(p.data.slug);
if (!props) {
notFound();
}
const { name, logo, description } = props.data;
return await generateAppMetadata(
{ slug: logo, name, description },
() => name,
() => description
);
};
async function Page({ params }: _PageProps) {
const p = paramsSchema.safeParse(params);
if (!p.success) {
return notFound();
}
const props = await getStaticProps(p.data.slug);
if (!props) {
notFound();
}
return <AppView {...props} />;
}
export default Page;
+22 -2
View File
@@ -3,8 +3,8 @@ import i18next from "i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { headers } from "next/headers";
import type { MeetingImageProps } from "@calcom/lib/OgImages";
import { constructGenericImage, constructMeetingImage } from "@calcom/lib/OgImages";
import type { AppImageProps, MeetingImageProps } from "@calcom/lib/OgImages";
import { constructAppImage, constructGenericImage, constructMeetingImage } from "@calcom/lib/OgImages";
import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG, CAL_URL } from "@calcom/lib/constants";
import { buildCanonical } from "@calcom/lib/next-seo.config";
import { truncateOnWord } from "@calcom/lib/text";
@@ -123,3 +123,23 @@ export const generateMeetingMetadata = async (
},
};
};
export const generateAppMetadata = async (
app: AppImageProps,
getTitle: (t: TFunction<string, undefined>) => string,
getDescription: (t: TFunction<string, undefined>) => string,
hideBranding?: boolean,
origin?: string
) => {
const metadata = await _generateMetadataWithoutImage(getTitle, getDescription, hideBranding, origin);
const image = SEO_IMG_OGIMG + constructAppImage({ ...app, description: metadata.description });
return {
...metadata,
openGraph: {
...metadata.openGraph,
images: [image],
},
};
};
-45
View File
@@ -1,45 +0,0 @@
import { Prisma } from "@prisma/client";
import { withAppDirSsg } from "app/WithAppDirSsg";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { AppRepository } from "@calcom/lib/server/repository/app";
import { getStaticProps } from "@lib/apps/[slug]/getStaticProps";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import type { PageProps } from "~/apps/[slug]/slug-view";
import Page from "~/apps/[slug]/slug-view";
const getData = withAppDirSsg<PageProps>(getStaticProps, "future/apps/[slug]");
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const legacyContext = buildLegacyCtx(headers(), cookies(), params, searchParams);
const res = await getData(legacyContext);
return await _generateMetadata(
() => res?.data.name ?? "",
() => res?.data.description ?? ""
);
};
export const generateStaticParams = async () => {
try {
const appStore = await AppRepository.findAppStore();
return appStore.map(({ slug }) => ({ slug }));
} catch (e: unknown) {
if (e instanceof Prisma.PrismaClientInitializationError) {
// Database is not available at build time, but that's ok – we fall back to resolving paths on demand
} else {
throw e;
}
}
return [];
};
export default WithLayout({ getLayout: null, Page, getData });
export const dynamic = "force-static";
+11 -19
View File
@@ -1,7 +1,5 @@
import fs from "fs";
import matter from "gray-matter";
import MarkdownIt from "markdown-it";
import type { GetStaticPropsContext } from "next";
import path from "path";
import { z } from "zod";
@@ -10,8 +8,6 @@ import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath";
import { IS_PRODUCTION } from "@calcom/lib/constants";
import prisma from "@calcom/prisma";
const md = new MarkdownIt("default", { html: true, breaks: true });
export const sourceSchema = z.object({
content: z.string(),
data: z.object({
@@ -29,15 +25,15 @@ export const sourceSchema = z.object({
}),
});
export const getStaticProps = async (ctx: GetStaticPropsContext) => {
if (typeof ctx.params?.slug !== "string") return { notFound: true } as const;
export type AppDataProps = NonNullable<Awaited<ReturnType<typeof getStaticProps>>>;
export const getStaticProps = async (slug: string) => {
const appMeta = await getAppWithMetadata({
slug: ctx.params?.slug,
slug,
});
const appFromDb = await prisma.app.findUnique({
where: { slug: ctx.params.slug.toLowerCase() },
where: { slug: slug.toLowerCase() },
});
const isAppAvailableInFileSystem = appMeta;
@@ -45,16 +41,14 @@ export const getStaticProps = async (ctx: GetStaticPropsContext) => {
if (!IS_PRODUCTION && isAppDisabled) {
return {
props: {
isAppDisabled: true as const,
data: {
...appMeta,
},
isAppDisabled: true as const,
data: {
...appMeta,
},
};
}
if (!appFromDb || !appMeta || isAppDisabled) return { notFound: true } as const;
if (!appFromDb || !appMeta || isAppDisabled) return null;
const isTemplate = appMeta.isTemplate;
const appDirname = path.join(isTemplate ? "templates" : "", appFromDb.dirName);
@@ -85,10 +79,8 @@ export const getStaticProps = async (ctx: GetStaticPropsContext) => {
});
}
return {
props: {
isAppDisabled: false as const,
source: { content, data },
data: appMeta,
},
isAppDisabled: false as const,
source: { content, data },
data: appMeta,
};
};
+2 -8
View File
@@ -1,7 +1,5 @@
"use client";
import MarkdownIt from "markdown-it";
import type { InferGetStaticPropsType } from "next";
import Link from "next/link";
import { IS_PRODUCTION } from "@calcom/lib/constants";
@@ -9,16 +7,12 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import { showToast } from "@calcom/ui";
import type { getStaticProps } from "@lib/apps/[slug]/getStaticProps";
import type { AppDataProps } from "@lib/apps/[slug]/getStaticProps";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import App from "@components/apps/App";
const md = new MarkdownIt("default", { html: true, breaks: true });
export type PageProps = InferGetStaticPropsType<typeof getStaticProps>;
function SingleAppPage(props: PageProps) {
function SingleAppPage(props: AppDataProps) {
const { error, setQuery: setError } = useRouterQuery("error");
const { t } = useLocale();
if (error === "account_already_linked") {
-39
View File
@@ -1,39 +0,0 @@
import { Prisma } from "@prisma/client";
import type { GetStaticPaths } from "next";
import { AppRepository } from "@calcom/lib/server/repository/app";
import { getStaticProps } from "@lib/apps/[slug]/getStaticProps";
import PageWrapper from "@components/PageWrapper";
import type { PageProps } from "~/apps/[slug]/slug-view";
import SingleAppPage from "~/apps/[slug]/slug-view";
const Page = (props: PageProps) => <SingleAppPage {...props} />;
export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => {
let paths: { params: { slug: string } }[] = [];
try {
const appStore = await AppRepository.findAppStore();
paths = appStore.map(({ slug }) => ({ params: { slug } }));
} catch (e: unknown) {
if (e instanceof Prisma.PrismaClientInitializationError) {
// Database is not available at build time, but that's ok – we fall back to resolving paths on demand
} else {
throw e;
}
}
return {
paths,
fallback: "blocking",
};
};
export { getStaticProps };
Page.PageWrapper = PageWrapper;
export default Page;
@@ -7,7 +7,6 @@ checkRoute () {
# These conditionals are used to remove directories from the build that are not needed in production
# This is to reduce the size of the build and prevent OOM errors
checkRoute "$APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED" app/future/apps/installed
checkRoute "$APP_ROUTER_APPS_SLUG_ENABLED" app/future/apps/\[slug\]
checkRoute "$APP_ROUTER_APPS_SLUG_SETUP_ENABLED" app/future/apps/\[slug\]/setup
checkRoute "$APP_ROUTER_APPS_CATEGORIES_ENABLED" app/future/apps/categories
checkRoute "$APP_ROUTER_APPS_CATEGORIES_CATEGORY_ENABLED" app/future/apps/categories/\[category\]
-1
View File
@@ -243,7 +243,6 @@
"APP_ROUTER_APPS_CATEGORIES_CATEGORY_ENABLED",
"APP_ROUTER_APPS_CATEGORIES_ENABLED",
"APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED",
"APP_ROUTER_APPS_SLUG_ENABLED",
"APP_ROUTER_APPS_SLUG_SETUP_ENABLED",
"APP_ROUTER_AUTH_FORGOT_PASSWORD_ENABLED",
"APP_ROUTER_AUTH_LOGIN_ENABLED",