Merge branch 'main' into testE2E-timezone
This commit is contained in:
commit
c332f0bbcb
|
@ -15,3 +15,5 @@ jobs:
|
|||
- uses: ./.github/actions/yarn-install
|
||||
# Should be an 8GB machine as per https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners
|
||||
- run: yarn test
|
||||
# We could add different timezones here that we need to run our tests in
|
||||
- run: TZ=America/Los_Angeles yarn test -- --timeZoneDependentTestsOnly
|
||||
|
|
|
@ -72,6 +72,7 @@ import useMeQuery from "@lib/hooks/useMeQuery";
|
|||
|
||||
import PageWrapper from "@components/PageWrapper";
|
||||
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
|
||||
import { UserAvatarGroup } from "@components/ui/avatar/UserAvatarGroup";
|
||||
|
||||
type EventTypeGroups = RouterOutputs["viewer"]["eventTypes"]["getByViewer"]["eventTypeGroups"];
|
||||
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
||||
|
@ -398,23 +399,11 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
<div className="mt-4 hidden sm:mt-0 sm:flex">
|
||||
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
|
||||
{type.team && !isManagedEventType && (
|
||||
<AvatarGroup
|
||||
<UserAvatarGroup
|
||||
className="relative right-3 top-1"
|
||||
size="sm"
|
||||
truncateAfter={4}
|
||||
items={
|
||||
type?.users
|
||||
? type.users.map(
|
||||
(organizer: { name: string | null; username: string | null }) => ({
|
||||
alt: organizer.name || "",
|
||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
||||
organizer.username
|
||||
}/avatar.png`,
|
||||
title: organizer.name || "",
|
||||
})
|
||||
)
|
||||
: []
|
||||
}
|
||||
users={type?.users ?? []}
|
||||
/>
|
||||
)}
|
||||
{isManagedEventType && type?.children && type.children?.length > 0 && (
|
||||
|
|
|
@ -78,8 +78,8 @@ type FormValues = {
|
|||
bio: string;
|
||||
};
|
||||
|
||||
const checkIfItFallbackImage = (fetchedImgSrc: string) => {
|
||||
return fetchedImgSrc.endsWith(AVATAR_FALLBACK);
|
||||
const checkIfItFallbackImage = (fetchedImgSrc?: string) => {
|
||||
return !fetchedImgSrc || fetchedImgSrc.endsWith(AVATAR_FALLBACK);
|
||||
};
|
||||
|
||||
const ProfileView = () => {
|
||||
|
@ -226,10 +226,11 @@ const ProfileView = () => {
|
|||
[ErrorCode.ThirdPartyIdentityProviderEnabled]: t("account_created_with_identity_provider"),
|
||||
};
|
||||
|
||||
if (isLoading || !user || fetchedImgSrc === undefined)
|
||||
if (isLoading || !user) {
|
||||
return (
|
||||
<SkeletonLoader title={t("profile")} description={t("profile_description", { appName: APP_NAME })} />
|
||||
);
|
||||
}
|
||||
|
||||
const defaultValues = {
|
||||
username: user.username || "",
|
||||
|
|
|
@ -2378,6 +2378,7 @@ async function handler(
|
|||
...eventTypeInfo,
|
||||
bookingId: booking?.id,
|
||||
rescheduleUid,
|
||||
oldBookingId: originalRescheduledBooking?.id || undefined,
|
||||
rescheduleStartTime: originalRescheduledBooking?.startTime
|
||||
? dayjs(originalRescheduledBooking?.startTime).utc().format()
|
||||
: undefined,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { describe, expect, test } from "vitest";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { getAvailableDatesInMonth } from "@calcom/features/calendars/lib/getAvailableDatesInMonth";
|
||||
import { daysInMonth, yyyymmdd } from "@calcom/lib/date-fns";
|
||||
|
@ -8,7 +8,7 @@ describe("Test Suite: Date Picker", () => {
|
|||
// *) Use right amount of days in given month. (28, 30, 31)
|
||||
test("it returns the right amount of days in a given month", () => {
|
||||
const currentDate = new Date();
|
||||
const nextMonthDate = new Date(Date.UTC(currentDate.getFullYear(), currentDate.getMonth() + 1));
|
||||
const nextMonthDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1);
|
||||
|
||||
const result = getAvailableDatesInMonth({
|
||||
browsingDate: nextMonthDate,
|
||||
|
@ -35,5 +35,33 @@ describe("Test Suite: Date Picker", () => {
|
|||
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("it translates correctly regardless of system time", () => {
|
||||
{
|
||||
// test a date in negative UTC offset
|
||||
vi.useFakeTimers().setSystemTime(new Date("2023-10-24T13:27:00.000-07:00"));
|
||||
|
||||
const currentDate = new Date();
|
||||
const result = getAvailableDatesInMonth({
|
||||
browsingDate: currentDate,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(daysInMonth(currentDate) - currentDate.getDate() + 1);
|
||||
}
|
||||
{
|
||||
// test a date in positive UTC offset
|
||||
vi.useFakeTimers().setSystemTime(new Date("2023-10-24T13:27:00.000+07:00"));
|
||||
|
||||
const currentDate = new Date();
|
||||
const result = getAvailableDatesInMonth({
|
||||
browsingDate: currentDate,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(daysInMonth(currentDate) - currentDate.getDate() + 1);
|
||||
}
|
||||
// Undo the forced time we applied earlier, reset to system default.
|
||||
vi.setSystemTime(vi.getRealSystemTime());
|
||||
vi.useRealTimers();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@ import { daysInMonth, yyyymmdd } from "@calcom/lib/date-fns";
|
|||
// *) Dates in the past are not available.
|
||||
// *) Use right amount of days in given month. (28, 30, 31)
|
||||
export function getAvailableDatesInMonth({
|
||||
browsingDate, // pass as UTC
|
||||
browsingDate,
|
||||
minDate = new Date(),
|
||||
includedDates,
|
||||
}: {
|
||||
|
@ -15,12 +15,14 @@ export function getAvailableDatesInMonth({
|
|||
}) {
|
||||
const dates = [];
|
||||
const lastDateOfMonth = new Date(
|
||||
Date.UTC(browsingDate.getFullYear(), browsingDate.getMonth(), daysInMonth(browsingDate))
|
||||
browsingDate.getFullYear(),
|
||||
browsingDate.getMonth(),
|
||||
daysInMonth(browsingDate)
|
||||
);
|
||||
for (
|
||||
let date = browsingDate > minDate ? browsingDate : minDate;
|
||||
date <= lastDateOfMonth;
|
||||
date = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 1))
|
||||
date = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)
|
||||
) {
|
||||
// intersect included dates
|
||||
if (includedDates && !includedDates.includes(yyyymmdd(date))) {
|
||||
|
|
|
@ -4,10 +4,9 @@ import { getLocationGroupedOptions } from "@calcom/app-store/server";
|
|||
import type { StripeData } from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { getEventTypeAppData } from "@calcom/app-store/utils";
|
||||
import type { LocationObject } from "@calcom/core/location";
|
||||
import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains";
|
||||
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { parseBookingLimit, parseDurationLimit, parseRecurringEvent } from "@calcom/lib";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { Credential } from "@calcom/prisma/client";
|
||||
|
@ -36,6 +35,7 @@ export default async function getEventTypeById({
|
|||
username: true,
|
||||
id: true,
|
||||
email: true,
|
||||
organizationId: true,
|
||||
locale: true,
|
||||
defaultScheduleId: true,
|
||||
});
|
||||
|
@ -298,9 +298,7 @@ export default async function getEventTypeById({
|
|||
const eventTypeUsers: ((typeof eventType.users)[number] & { avatar: string })[] = eventType.users.map(
|
||||
(user) => ({
|
||||
...user,
|
||||
avatar: `${eventType.team?.parent?.slug ? getOrgFullOrigin(eventType.team?.parent?.slug) : CAL_URL}/${
|
||||
user.username
|
||||
}/avatar.png`,
|
||||
avatar: getUserAvatarUrl(user),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -346,11 +344,7 @@ export default async function getEventTypeById({
|
|||
.map((member) => {
|
||||
const user: typeof member.user & { avatar: string } = {
|
||||
...member.user,
|
||||
avatar: `${
|
||||
eventTypeObject.team?.parent?.slug
|
||||
? getOrgFullOrigin(eventTypeObject.team?.parent?.slug)
|
||||
: CAL_URL
|
||||
}/${member.user.username}/avatar.png`,
|
||||
avatar: getUserAvatarUrl(member.user),
|
||||
};
|
||||
return {
|
||||
...user,
|
||||
|
|
|
@ -30,6 +30,7 @@ const userSelect = Prisma.validator<Prisma.UserSelect>()({
|
|||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
organizationId: true,
|
||||
});
|
||||
|
||||
const userEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { isOrganisationAdmin } from "@calcom/lib/server/queries/organisations";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
|
@ -11,42 +10,12 @@ type ListOptions = {
|
|||
};
|
||||
|
||||
export const listHandler = async ({ ctx }: ListOptions) => {
|
||||
if (ctx.user?.organization?.id) {
|
||||
const membershipsWithoutParent = await prisma.membership.findMany({
|
||||
where: {
|
||||
userId: ctx.user.id,
|
||||
team: {
|
||||
parent: {
|
||||
is: {
|
||||
id: ctx.user?.organization?.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
include: {
|
||||
team: {
|
||||
include: {
|
||||
inviteTokens: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { role: "desc" },
|
||||
});
|
||||
|
||||
const isOrgAdmin = !!(await isOrganisationAdmin(ctx.user.id, ctx.user.organization.id)); // Org id exists here as we're inside a conditional TS complaining for some reason
|
||||
|
||||
return membershipsWithoutParent.map(({ team: { inviteTokens, ..._team }, ...membership }) => ({
|
||||
role: membership.role,
|
||||
accepted: membership.accepted,
|
||||
isOrgAdmin,
|
||||
..._team,
|
||||
/** To prevent breaking we only return non-email attached token here, if we have one */
|
||||
inviteToken: inviteTokens.find((token) => token.identifier === `invite-link-for-teamId-${_team.id}`),
|
||||
}));
|
||||
}
|
||||
|
||||
const memberships = await prisma.membership.findMany({
|
||||
where: {
|
||||
// Show all the teams this user belongs to regardless of the team being part of the user's org or not
|
||||
// We don't want to restrict in the listing here. If we need to restrict a situation where a user is part of the org along with being part of a non-org team, we should do that instead of filtering out from here
|
||||
// This became necessary when we started migrating user to Org, without migrating some teams of the user to the org
|
||||
// Also, we would allow a user to be part of multiple orgs, then also it would be necessary.
|
||||
userId: ctx.user.id,
|
||||
},
|
||||
include: {
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import { defineWorkspace } from "vitest/config";
|
||||
|
||||
const packagedEmbedTestsOnly = process.argv.includes("--packaged-embed-tests-only");
|
||||
const timeZoneDependentTestsOnly = process.argv.includes("--timeZoneDependentTestsOnly");
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const envTZ = process.env.TZ;
|
||||
if (timeZoneDependentTestsOnly && !envTZ) {
|
||||
throw new Error("TZ environment variable is not set");
|
||||
}
|
||||
|
||||
// defineWorkspace provides a nice type hinting DX
|
||||
const workspaces = packagedEmbedTestsOnly
|
||||
? [
|
||||
|
@ -11,6 +18,19 @@ const workspaces = packagedEmbedTestsOnly
|
|||
},
|
||||
},
|
||||
]
|
||||
: // It doesn't seem to be possible to fake timezone per test, so we rerun the entire suite with different TZ. See https://github.com/vitest-dev/vitest/issues/1575#issuecomment-1439286286
|
||||
timeZoneDependentTestsOnly
|
||||
? [
|
||||
{
|
||||
test: {
|
||||
name: `TimezoneDependentTests:${envTZ}`,
|
||||
include: ["packages/**/*.timezone.test.ts", "apps/**/*.timezone.test.ts"],
|
||||
// TODO: Ignore the api until tests are fixed
|
||||
exclude: ["**/node_modules/**/*", "packages/embeds/**/*"],
|
||||
setupFiles: ["setupVitest.ts"],
|
||||
},
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
test: {
|
||||
|
@ -20,6 +40,7 @@ const workspaces = packagedEmbedTestsOnly
|
|||
setupFiles: ["setupVitest.ts"],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
test: {
|
||||
name: "@calcom/closecom",
|
||||
|
|
Loading…
Reference in New Issue
Block a user