From 75589db569fa5fe5d158e76f153d1304de08dc3e Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Tue, 4 Oct 2022 00:33:47 +0530 Subject: [PATCH 01/24] Hotfix: Fix Broken webhooks (#4807) --- packages/features/webhooks/components/WebhookForm.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/features/webhooks/components/WebhookForm.tsx b/packages/features/webhooks/components/WebhookForm.tsx index c9ab8476d5..3b6404b308 100644 --- a/packages/features/webhooks/components/WebhookForm.tsx +++ b/packages/features/webhooks/components/WebhookForm.tsx @@ -53,7 +53,9 @@ const WebhookForm = (props: { const triggerOptions = [...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2["core"]]; if (apps) { for (const app of apps) { - triggerOptions.push(...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]); + if (WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]) { + triggerOptions.push(...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]); + } } } const translatedTriggerOptions = triggerOptions.map((option) => ({ ...option, label: t(option.label) })); From 4438ca2a6341dca876272ab5ba33ff8cfd95e830 Mon Sep 17 00:00:00 2001 From: Jeroen Reumkens Date: Mon, 3 Oct 2022 21:52:57 +0200 Subject: [PATCH 02/24] Improve password peek positioning accross app and website. (#4810) --- packages/ui/v2/core/form/fields.tsx | 49 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/ui/v2/core/form/fields.tsx b/packages/ui/v2/core/form/fields.tsx index 0c2d9c6914..dc8fb3d8b7 100644 --- a/packages/ui/v2/core/form/fields.tsx +++ b/packages/ui/v2/core/form/fields.tsx @@ -202,12 +202,12 @@ const InputField = forwardRef(function InputF {addOnLeading || addOnSuffix ? (
(funct props, ref ) { - /*const { t } = useLocale(); + const { t } = useLocale(); const [isPasswordVisible, setIsPasswordVisible] = useState(false); const toggleIsPasswordVisible = useCallback( () => setIsPasswordVisible(!isPasswordVisible), [isPasswordVisible, setIsPasswordVisible] ); const textLabel = isPasswordVisible ? t("hide_password") : t("show_password"); -*/ + return ( -
+
+ + + } /> - - {/* - - */}
); }); From 369d7c4e28f6c011a69c760d050b9bfe478d26ca Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Tue, 4 Oct 2022 11:02:28 +0200 Subject: [PATCH 03/24] adds custom filter allowing eml format (#4815) --- packages/lib/CalendarService.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/lib/CalendarService.ts b/packages/lib/CalendarService.ts index 392610a836..5212d1b18e 100644 --- a/packages/lib/CalendarService.ts +++ b/packages/lib/CalendarService.ts @@ -221,6 +221,20 @@ export default abstract class BaseCalendarService implements Calendar { } } + isValidFormat = (url: string): boolean => { + const acceptedFormats = ["eml", "ics"]; + const urlFormat = url.split(".").pop(); + if (urlFormat === undefined) { + console.error("Invalid request, calendar object extension missing"); + return false; + } + if (!acceptedFormats.includes(urlFormat)) { + console.error(`Unsupported calendar object format: ${urlFormat}`); + return false; + } + return true; + }; + async getAvailability( dateFrom: string, dateTo: string, @@ -232,6 +246,7 @@ export default abstract class BaseCalendarService implements Calendar { .filter((sc) => ["caldav_calendar", "apple_calendar"].includes(sc.integration ?? "")) .map((sc) => fetchCalendarObjects({ + urlFilter: (url: string) => this.isValidFormat(url), calendar: { url: sc.externalId, }, From ae929f27b0e140327685c8abdff75d68f464315d Mon Sep 17 00:00:00 2001 From: GitStart <1501599+gitstart@users.noreply.github.com> Date: Tue, 4 Oct 2022 14:17:30 +0500 Subject: [PATCH 04/24] /workflows /detail-view - unusual scroll behaviour (#4806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: gitstart Co-authored-by: Júlio Piubello da Silva Cabral Co-authored-by: Nitesh Singh Co-authored-by: C000Ldude Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com> Co-authored-by: Grace Nshokano Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com> Co-authored-by: Thiago Nascimbeni Co-authored-by: Peer Richelsen Co-authored-by: Bailey Pumfleet --- .../ee/workflows/components/v2/WorkflowDetailsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/features/ee/workflows/components/v2/WorkflowDetailsPage.tsx b/packages/features/ee/workflows/components/v2/WorkflowDetailsPage.tsx index 21586ead4e..d743e16566 100644 --- a/packages/features/ee/workflows/components/v2/WorkflowDetailsPage.tsx +++ b/packages/features/ee/workflows/components/v2/WorkflowDetailsPage.tsx @@ -80,7 +80,7 @@ export default function WorkflowDetailsPage(props: Props) { return ( <>
-
+
@@ -116,7 +116,7 @@ export default function WorkflowDetailsPage(props: Props) {
{/* Workflow Trigger Event & Steps */} -
+
{form.getValues("trigger") && (
From d241a522fb63e509d00e6fcc58dc2d6060ddb812 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Tue, 4 Oct 2022 05:20:21 -0400 Subject: [PATCH 05/24] Add placeholder (#4803) Co-authored-by: Bailey Pumfleet --- packages/ui/v2/core/form/fields.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/v2/core/form/fields.tsx b/packages/ui/v2/core/form/fields.tsx index dc8fb3d8b7..16314158ba 100644 --- a/packages/ui/v2/core/form/fields.tsx +++ b/packages/ui/v2/core/form/fields.tsx @@ -262,7 +262,7 @@ export const PasswordField = forwardRef(funct
Date: Tue, 4 Oct 2022 10:31:13 +0100 Subject: [PATCH 06/24] new button in logout (#4816) Co-authored-by: Bailey Pumfleet --- apps/web/pages/auth/logout.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/web/pages/auth/logout.tsx b/apps/web/pages/auth/logout.tsx index 42bc9babec..5eac3b48c0 100644 --- a/apps/web/pages/auth/logout.tsx +++ b/apps/web/pages/auth/logout.tsx @@ -1,17 +1,16 @@ import { GetServerSidePropsContext } from "next"; import { signOut, useSession } from "next-auth/react"; -import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect } from "react"; import { WEBSITE_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import Button from "@calcom/ui/Button"; import { Icon } from "@calcom/ui/Icon"; +import Button from "@calcom/ui/v2/core/Button"; import { inferSSRProps } from "@lib/types/inferSSRProps"; -import AuthContainer from "@components/ui/AuthContainer"; +import AuthContainer from "@components/v2/ui/AuthContainer"; import { ssrInit } from "@server/lib/ssr"; @@ -30,7 +29,7 @@ export default function Logout(props: Props) { const { t } = useLocale(); return ( - +
@@ -44,9 +43,9 @@ export default function Logout(props: Props) {
- - - + ); } From e7ed20ea27baadc3140a2cbf829650bdcef9057a Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Tue, 4 Oct 2022 13:43:49 +0100 Subject: [PATCH 07/24] fixed border on dark mode success (#4823) --- apps/web/pages/v2/success.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/pages/v2/success.tsx b/apps/web/pages/v2/success.tsx index fb0d39852b..b851f6cce9 100644 --- a/apps/web/pages/v2/success.tsx +++ b/apps/web/pages/v2/success.tsx @@ -263,7 +263,7 @@ export default function Success(props: SuccessProps) { {userIsOwner && !isEmbed && (
- + {t("back_to_bookings")} @@ -411,7 +411,7 @@ export default function Success(props: SuccessProps) { !isCancelled && (!isCancellationMode ? ( <> -
+
{t("need_to_make_a_change")} @@ -448,7 +448,7 @@ export default function Success(props: SuccessProps) { ))} {userIsOwner && !needsConfirmation && !isCancellationMode && !isCancelled && ( <> -
+
{t("add_to_calendar")} From d43d8700d0568aad43f6536fbe2371f7d077c5ef Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Tue, 4 Oct 2022 15:01:32 +0100 Subject: [PATCH 08/24] Fixes global console error (#4825) --- packages/trpc/server/routers/viewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/trpc/server/routers/viewer.tsx b/packages/trpc/server/routers/viewer.tsx index a279ac6e97..2d1abea80a 100644 --- a/packages/trpc/server/routers/viewer.tsx +++ b/packages/trpc/server/routers/viewer.tsx @@ -764,7 +764,7 @@ const loggedInViewerRouter = createProtectedRouter() const apps = getApps(credentials); const appFromDb = apps.find((app) => app.credential?.appId === appId); if (!appFromDb) { - return appFromDb; + return null; } // eslint-disable-next-line @typescript-eslint/no-unused-vars const { credential: _, credentials: _1, ...app } = appFromDb; From 62fea25eb911377eba042abbfc20b629f842eb2d Mon Sep 17 00:00:00 2001 From: alannnc Date: Tue, 4 Oct 2022 16:56:38 +0200 Subject: [PATCH 09/24] fix/connected calendar list different states (#4821) * Display error if trpc query failed, catch error on getting calendar and cleanup to don't leak credentials to client * Add calendar connection broke error * Edit style on alert and disconnecting button * Ts errors and added translation * Type fix * Key and text change for broken calendar connection Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Alex van Andel --- .../v2/settings/my-account/calendars.tsx | 44 ++++++++- apps/web/public/static/locales/en/common.json | 11 ++- packages/core/CalendarManager.ts | 93 +++++++++++++------ 3 files changed, 115 insertions(+), 33 deletions(-) diff --git a/apps/web/pages/v2/settings/my-account/calendars.tsx b/apps/web/pages/v2/settings/my-account/calendars.tsx index cd1e173cb3..84b64e5aa3 100644 --- a/apps/web/pages/v2/settings/my-account/calendars.tsx +++ b/apps/web/pages/v2/settings/my-account/calendars.tsx @@ -7,6 +7,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Icon } from "@calcom/ui"; +import { Alert } from "@calcom/ui/v2"; import Badge from "@calcom/ui/v2/core/Badge"; import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen"; import Meta from "@calcom/ui/v2/core/Meta"; @@ -23,7 +24,7 @@ import { CalendarSwitch } from "@components/v2/settings/CalendarSwitch"; const SkeletonLoader = () => { return ( -
+
@@ -89,7 +90,30 @@ const CalendarsView = () => { {data.connectedCalendars.map((item) => ( - {item.calendars && ( + {item.error && item.error.message && ( + + {/* @TODO: add a reconnect button, that calls add api and delete old credential */} + query.refetch()} + buttonProps={{ + className: "border border-gray-300 py-[2px]", + color: "secondary", + }} + /> + + } + /> + )} + {item?.error === undefined && item.calendars && (
{ @@ -154,6 +178,22 @@ const CalendarsView = () => { /> ); }} + error={() => { + return ( + + An error ocurred while fetching your Calendars. + query.refetch()}> + try again + + . + + } + severity="error" + /> + ); + }} /> ); diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 919bb51d56..cfdfdc7295 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -1253,9 +1253,9 @@ "create_first_api_key_description": "API keys allow other apps to communicate with Cal.com", "back_to_signin": "Back to sign in", "reset_link_sent": "Reset link sent", - "password_reset_email":"An email is on it’s way to {{email}} with instructions to reset your password.", - "password_reset_leading":"If you don't receive an email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.", - "password_updated":"Password updated!", + "password_reset_email": "An email is on it’s way to {{email}} with instructions to reset your password.", + "password_reset_leading": "If you don't receive an email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.", + "password_updated": "Password updated!", "pending_payment": "Pending payment", "confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.", "not_on_cal": "Not on Cal.com", @@ -1272,5 +1272,8 @@ "format": "Format", "uppercase_for_letters": "Use uppercase for all letters", "replace_whitespaces_underscores": "Replace whitespaces with underscores", - "ignore_special_characters": "Ignore special characters in your Additonal Input label. Use only letters and numbers" + "ignore_special_characters": "Ignore special characters in your Additional Input label. Use only letters and numbers", + "retry": "Retry", + "fetching_calendars_error": "There was a problem fetching your calendars. Please <1>try again or reach out to customer support.", + "calendar_connection_fail": "Calendar connection failed" } diff --git a/packages/core/CalendarManager.ts b/packages/core/CalendarManager.ts index e4db1f9b81..d47a536d81 100644 --- a/packages/core/CalendarManager.ts +++ b/packages/core/CalendarManager.ts @@ -8,6 +8,7 @@ import getApps from "@calcom/app-store/utils"; import { getUid } from "@calcom/lib/CalEventParser"; import logger from "@calcom/lib/logger"; import { performance } from "@calcom/lib/server/perfObserver"; +import { App } from "@calcom/types/App"; import type { CalendarEvent, EventBusyDate, NewCalendarEventType } from "@calcom/types/Calendar"; import type { EventResult } from "@calcom/types/EventManager"; @@ -33,47 +34,85 @@ export const getConnectedCalendars = async ( ) => { const connectedCalendars = await Promise.all( calendarCredentials.map(async (item) => { - const { calendar, integration, credential } = item; - const credentialId = credential.id; - if (!calendar) { + try { + const { calendar, integration, credential } = item; + + // Don't leak credentials to the client + const credentialId = credential.id; + if (!calendar) { + return { + integration, + credentialId, + }; + } + const cals = await calendar.listCalendars(); + const calendars = _(cals) + .map((cal) => ({ + ...cal, + readOnly: cal.readOnly || false, + primary: cal.primary || null, + isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId), + credentialId, + })) + .sortBy(["primary"]) + .value(); + const primary = calendars.find((item) => item.primary) ?? calendars.find((cal) => cal !== undefined); + if (!primary) { + return { + integration, + credentialId, + error: { + message: "No primary calendar found", + }, + }; + } + return { - integration, + integration: cleanIntegrationKeys(integration), credentialId, + primary, + calendars, }; - } - const cals = await calendar.listCalendars(); - const calendars = _(cals) - .map((cal) => ({ - ...cal, - readOnly: cal.readOnly || false, - primary: cal.primary || null, - isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId), - credentialId, - })) - .sortBy(["primary"]) - .value(); - const primary = calendars.find((item) => item.primary) ?? calendars.find((cal) => cal !== undefined); - if (!primary) { + } catch (error) { + let errorMessage = "Could not get connected calendars"; + + // Here you can expect for specific errors + if (error instanceof Error) { + if (error.message === "invalid_grant") { + errorMessage = "Access token expired or revoked"; + } + } + return { - integration, - credentialId, + integration: cleanIntegrationKeys(item.integration), + credentialId: item.credential.id, error: { - message: "No primary calendar found", + message: errorMessage, }, }; } - return { - integration, - credentialId, - primary, - calendars, - }; }) ); return connectedCalendars; }; +/** + * Important function to prevent leaking credentials to the client + * @param appIntegration + * @returns App + */ +const cleanIntegrationKeys = ( + appIntegration: ReturnType[number]["integration"] & { + credentials?: Array; + credential: Credential; + } +) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { credentials, credential, ...rest } = appIntegration; + return rest; +}; + const CACHING_TIME = 30_000; // 30 seconds const getCachedResults = async ( From 30a887df6f5cbf4ad8a30a13420fd17be67a0aa1 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Tue, 4 Oct 2022 16:37:20 +0100 Subject: [PATCH 10/24] Some tweaks to the ui - use button - use flex justify-between (#4826) --- .../getting-started/components/CalendarItem.tsx | 12 ++++++------ .../getting-started/steps-views/ConnectCalendars.tsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/components/getting-started/components/CalendarItem.tsx b/apps/web/components/getting-started/components/CalendarItem.tsx index b3662168a3..9ee3854909 100644 --- a/apps/web/components/getting-started/components/CalendarItem.tsx +++ b/apps/web/components/getting-started/components/CalendarItem.tsx @@ -14,10 +14,11 @@ const CalendarItem = (props: ICalendarItem) => { const { title, imageSrc, type } = props; const { t } = useLocale(); return ( -
- {title} -

{title}

- +
+
+ {title} +

{title}

+
( @@ -29,8 +30,7 @@ const CalendarItem = (props: ICalendarItem) => { // Save cookie key to return url step document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`; buttonProps && buttonProps.onClick && buttonProps?.onClick(event); - }} - className="ml-auto rounded-md border border-gray-200 py-[10px] px-4 text-sm font-bold"> + }}> {t("connect")} )} diff --git a/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx b/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx index 8125a9b3fb..2e33665b14 100644 --- a/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx +++ b/apps/web/components/getting-started/steps-views/ConnectCalendars.tsx @@ -76,7 +76,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => { )} - {queryConnectedCalendars.isLoading && ( + {queryIntegrations.isLoading && (