chore: [app-router-migration-9] Migrate apps/index page (#12775)

Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
DmytroHryshyn 2024-01-04 23:36:31 +02:00 committed by GitHub
parent 49f9f5489b
commit 0dddc2224a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 5 deletions

View File

@ -30,7 +30,7 @@ const getPageProps = async ({ params }: { params: Record<string, string | string
};
export default async function Page({ params }: { params: Record<string, string | string[]> }) {
const { category } = await getPageProps({ params });
await getPageProps({ params });
return <LegacyPage />;
}

View File

@ -0,0 +1,81 @@
import AppsPage from "@pages/apps";
import { ssrInit } from "app/_trpc/ssrInit";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
import { getLayout } from "@calcom/features/MainLayoutAppDir";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams";
import getUserAdminTeams from "@calcom/features/ee/teams/lib/getUserAdminTeams";
import { APP_NAME } from "@calcom/lib/constants";
import type { AppCategories } from "@calcom/prisma/enums";
import PageWrapper from "@components/PageWrapperAppDir";
export const generateMetadata = async () => {
return await _generateMetadata(
() => `Apps | ${APP_NAME}`,
() => ""
);
};
const getPageProps = async () => {
const ssr = await ssrInit();
const req = { headers: headers(), cookies: cookies() };
// @ts-expect-error Type '{ headers: ReadonlyHeaders; cookies: ReadonlyRequestCookies; }' is not assignable to type 'NextApiRequest
const session = await getServerSession({ req });
let appStore, userAdminTeams: UserAdminTeams;
if (session?.user?.id) {
userAdminTeams = await getUserAdminTeams({ userId: session.user.id, getUserInfo: true });
appStore = await getAppRegistryWithCredentials(session.user.id, userAdminTeams);
} else {
appStore = await getAppRegistry();
userAdminTeams = [];
}
const categoryQuery = appStore.map(({ categories }) => ({
categories: categories || [],
}));
const categories = categoryQuery.reduce((c, app) => {
for (const category of app.categories) {
c[category] = c[category] ? c[category] + 1 : 1;
}
return c;
}, {} as Record<string, number>);
return {
categories: Object.entries(categories)
.map(([name, count]): { name: AppCategories; count: number } => ({
name: name as AppCategories,
count,
}))
.sort(function (a, b) {
return b.count - a.count;
}),
appStore,
userAdminTeams,
dehydratedState: await ssr.dehydrate(),
};
};
export default async function AppPageAppDir() {
const { categories, appStore, userAdminTeams, dehydratedState } = await getPageProps();
const h = headers();
const nonce = h.get("x-nonce") ?? undefined;
return (
<PageWrapper
getLayout={getLayout}
requiresLicense={false}
nonce={nonce}
themeBasis={null}
dehydratedState={dehydratedState}>
<AppsPage categories={categories} appStore={appStore} userAdminTeams={userAdminTeams} />
</PageWrapper>
);
}

View File

@ -1,3 +1,5 @@
"use client";
import type { GetServerSidePropsContext } from "next";
import type { ChangeEventHandler } from "react";
import { useState } from "react";
@ -64,7 +66,7 @@ export default function Apps({
categories,
appStore,
userAdminTeams,
}: inferSSRProps<typeof getServerSideProps>) {
}: Omit<inferSSRProps<typeof getServerSideProps>, "trpcState">) {
const { t } = useLocale();
const [searchText, setSearchText] = useState<string | undefined>(undefined);

View File

@ -8,6 +8,33 @@ test.describe.configure({ mode: "parallel" });
test.afterEach(({ users }) => users.deleteAll());
test.describe("App Store - Authed", () => {
test("should point to the /future/apps/", async ({ page, users, context }) => {
await context.addCookies([
{
name: "x-calcom-future-routes-override",
value: "1",
url: "http://localhost:3000",
},
]);
const user = await users.create();
await user.apiLogin();
await page.goto("/apps/");
await page.waitForLoadState();
const dataNextJsRouter = await page.evaluate(() =>
window.document.documentElement.getAttribute("data-nextjs-router")
);
expect(dataNextJsRouter).toEqual("app");
const locator = page.getByRole("heading", { name: "App Store" });
await expect(locator).toBeVisible();
});
test("Browse apple-calendar and try to install", async ({ page, users }) => {
const pro = await users.create();
await pro.apiLogin();

View File

@ -270,6 +270,9 @@ test.describe("Teams - NonOrg", () => {
await page.goto(`/settings/teams/${team.id}/members`);
await page.click("[data-testid=make-team-private-check]");
await expect(page.locator(`[data-testid=make-team-private-check][data-state="checked"]`)).toBeVisible();
// according to switch implementation, checked state can be set before mutation is resolved
// so we need to await for req to resolve
await page.waitForResponse((res) => res.url().includes("/api/trpc/teams/update"));
// Go to Team's page
await page.goto(`/team/${team.slug}`);
@ -325,15 +328,19 @@ test.describe("Teams - Org", () => {
await page.locator('[placeholder="email\\@example\\.com"]').fill(inviteeEmail);
await page.getByTestId("invite-new-member-button").click();
await expect(page.locator(`li:has-text("${inviteeEmail}")`)).toBeVisible();
expect(await page.getByTestId("pending-member-item").count()).toBe(2);
// locator.count() does not await for the expected number of elements
// https://github.com/microsoft/playwright/issues/14278
// using toHaveCount() is more reliable
await expect(page.getByTestId("pending-member-item")).toHaveCount(2);
});
await test.step("Can remove members", async () => {
expect(await page.getByTestId("pending-member-item").count()).toBe(2);
await expect(page.getByTestId("pending-member-item")).toHaveCount(2);
const lastRemoveMemberButton = page.getByTestId("remove-member-button").last();
await lastRemoveMemberButton.click();
await page.waitForLoadState("networkidle");
expect(await page.getByTestId("pending-member-item").count()).toBe(1);
await expect(page.getByTestId("pending-member-item")).toHaveCount(1);
// Cleanup here since this user is created without our fixtures.
await prisma.user.delete({ where: { email: inviteeEmail } });