Merge branch 'main' into chore/revert-appDir-2

This commit is contained in:
Peer Richelsen 2023-12-22 19:45:01 +00:00 committed by GitHub
commit a49323f599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 78 additions and 25 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "3.6.0",
"version": "3.6.1",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",

View File

@ -6,6 +6,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getDefaultEvent } from "@calcom/lib/defaultEvents";
import { maybeGetBookingUidFromSeat } from "@calcom/lib/server/maybeGetBookingUidFromSeat";
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import { BookingStatus } from "@calcom/prisma/client";
export default function Type() {
// Just redirect to the schedule page to reschedule it.
@ -63,6 +64,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
dynamicEventSlugRef: true,
dynamicGroupSlugRef: true,
user: true,
status: true,
},
});
const dynamicEventSlugRef = booking?.dynamicEventSlugRef || "";
@ -73,6 +75,17 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
} as const;
}
// If booking is already CANCELLED or REJECTED, we can't reschedule this booking. Take the user to the booking page which would show it's correct status and other details.
// A booking that has been rescheduled to a new booking will also have a status of CANCELLED
if (booking.status === BookingStatus.CANCELLED || booking.status === BookingStatus.REJECTED) {
return {
redirect: {
destination: `/booking/${uid}`,
permanent: false,
},
};
}
if (!booking?.eventType && !booking?.dynamicEventSlugRef) {
// TODO: Show something in UI to let user know that this booking is not rescheduleable
return {

View File

@ -126,6 +126,34 @@ test.describe("pro user", () => {
await bookFirstEvent(page);
});
test("Can cancel the recently created booking and shouldn't be allowed to reschedule it", async ({
page,
users,
}, testInfo) => {
// Because it tests the entire booking flow + the cancellation + rebooking
test.setTimeout(testInfo.timeout * 3);
await bookFirstEvent(page);
await expect(page.locator(`[data-testid="attendee-email-${testEmail}"]`)).toHaveText(testEmail);
await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
const [pro] = users.get();
await pro.apiLogin();
await page.goto("/bookings/upcoming");
await page.locator('[data-testid="cancel"]').click();
await page.waitForURL((url) => {
return url.pathname.startsWith("/booking/");
});
await page.locator('[data-testid="confirm_cancel"]').click();
const cancelledHeadline = page.locator('[data-testid="cancelled-headline"]');
await expect(cancelledHeadline).toBeVisible();
const bookingCancelledId = new URL(page.url()).pathname.split("/booking/")[1];
await page.goto(`/reschedule/${bookingCancelledId}`);
// Should be redirected to the booking details page which shows the cancelled headline
await expect(page.locator('[data-testid="cancelled-headline"]')).toBeVisible();
});
test("can book an event that requires confirmation and then that booking can be accepted by organizer", async ({
page,
users,

View File

@ -535,7 +535,8 @@ type CustomUserOptsKeys =
| "locale"
| "name"
| "email"
| "organizationId";
| "organizationId"
| "role";
type CustomUserOpts = Partial<Pick<Prisma.User, CustomUserOptsKeys>> & {
timeZone?: TimeZoneEnum;
eventTypes?: SupportedTestEventTypes[];
@ -565,6 +566,7 @@ const createUser = (
completedOnboarding: opts?.completedOnboarding ?? true,
timeZone: opts?.timeZone ?? TimeZoneEnum.UK,
locale: opts?.locale ?? "en",
role: opts?.role ?? "USER",
...getOrganizationRelatedProps({ organizationId: opts?.organizationId, role: opts?.roleInOrganization }),
schedules:
opts?.completedOnboarding ?? true

View File

@ -354,6 +354,6 @@ export async function doOnOrgDomain(
await callback({ page });
}
// When App directory is there, this is the 404 page text. It is commented till it's disabled
// export const NotFoundPageText = "This page could not be found";
export const NotFoundPageText = "ERROR 404";
// When App directory is there, this is the 404 page text. We should work on fixing the 404 page as it changed due to app directory.
export const NotFoundPageText = "This page could not be found";
// export const NotFoundPageText = "ERROR 404";

View File

@ -18,12 +18,14 @@ function capitalize(text: string) {
}
test.describe("Organization", () => {
test("should be able to create an organization and complete onboarding", async ({
test("Admin should be able to create an organization and complete onboarding", async ({
page,
users,
emails,
}) => {
const orgOwner = await users.create();
const orgOwner = await users.create({
role: "ADMIN",
});
const orgDomain = `${orgOwner.username}-org`;
const orgName = capitalize(`${orgOwner.username}-org`);
await orgOwner.apiLogin();

View File

@ -13,7 +13,9 @@ test.describe("Settings/admin A/B tests", () => {
url: "http://localhost:3000",
},
]);
const user = await users.create();
const user = await users.create({
role: "ADMIN",
});
await user.apiLogin();
await page.goto("/settings/admin");

View File

@ -109,10 +109,6 @@
background: var(--cal-brand);
}
html {
scrollbar-gutter: stable;
}
body  {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;

View File

@ -13,7 +13,9 @@ import GoogleCalendarService from "../lib/CalendarService";
import { createBookingAndFetchGCalEvent, deleteBookingAndEvent, assertValueExists } from "./testUtils";
test.describe("Google Calendar", async () => {
test.describe("Test using the primary calendar", async () => {
// Skip till the tests are flaky
// eslint-disable-next-line playwright/no-skipped-test
test.describe.skip("Test using the primary calendar", async () => {
let qaUsername: string;
let qaGCalCredential: CredentialPayload;
test.beforeAll(async () => {

View File

@ -232,6 +232,12 @@ const providers: Provider[] = [
if (role !== "ADMIN") return role;
// User's identity provider is not "CAL"
if (user.identityProvider !== IdentityProvider.CAL) return role;
if (process.env.NEXT_PUBLIC_IS_E2E) {
console.warn("E2E testing is enabled, skipping password and 2FA requirements for Admin");
return role;
}
// User's password is valid and two-factor authentication is enabled
if (isPasswordValid(credentials.password, false, true) && user.twoFactorEnabled) return role;
// Code is running in a development environment

View File

@ -383,7 +383,7 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
try {
// Required for Safari but also works on Chrome
// Credits to https://wolfgangrittner.dev/how-to-use-clipboard-api-in-firefox/
if (typeof ClipboardItem) {
if (typeof ClipboardItem !== "undefined") {
const inviteLinkClipbardItem = new ClipboardItem({
"text/plain": new Promise(async (resolve) => {
// Instead of doing async work and then writing to clipboard, do async work in clipboard API itself

View File

@ -199,17 +199,19 @@ export default function MemberListItem(props: Props) {
StartIcon={Clock}
/>
</Tooltip> */}
<Tooltip content={t("view_public_page")}>
<Button
target="_blank"
href={`${bookerUrl}/${props.member.username}`}
color="secondary"
className={classNames(!editMode ? "rounded-r-md" : "")}
variant="icon"
StartIcon={ExternalLink}
disabled={!props.member.accepted}
/>
</Tooltip>
{!!props.member.accepted && (
<Tooltip content={t("view_public_page")}>
<Button
target="_blank"
href={`${bookerUrl}/${props.member.username}`}
color="secondary"
className={classNames(!editMode ? "rounded-r-md" : "")}
variant="icon"
StartIcon={ExternalLink}
disabled={!props.member.accepted}
/>
</Tooltip>
)}
{editMode && (
<Dropdown>
<DropdownMenuTrigger asChild>