Installed Apps page revamp (#2751)

* First round of changes

* Some missing styling

* Last round of core changes

* Color tweaks

* Improving code readability

* Reverting unneeded changes

* Reverting yarn.lock

* Removing yarn.lock

* Empty state updated

* Fixing webhook test

* Cleaning up code

* Fixing test and simplifying code a bit

* Merging API Keys into developer section

* Unifying Empty Screen with monorepo version

* Cleaning up

* Installed apps logic consistency + cleaning up

* Type fixes

* Apply suggestions from code review

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>

* Improvements, still WIP

* Update apps/web/pages/apps/installed.tsx

Co-authored-by: Omar López <zomars@me.com>

* Apply suggestions from code review

Co-authored-by: Omar López <zomars@me.com>

* App active install status

* Apple Calendar setup, Daily.co preinstalled

* Final pass

* Minor tweaks

* Conflicts with migration ignored

* Fixing merge

* Fixing merge yet again

* Adopting main changes

* Removing unneeded data-testid

* Fixing reported bugs

* Simplifying webhook query

* Moving teams settings tab to second

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Leo Giovanetti 2022-06-01 14:24:41 -03:00 committed by GitHub
parent 6179b0cc56
commit 33a45a8af5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 605 additions and 894 deletions

View File

@ -0,0 +1,76 @@
import React from "react";
import Select from "react-select";
import { OptionProps } from "react-select";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { App } from "@calcom/types/App";
import { Button } from "@calcom/ui";
import { QueryCell } from "@lib/QueryCell";
import { trpc } from "@lib/trpc";
interface AdditionalCalendarSelectorProps {
isLoading?: boolean;
}
const ImageOption = (optionProps: OptionProps<{ [key: string]: string; type: App["type"] }>) => {
const { data } = optionProps;
return (
<InstallAppButton
type={data.type}
render={(installProps) => {
return (
<Button {...installProps} className="w-full" color="minimal">
{/* eslint-disable @next/next/no-img-element */}
{data.image && (
<img className="float-left mr-3 inline h-5 w-5" src={data.image} alt={data.label} />
)}
<p>{data.label}</p>
</Button>
);
}}
/>
);
};
const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorProps): JSX.Element | null => {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations", { variant: "calendar", onlyInstalled: true }]);
return (
<QueryCell
query={query}
success={({ data }) => {
const options = data.items.map((item) => ({
label: item.name,
slug: item.slug,
image: item.imageSrc,
type: item.type,
}));
return (
<Select
name={"additionalCalendar"}
placeholder={t("connect_additional_calendar")}
options={options}
styles={{
placeholder: (defaultStyles) => {
return {
...defaultStyles,
color: "#3E3E3E",
marginLeft: "3px",
};
},
}}
isSearchable={false}
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 font-medium text-gray-700 sm:text-sm"
isLoading={isLoading}
components={{ Option: ImageOption }}
/>
);
}}
/>
);
};
export default AdditionalCalendarSelector;

View File

@ -5,6 +5,8 @@ import {
FlagIcon,
MailIcon,
ShieldCheckIcon,
PlusIcon,
CheckIcon,
} from "@heroicons/react/outline";
import { ChevronLeftIcon } from "@heroicons/react/solid";
import Link from "next/link";
@ -13,7 +15,7 @@ import React, { useEffect, useState } from "react";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { App as AppType } from "@calcom/types/App";
import { Button } from "@calcom/ui";
import { Button, SkeletonButton } from "@calcom/ui";
import Shell from "@components/Shell";
import Badge from "@components/ui/Badge";
@ -59,7 +61,8 @@ export default function App({
currency: "USD",
useGrouping: false,
}).format(price);
const [installedApp, setInstalledApp] = useState(false);
const [installedApp, setInstalledApp] = useState(0);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function getInstalledApp(appCredentialType: string) {
const queryParam = new URLSearchParams();
@ -70,9 +73,13 @@ export default function App({
headers: {
"Content-Type": "application/json",
},
}).then((data) => {
setIsLoading(false);
return data;
});
if (result.status === 200) {
setInstalledApp(true);
const res = await result.json();
setInstalledApp(res.count);
}
} catch (error) {
if (error instanceof Error) {
@ -107,19 +114,35 @@ export default function App({
</div>
<div className="mt-4 sm:mt-0 sm:text-right">
{isGlobal || installedApp ? (
<Button color="secondary" disabled title="This app is globally installed">
{t("installed")}
</Button>
) : (
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button data-testid="install-app-button" {...buttonProps}>
{t("install_app")}
{!isLoading ? (
isGlobal || installedApp > 0 ? (
<div className="space-x-3">
<Button StartIcon={CheckIcon} color="secondary" disabled>
{installedApp > 0
? t("active_install", { count: installedApp })
: t("globally_install")}
</Button>
)}
/>
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button StartIcon={PlusIcon} data-testid="install-app-button" {...buttonProps}>
{t("add_another")}
</Button>
)}
/>
</div>
) : (
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button data-testid="install-app-button" {...buttonProps}>
{t("install_app")}
</Button>
)}
/>
)
) : (
<SkeletonButton width="24" height="10" />
)}
{price !== 0 && (
<small className="block text-right">

View File

@ -1,9 +1,9 @@
import classNames from "classnames";
import React, { useEffect, useState } from "react";
import Select from "react-select";
import Button from "@calcom/ui/Button";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
interface Props {
@ -24,6 +24,22 @@ const DestinationCalendarSelector = ({
const query = trpc.useQuery(["viewer.connectedCalendars"]);
const [selectedOption, setSelectedOption] = useState<{ value: string; label: string } | null>(null);
// Extra styles to show prefixed text in react-select
const content = (hidePlaceholder = false) => {
if (!hidePlaceholder) {
return {
alignItems: "center",
display: "flex",
":before": {
content: `'${t("select_destination_calendar")}:'`,
display: "block",
marginRight: 8,
},
};
}
return {};
};
useEffect(() => {
const selected = query.data?.connectedCalendars
.map((connected) => connected.calendars ?? [])
@ -52,23 +68,29 @@ const DestinationCalendarSelector = ({
})) ?? [];
return (
<div className="relative" title={`${t("select_destination_calendar")}: ${selectedOption?.label || ""}`}>
{/* There's no easy way to customize the displayed value for a Select, so we fake it. */}
{!hidePlaceholder && (
<div className="pointer-events-none absolute z-10 w-full">
<Button
size="sm"
color="secondary"
className="m-[1px] w-[calc(100%_-_40px)] overflow-hidden overflow-ellipsis whitespace-nowrap rounded-sm border-none leading-5">
{t("select_destination_calendar")}: {selectedOption?.label || ""}
</Button>
</div>
)}
<Select
name={"primarySelectedCalendar"}
placeholder={!hidePlaceholder ? `${t("select_destination_calendar")}:` : undefined}
options={options}
styles={{
placeholder: (styles) => ({ ...styles, ...content(hidePlaceholder) }),
singleValue: (styles) => ({ ...styles, ...content(hidePlaceholder) }),
option: (defaultStyles, state) => ({
...defaultStyles,
backgroundColor: state.isSelected
? state.isFocused
? "var(--brand-color)"
: "var(--brand-color)"
: state.isFocused
? "var(--brand-color-dark-mode)"
: "var(--brand-text-color)",
}),
}}
isSearchable={false}
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 sm:text-sm"
className={classNames(
"mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 sm:text-sm",
!hidePlaceholder && "font-medium"
)}
onChange={(option) => {
setSelectedOption(option);
if (!option) {

View File

@ -1,27 +0,0 @@
import React from "react";
import { SVGComponent } from "@lib/types/SVGComponent";
export default function EmptyScreen({
Icon,
headline,
description,
}: {
Icon: SVGComponent;
headline: string;
description: string | React.ReactElement;
}) {
return (
<>
<div className="min-h-80 my-6 flex flex-col items-center justify-center rounded-sm border border-dashed">
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
<Icon className="inline-block h-10 w-10 text-white dark:bg-white dark:text-gray-600" />
</div>
<div className="max-w-[420px] text-center">
<h2 className="mt-6 mb-1 text-lg font-medium dark:text-gray-300">{headline}</h2>
<p className="text-sm leading-6 text-gray-600 dark:text-gray-300">{description}</p>
</div>
</div>
</>
);
}

View File

@ -1,4 +1,11 @@
import { CreditCardIcon, KeyIcon, LockClosedIcon, UserGroupIcon, UserIcon } from "@heroicons/react/solid";
import {
CreditCardIcon,
KeyIcon,
LockClosedIcon,
UserGroupIcon,
UserIcon,
CodeIcon,
} from "@heroicons/react/solid";
import React, { ComponentProps } from "react";
import ErrorBoundary from "@lib/ErrorBoundary";
@ -12,15 +19,20 @@ const tabs = [
href: "/settings/profile",
icon: UserIcon,
},
{
name: "teams",
href: "/settings/teams",
icon: UserGroupIcon,
},
{
name: "security",
href: "/settings/security",
icon: KeyIcon,
},
{
name: "teams",
href: "/settings/teams",
icon: UserGroupIcon,
name: "developer",
href: "/settings/developer",
icon: CodeIcon,
},
{
name: "billing",

View File

@ -4,10 +4,10 @@ import { SkeletonText } from "@calcom/ui";
import { ShellSubHeading } from "@components/Shell";
function SkeletonLoader() {
function SkeletonLoader({ className }: { className?: string }) {
return (
<>
<ShellSubHeading title={<div className="h-6 w-32 rounded-sm bg-gray-100"></div>} />
<ShellSubHeading title={<div className="h-6 w-32 rounded-sm bg-gray-100"></div>} {...{ className }} />
<ul className="-mx-4 animate-pulse divide-y divide-neutral-200 rounded-sm border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />

View File

@ -1,19 +1,20 @@
import { Fragment } from "react";
import { useMutation } from "react-query";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import Switch from "@calcom/ui/Switch";
import { QueryCell } from "@lib/QueryCell";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
import AdditionalCalendarSelector from "@components/AdditionalCalendarSelector";
import DestinationCalendarSelector from "@components/DestinationCalendarSelector";
import { List } from "@components/List";
import { ShellSubHeading } from "@components/Shell";
import SkeletonLoader from "@components/apps/SkeletonLoader";
import DisconnectIntegration from "./DisconnectIntegration";
import IntegrationListItem from "./IntegrationListItem";
@ -163,40 +164,6 @@ function ConnectedCalendarsList(props: Props) {
);
}
function CalendarList(props: Props) {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations"]);
return (
<QueryCell
query={query}
success={({ data }) => (
<List>
{data.calendar.items.map((item) => (
<IntegrationListItem
key={item.title}
title={item.title}
imageSrc={item.imageSrc}
description={item.description}
actions={
<InstallAppButton
type={item.type}
render={(buttonProps) => (
<Button color="secondary" {...buttonProps}>
{t("connect")}
</Button>
)}
onChanged={() => props.onChanged()}
/>
}
/>
))}
</List>
)}
/>
);
}
export function CalendarListContainer(props: { heading?: false }) {
const { t } = useLocale();
const { heading = true } = props;
@ -207,39 +174,54 @@ export function CalendarListContainer(props: { heading?: false }) {
utils.invalidateQueries(["viewer.connectedCalendars"]),
]);
const query = trpc.useQuery(["viewer.connectedCalendars"]);
const installedCalendars = trpc.useQuery([
"viewer.integrations",
{ variant: "calendar", onlyInstalled: true },
]);
const mutation = trpc.useMutation("viewer.setDestinationCalendar");
return (
<>
{heading && (
<ShellSubHeading
className="mt-10 mb-0"
title={
<SubHeadingTitleWithConnections
title="Calendars"
numConnections={query.data?.connectedCalendars.length}
/>
}
subtitle={t("configure_how_your_event_types_interact")}
actions={
<div className="sm:min-w-80 block max-w-full">
<DestinationCalendarSelector
onChange={mutation.mutate}
isLoading={mutation.isLoading}
value={query.data?.destinationCalendar?.externalId}
/>
</div>
}
/>
)}
<ConnectedCalendarsList onChanged={onChanged} />
{!!query.data?.connectedCalendars.length && (
<ShellSubHeading
className="mt-6"
title={<SubHeadingTitleWithConnections title={t("connect_an_additional_calendar")} />}
/>
)}
<CalendarList onChanged={onChanged} />
</>
<QueryCell
query={query}
customLoader={<SkeletonLoader className="mt-10" />}
success={({ data }) => {
return (
<>
{(!!data.connectedCalendars.length || !!installedCalendars.data?.items.length) && (
<>
{heading && (
<ShellSubHeading
className="mt-10 mb-0"
title={
<SubHeadingTitleWithConnections
title="Calendars"
numConnections={data.connectedCalendars.length}
/>
}
subtitle={t("configure_how_your_event_types_interact")}
actions={
<div className="flex flex-col xl:flex-row xl:space-x-5">
<div className="sm:min-w-80 block max-w-full">
<DestinationCalendarSelector
onChange={mutation.mutate}
isLoading={mutation.isLoading}
value={data.destinationCalendar?.externalId}
/>
</div>
{!!data.connectedCalendars.length && (
<div className="sm:min-w-80 inline max-w-full">
<AdditionalCalendarSelector isLoading={mutation.isLoading} />
</div>
)}
</div>
}
/>
)}
<ConnectedCalendarsList onChanged={onChanged} />
</>
)}
</>
);
}}
/>
);
}

View File

@ -1,16 +1,15 @@
import classNames from "classnames";
import Image from "next/image";
import { PlusIcon } from "@heroicons/react/solid";
import { useState } from "react";
import Button from "@calcom/ui/Button";
import { Dialog, DialogContent } from "@calcom/ui/Dialog";
import { QueryCell } from "@lib/QueryCell";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
import { List, ListItem, ListItemText, ListItemTitle } from "@components/List";
import { List } from "@components/List";
import { ShellSubHeading } from "@components/Shell";
import SkeletonLoader from "@components/apps/SkeletonLoader";
import WebhookDialogForm from "@components/webhook/WebhookDialogForm";
import WebhookListItem, { TWebhook } from "@components/webhook/WebhookListItem";
@ -21,47 +20,35 @@ export type WebhookListContainerType = {
};
export default function WebhookListContainer(props: WebhookListContainerType) {
const { t } = useLocale();
const query = props.eventTypeId
? trpc.useQuery(["viewer.webhook.list", { eventTypeId: props.eventTypeId }], {
suspense: true,
})
: trpc.useQuery(["viewer.webhook.list"], {
suspense: true,
});
const query = trpc.useQuery(["viewer.webhook.list", { eventTypeId: props.eventTypeId }], {
suspense: true,
});
const [newWebhookModal, setNewWebhookModal] = useState(false);
const [editModalOpen, setEditModalOpen] = useState(false);
const [editing, setEditing] = useState<TWebhook | null>(null);
return (
<QueryCell
query={query}
customLoader={<SkeletonLoader />}
success={({ data }) => (
<>
<ShellSubHeading className="mt-10" title={props.title} subtitle={props.subtitle} />
<List>
<ListItem className={classNames("flex-col")}>
<div
className={classNames("flex w-full flex-1 items-center space-x-2 p-3 rtl:space-x-reverse")}>
<Image width={40} height={40} src="/apps/webhooks.svg" alt="Webhooks" />
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3">Webhooks</ListItemTitle>
<ListItemText component="p">{t("automation")}</ListItemText>
</div>
<div>
<Button
color="secondary"
onClick={() => setNewWebhookModal(true)}
data-testid="new_webhook">
{t("new_webhook")}
</Button>
</div>
</div>
</ListItem>
</List>
<div className="border-b border-gray-200 py-8 pl-2 pr-1">
<ShellSubHeading
className="mt-2"
title={props.title}
subtitle={props.subtitle}
actions={
<Button
color="secondary"
size="icon"
StartIcon={PlusIcon}
onClick={() => setNewWebhookModal(true)}
data-testid="new_webhook"
/>
}
/>
{data.length ? (
<List>
<List className="mt-6">
{data.map((item) => (
<WebhookListItem
key={item.id}
@ -97,7 +84,7 @@ export default function WebhookListContainer(props: WebhookListContainerType) {
)}
</DialogContent>
</Dialog>
</>
</div>
)}
/>
);

View File

@ -23,14 +23,14 @@ export default function WebhookListItem(props: { webhook: TWebhook; onEditWebhoo
});
return (
<ListItem className="-mt-px flex w-full p-4">
<ListItem className={classNames("flex w-full p-4", props.webhook.active ? "bg-white" : "bg-gray-100")}>
<div className="flex w-full justify-between">
<div className="flex max-w-full flex-col truncate">
<div className="flex space-y-1">
<span
className={classNames(
"truncate text-sm",
props.webhook.active ? "text-neutral-700" : "text-neutral-200"
props.webhook.active ? "text-neutral-700" : "text-neutral-400"
)}>
{props.webhook.subscriberUrl}
</span>
@ -41,8 +41,8 @@ export default function WebhookListItem(props: { webhook: TWebhook; onEditWebhoo
<span
key={ind}
className={classNames(
"w-max rounded-sm px-1 text-xs ",
props.webhook.active ? "bg-blue-100 text-blue-700" : "bg-blue-50 text-blue-200"
"w-max rounded-sm px-1 text-xs",
props.webhook.active ? "text-grey-200 bg-gray-200" : "bg-grey-50 text-neutral-400"
)}>
{t(`${eventTrigger.toLowerCase()}`)}
</span>

View File

@ -3,8 +3,7 @@ import { useSession } from "next-auth/react";
import React, { AriaRole, ComponentType, FC, Fragment } from "react";
import { CONSOLE_URL } from "@calcom/lib/constants";
import EmptyScreen from "@components/EmptyScreen";
import EmptyScreen from "@calcom/ui/EmptyScreen";
type LicenseRequiredProps = {
as?: keyof JSX.IntrinsicElements | "";

View File

@ -11,6 +11,8 @@ import { QueryCell } from "@lib/QueryCell";
import { trpc } from "@lib/trpc";
import { List } from "@components/List";
import { ShellSubHeading } from "@components/Shell";
import SkeletonLoader from "@components/apps/SkeletonLoader";
import LicenseRequired from "../LicenseRequired";
@ -22,25 +24,28 @@ function ApiKeyListContainer() {
const [editModalOpen, setEditModalOpen] = useState(false);
const [apiKeyToEdit, setApiKeyToEdit] = useState<(TApiKeys & { neverExpires?: boolean }) | null>(null);
return (
<>
<div className="flex flex-col justify-between truncate pl-2 pr-1 sm:flex-row">
<div className="mt-9">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("api_keys")}</h2>
<p className="mt-1 mb-5 text-sm text-gray-500">{t("api_keys_subtitle")}</p>
</div>
<div className="mb-9 sm:self-center">
<Button StartIcon={PlusIcon} color="secondary" onClick={() => setNewApiKeyModal(true)}>
{t("generate_new_api_key")}
</Button>
</div>
</div>
<div className="border-b border-gray-200 py-8 pl-2 pr-1">
<ShellSubHeading
className="mt-2"
title={t("api_keys")}
subtitle={t("api_keys_subtitle")}
actions={
<Button
color="secondary"
size="icon"
StartIcon={PlusIcon}
onClick={() => setNewApiKeyModal(true)}
/>
}
/>
<LicenseRequired>
<QueryCell
query={query}
customLoader={<SkeletonLoader />}
success={({ data }) => (
<>
{data.length > 0 && (
<List className="pb-6">
<List className="mt-6">
{data.map((item) => (
<ApiKeyListItem
key={item.id}
@ -80,7 +85,7 @@ function ApiKeyListContainer() {
)}
/>
</LicenseRequired>
</>
</div>
);
}

View File

@ -30,7 +30,7 @@ export default function ApiKeyListItem(props: { apiKey: TApiKeys; onEditApiKey:
},
});
return (
<ListItem className="-mt-px flex w-full p-4">
<ListItem className="flex w-full p-4">
<div className="flex w-full justify-between">
<div className="flex max-w-full flex-col truncate">
<div className="flex space-x-2">

View File

@ -14,15 +14,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const userId = req.session.user.id;
try {
const installedApp = await prisma.credential.findFirst({
const installedApp = await prisma.credential.findMany({
where: {
type: appCredentialType as string,
userId: userId,
},
});
if (installedApp && !!installedApp.key) {
res.status(200);
if (installedApp && !!installedApp.length) {
res.json({ count: installedApp.length });
} else {
res.status(404);
}

View File

@ -1,21 +1,22 @@
import { ArrowRightIcon, ViewGridIcon } from "@heroicons/react/solid";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import { JSONObject } from "superjson/dist/types";
import { AppConfiguration, InstallAppButton } from "@calcom/app-store/components";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { App } from "@calcom/types/App";
import type { App } from "@calcom/types/App";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { QueryCell } from "@lib/QueryCell";
import classNames from "@lib/classNames";
import { HttpError } from "@lib/core/http/error";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
import AppsShell from "@components/AppsShell";
import { ClientSuspense } from "@components/ClientSuspense";
import { List, ListItem, ListItemText, ListItemTitle } from "@components/List";
import Shell, { ShellSubHeading } from "@components/Shell";
import SkeletonLoader from "@components/apps/SkeletonLoader";
@ -24,10 +25,8 @@ import DisconnectIntegration from "@components/integrations/DisconnectIntegratio
import DisconnectStripeIntegration from "@components/integrations/DisconnectStripeIntegration";
import IntegrationListItem from "@components/integrations/IntegrationListItem";
import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections";
import WebhookListContainer from "@components/webhook/WebhookListContainer";
function ConnectOrDisconnectIntegrationButton(props: {
//
credentialIds: number[];
type: App["type"];
isGlobal?: boolean;
@ -95,122 +94,91 @@ function ConnectOrDisconnectIntegrationButton(props: {
);
}
function IntegrationsContainer() {
interface IntegrationsContainerProps {
variant: App["variant"];
className?: string;
}
const IntegrationsContainer = ({ variant, className = "" }: IntegrationsContainerProps): JSX.Element => {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations"], { suspense: true });
const query = trpc.useQuery(["viewer.integrations", { variant, onlyInstalled: true }], { suspense: true });
return (
<QueryCell
query={query}
success={({ data }) => (
<>
<ShellSubHeading
title={
<SubHeadingTitleWithConnections
title={t("conferencing")}
numConnections={data.conferencing.numActive}
/>
}
/>
<List>
{data.conferencing.items.map((item) => (
<IntegrationListItem
key={item.title}
title={item.title}
imageSrc={item.imageSrc}
description={item.description}
actions={
<ConnectOrDisconnectIntegrationButton
credentialIds={item.credentialIds}
type={item.type}
isGlobal={item.isGlobal}
installed
/>
}
/>
))}
</List>
<ShellSubHeading
className="mt-10"
title={
<SubHeadingTitleWithConnections title={t("payment")} numConnections={data.payment.numActive} />
}
/>
<List>
{data.payment.items.map((item) => (
<IntegrationListItem
key={item.title}
imageSrc={item.imageSrc}
title={item.title}
description={item.description}
actions={
<ConnectOrDisconnectIntegrationButton
credentialIds={item.credentialIds}
type={item.type}
isGlobal={item.isGlobal}
installed={item.installed}
/>
}
/>
))}
</List>
<ShellSubHeading
className="mt-10"
title={
<SubHeadingTitleWithConnections title={"Others"} numConnections={data?.other?.numActive || 0} />
}
/>
<List>
{data.other.items.map((item) => (
<IntegrationListItem
key={item.title}
imageSrc={item.imageSrc}
title={item.title}
description={item.description}
actions={
<ConnectOrDisconnectIntegrationButton
credentialIds={item.credentialIds}
type={item.type}
isGlobal={item.isGlobal}
installed={item.installed}
/>
}>
<AppConfiguration type={item.type} credentialIds={item.credentialIds} />
</IntegrationListItem>
))}
</List>
</>
)}></QueryCell>
customLoader={<SkeletonLoader className={className} />}
success={({ data }) => {
return (
<>
{data.items.length > 0 && (
<div className={className}>
<ShellSubHeading
title={
<SubHeadingTitleWithConnections title={t(variant)} numConnections={data.items.length} />
}
/>
<List>
{data.items.map((item) => (
<IntegrationListItem
key={item.title}
title={item.title}
imageSrc={item.imageSrc}
description={item.description}
actions={
<ConnectOrDisconnectIntegrationButton
credentialIds={item.credentialIds}
type={item.type}
isGlobal={item.isGlobal}
installed
/>
}
/>
))}
</List>
</div>
)}
</>
);
}}
/>
);
}
};
function Web3Container() {
const { t } = useLocale();
const result = trpc.useQuery(["viewer.web3Integration"]);
const isWeb3Active = !!result.data?.isWeb3Active;
return (
<>
<ShellSubHeading title="Web3" subtitle={t("meet_people_with_the_same_tokens")} className="mt-10" />
<div className="lg:col-span-9 lg:pb-8">
<List>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3")}>
<Image width={40} height={40} src="/apps/metamask.svg" alt="Embed" />
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3">
MetaMask (
<a className="text-blue-500" target="_blank" href="https://cal.com/web3" rel="noreferrer">
Read more
</a>
)
</ListItemTitle>
<ListItemText component="p">{t("only_book_people_and_allow")}</ListItemText>
</div>
<Web3ConnectBtn />
</div>
</ListItem>
</List>
</div>
{isWeb3Active && (
<>
<ShellSubHeading title="Web3" subtitle={t("meet_people_with_the_same_tokens")} className="mt-10" />
<div className="lg:col-span-9 lg:pb-8">
<List>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3")}>
<Image width={40} height={40} src="/apps/metamask.svg" alt="Embed" />
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3">
MetaMask (
<a
className="text-blue-500"
target="_blank"
href="https://cal.com/web3"
rel="noreferrer">
Read more
</a>
)
</ListItemTitle>
<ListItemText component="p">{t("only_book_people_and_allow")}</ListItemText>
</div>
<Web3ConnectBtn />
</div>
</ListItem>
</List>
</div>
</>
)}
</>
);
}
@ -264,7 +232,7 @@ function Web3ConnectBtn() {
export default function IntegrationsPage() {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations", { onlyInstalled: true }]);
return (
<Shell
heading={t("installed_apps")}
@ -272,12 +240,33 @@ export default function IntegrationsPage() {
large
customLoader={<SkeletonLoader />}>
<AppsShell>
<ClientSuspense fallback={<SkeletonLoader />}>
<IntegrationsContainer />
<CalendarListContainer />
<WebhookListContainer title={t("webhooks")} subtitle={t("receive_cal_meeting_data")} />
<Web3Container />
</ClientSuspense>
<QueryCell
query={query}
success={({ data }) => {
return data.items.length > 0 ? (
<>
<IntegrationsContainer variant="conferencing" />
<CalendarListContainer />
<IntegrationsContainer variant="payment" className="mt-8" />
<IntegrationsContainer variant="other" className="mt-8" />
<Web3Container />
</>
) : (
<EmptyScreen
Icon={ViewGridIcon}
headline={t("empty_installed_apps_headline")}
description={
<>
<span className="mb-6 block">{t("empty_installed_apps_description")}</span>
<Button href="/apps" EndIcon={ArrowRightIcon}>
{t("empty_installed_apps_button")}
</Button>
</>
}
/>
);
}}
/>
</AppsShell>
</Shell>
);

View File

@ -2,12 +2,12 @@ import { ClockIcon } from "@heroicons/react/outline";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { withQuery } from "@lib/QueryCell";
import { HttpError } from "@lib/core/http/error";
import { inferQueryOutput, trpc } from "@lib/trpc";
import EmptyScreen from "@components/EmptyScreen";
import Shell from "@components/Shell";
import { NewScheduleButton } from "@components/availability/NewScheduleButton";
import { ScheduleListItem } from "@components/availability/ScheduleListItem";

View File

@ -6,12 +6,12 @@ import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/componen
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { useInViewObserver } from "@lib/hooks/useInViewObserver";
import { inferQueryInput, inferQueryOutput, trpc } from "@lib/trpc";
import BookingsShell from "@components/BookingsShell";
import EmptyScreen from "@components/EmptyScreen";
import Shell from "@components/Shell";
import BookingListItem from "@components/booking/BookingListItem";
import SkeletonLoader from "@components/booking/SkeletonLoader";

View File

@ -31,6 +31,7 @@ import Dropdown, {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@calcom/ui/Dropdown";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { Tooltip } from "@calcom/ui/Tooltip";
import { withQuery } from "@lib/QueryCell";
@ -39,7 +40,6 @@ import { HttpError } from "@lib/core/http/error";
import { inferQueryOutput, trpc } from "@lib/trpc";
import { EmbedButton, EmbedDialog } from "@components/Embed";
import EmptyScreen from "@components/EmptyScreen";
import Shell from "@components/Shell";
import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent";
import CreateEventTypeButton from "@components/eventtype/CreateEventType";

View File

@ -0,0 +1,16 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import ApiKeyListContainer from "@ee/components/apiKeys/ApiKeyListContainer";
import SettingsShell from "@components/SettingsShell";
import WebhookListContainer from "@components/webhook/WebhookListContainer";
export default function Settings() {
const { t } = useLocale();
return (
<SettingsShell heading={t("developer")} subtitle={t("manage_developer_settings")}>
<WebhookListContainer title={t("webhooks")} subtitle={t("receive_cal_meeting_data")} />
<ApiKeyListContainer />
</SettingsShell>
);
}

View File

@ -2,7 +2,6 @@ import { IdentityProvider } from "@prisma/client";
import React from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import ApiKeyListContainer from "@ee/components/apiKeys/ApiKeyListContainer";
import SAMLConfiguration from "@ee/components/saml/Configuration";
import { identityProviderNameMap } from "@lib/auth";
@ -37,7 +36,6 @@ export default function Security() {
) : (
<div className="space-y-2 divide-y">
<ChangePasswordSection />
<ApiKeyListContainer />
<TwoFactorAuthSection twoFactorEnabled={user?.twoFactorEnabled || false} />
<DisableUserImpersonation disableImpersonation={user?.disableImpersonation ?? true} />
</div>

View File

@ -7,11 +7,11 @@ import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import useMeQuery from "@lib/hooks/useMeQuery";
import { trpc } from "@lib/trpc";
import EmptyScreen from "@components/EmptyScreen";
import Loader from "@components/Loader";
import SettingsShell from "@components/SettingsShell";
import TeamCreateModal from "@components/team/TeamCreateModal";

View File

@ -145,12 +145,12 @@ export async function login(
}
export async function getPaymentCredential(page: Page) {
await page.goto("/apps/installed");
await page.goto("/apps/stripe");
/** We start the Stripe flow */
await Promise.all([
page.waitForNavigation({ url: "https://connect.stripe.com/oauth/v2/authorize?*" }),
page.click('li:has-text("Stripe") >> [data-testid="integration-connection-button"]'),
page.click('[data-testid="install-app-button"]'),
]);
await Promise.all([

View File

@ -24,7 +24,7 @@ test.describe("Integrations", () => {
const user = await users.create();
const [eventType] = user.eventTypes;
await user.login();
await page.goto("/apps/installed");
await page.goto("/settings/developer");
// --- add webhook
await page.click('[data-testid="new_webhook"]');

View File

@ -352,6 +352,8 @@
"loading": "Loading...",
"deleting": "Deleting...",
"standard_iframe": "Standard iframe",
"developer": "Developer",
"manage_developer_settings": "Manage your developer settings.",
"iframe_embed": "iframe Embed",
"embed_calcom": "The easiest way to embed Cal.com on your website.",
"integrate_using_embed_or_webhooks": "Integrate with your website using our embed options, or get real-time booking information using custom webhooks.",
@ -670,13 +672,16 @@
"next_step": "Skip step",
"prev_step": "Prev step",
"installed": "Installed",
"active_install": "{{count}} active install",
"active_install_plural": "{{count}} active installs",
"globally_install": "Globally installed",
"disconnect": "Disconnect",
"embed_your_calendar": "Embed your calendar within your webpage",
"connect_your_favourite_apps": "Connect your favourite apps.",
"automation": "Automation",
"configure_how_your_event_types_interact": "Configure how your event types should interact with your calendars.",
"select_destination_calendar": "Create events on",
"connect_an_additional_calendar": "Connect an additional calendar",
"connect_additional_calendar": "Connect additional calendar",
"conferencing": "Conferencing",
"calendar": "Calendar",
"not_installed": "Not installed",
@ -716,6 +721,9 @@
"trending_apps": "Trending Apps",
"all_apps": "All Apps",
"installed_apps": "Installed Apps",
"empty_installed_apps_headline": "No apps installed",
"empty_installed_apps_description": "Apps enable you to enhance your workflow and improve your scheduling life significantly.",
"empty_installed_apps_button": "Explore the App Store",
"manage_your_connected_apps": "Manage your installed apps or change settings",
"browse_apps": "Browse Apps",
"features": "Features",
@ -776,7 +784,6 @@
"api_keys": "API Keys",
"api_key_modal_subtitle": "API keys allow you to make API calls for your own account.",
"api_keys_subtitle": "Generate API keys to use for accessing your own account.",
"generate_new_api_key": "Generate new API key",
"create_api_key": "Create an API key",
"personal_note": "Name this key",
"personal_note_placeholder": "E.g. Development",

View File

@ -610,41 +610,32 @@ const loggedInViewerRouter = createProtectedRouter()
},
})
.query("integrations", {
async resolve({ ctx }) {
input: z.object({
variant: z.string().optional(),
onlyInstalled: z.boolean().optional(),
}),
async resolve({ ctx, input }) {
const { user } = ctx;
const { variant, onlyInstalled } = input;
const { credentials } = user;
function countActive(items: { credentialIds: unknown[] }[]) {
return items.reduce((acc, item) => acc + item.credentialIds.length, 0);
}
const apps = getApps(credentials).map(
let apps = getApps(credentials).map(
({ credentials: _, credential: _1 /* don't leak to frontend */, ...app }) => ({
...app,
credentialIds: credentials.filter((c) => c.type === app.type).map((c) => c.id),
})
);
// `flatMap()` these work like `.filter()` but infers the types correctly
const conferencing = apps.flatMap((item) => (item.variant === "conferencing" ? [item] : []));
const payment = apps.flatMap((item) => (item.variant === "payment" ? [item] : []));
const other = apps.flatMap((item) => (item.variant.startsWith("other") ? [item] : []));
const calendar = apps.flatMap((item) => (item.variant === "calendar" ? [item] : []));
if (variant) {
// `flatMap()` these work like `.filter()` but infers the types correctly
apps = apps
// variant check
.flatMap((item) => (item.variant.startsWith(variant) ? [item] : []));
}
if (onlyInstalled) {
apps = apps.flatMap((item) => (item.credentialIds.length > 0 || item.isGlobal ? [item] : []));
}
return {
conferencing: {
items: conferencing,
numActive: countActive(conferencing),
},
calendar: {
items: calendar,
numActive: countActive(calendar),
},
payment: {
items: payment,
numActive: countActive(payment),
},
other: {
items: other,
numActive: countActive(other),
},
items: apps,
};
},
})

View File

@ -1,6 +1,7 @@
import { GetStaticPropsContext } from "next";
export const AppSetupPageMap = {
"apple-calendar": import("../../applecalendar/pages/setup/_getStaticProps"),
zapier: import("../../zapier/pages/setup/_getStaticProps"),
};

View File

@ -3,6 +3,7 @@ import dynamic from "next/dynamic";
import { DynamicComponent } from "../../_components/DynamicComponent";
export const AppSetupMap = {
"apple-calendar": dynamic(() => import("../../applecalendar/pages/setup")),
zapier: dynamic(() => import("../../zapier/pages/setup")),
};

View File

@ -41,6 +41,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return res.status(500).json({ message: "Could not add this caldav account" });
}
return res.status(200).json({});
return res.status(200).json({ url: "/apps/installed" });
}
if (req.method === "GET") {
return res.status(200).json({ url: "/apps/apple-calendar/setup" });
}
}

View File

@ -1,104 +0,0 @@
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogProps,
} from "@calcom/ui/Dialog";
import { Form, TextField } from "@calcom/ui/form/fields";
export const ADD_INTEGRATION_FORM_TITLE = "addAppleIntegration";
function AddIntegrationModal(props: DialogProps) {
const form = useForm({
defaultValues: {
username: "",
password: "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<Dialog name={ADD_INTEGRATION_FORM_TITLE} {...props}>
<DialogContent>
<DialogHeader
title="Connect to Apple Server"
subtitle={
<>
Generate an app specific password to use with Cal.com at{" "}
<a
className="text-indigo-400"
href="https://appleid.apple.com/account/manage"
target="_blank"
rel="noopener noreferrer">
https://appleid.apple.com/account/manage
</a>
. Your credentials will be stored and encrypted.
</>
}
/>
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/applecalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || "Something went wrong");
} else {
props.onOpenChange?.(false);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("username")}
label="Username"
placeholder="rickroll"
/>
<TextField
required
type="password"
{...form.register("password")}
label="Password"
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<DialogFooter>
<DialogClose
onClick={() => {
props.onOpenChange?.(false);
}}
asChild>
<Button type="button" color="secondary" tabIndex={-1}>
Cancel
</Button>
</DialogClose>
<Button type="submit" loading={form.formState.isSubmitting}>
Save
</Button>
</DialogFooter>
</Form>
</DialogContent>
</Dialog>
);
}
export default AddIntegrationModal;

View File

@ -1,20 +1,18 @@
import { useState } from "react";
import type { InstallAppButtonProps } from "@calcom/app-store/types";
import { InstallAppButtonProps } from "../../types";
import AddIntegration from "./AddIntegration";
import useAddAppMutation from "../../_utils/useAddAppMutation";
export default function InstallAppButton(props: InstallAppButtonProps) {
const [isModalOpen, setIsModalOpen] = useState(false);
const mutation = useAddAppMutation("apple_calendar");
return (
<>
{props.render({
onClick() {
setIsModalOpen(true);
mutation.mutate("");
},
disabled: isModalOpen,
loading: mutation.isLoading,
})}
<AddIntegration open={isModalOpen} onOpenChange={setIsModalOpen} />
</>
);
}

View File

@ -1,2 +1 @@
export { default as AddIntegration } from "./AddIntegration";
export { default as InstallAppButton } from "./InstallAppButton";

View File

@ -0,0 +1,7 @@
import { GetStaticPropsContext } from "next";
export const getStaticProps = async (ctx: GetStaticPropsContext) => {
return {
props: {},
};
};

View File

@ -0,0 +1,100 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import { Form, TextField } from "@calcom/ui/form/fields";
export default function AppleCalendarSetup() {
const { t } = useLocale();
const router = useRouter();
const form = useForm({
defaultValues: {
username: "",
password: "",
},
});
const [errorMessage, setErrorMessage] = useState("");
return (
<div className="flex h-screen bg-gray-200">
<div className="m-auto rounded bg-white p-5 md:w-[560px] md:p-10">
<div className="flex flex-col space-y-5 md:flex-row md:space-y-0 md:space-x-5">
<div>
{/* eslint-disable @next/next/no-img-element */}
<img
src="/api/app-store/applecalendar/icon.svg"
alt="Apple Calendar"
className="h-12 w-12 max-w-2xl"
/>
</div>
<div>
<h1 className="text-gray-600">Connect to Apple Server</h1>
<div className="mt-1 text-sm">
Generate an app specific password to use with Cal.com at{" "}
<a
className="text-indigo-400"
href="https://appleid.apple.com/account/manage"
target="_blank"
rel="noopener noreferrer">
https://appleid.apple.com/account/manage
</a>
. Your credentials will be stored and encrypted.
</div>
<div className="my-2 mt-3">
<Form
form={form}
handleSubmit={async (values) => {
setErrorMessage("");
const res = await fetch("/api/integrations/applecalendar/add", {
method: "POST",
body: JSON.stringify(values),
headers: {
"Content-Type": "application/json",
},
});
const json = await res.json();
if (!res.ok) {
setErrorMessage(json?.message || "Something went wrong");
} else {
router.push(json.url);
}
}}>
<fieldset className="space-y-2" disabled={form.formState.isSubmitting}>
<TextField
required
type="text"
{...form.register("username")}
label="Username"
placeholder="rickroll"
/>
<TextField
required
type="password"
{...form.register("password")}
label="Password"
placeholder="•••••••••••••"
autoComplete="password"
/>
</fieldset>
{errorMessage && <Alert severity="error" title={errorMessage} className="my-4" />}
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" loading={form.formState.isSubmitting}>
Save
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
<Toaster position="bottom-right" />
</div>
);
}

View File

@ -21,6 +21,7 @@ export const metadata = {
trending: false,
url: "https://cal.com/",
verified: true,
isGlobal: true,
email: "help@cal.com",
locationType: LocationType.GoogleMeet,
locationLabel: "Google Meet",

View File

@ -13,12 +13,15 @@ interface IWipeMyCalActionButtonProps {
const WipeMyCalActionButton = (props: IWipeMyCalActionButtonProps) => {
const { trpc, bookingsEmpty, bookingStatus } = props;
const [openDialog, setOpenDialog] = useState(false);
const { isSuccess, isLoading, data } = trpc.useQuery(["viewer.integrations"]);
const { isSuccess, isLoading, data } = trpc.useQuery([
"viewer.integrations",
{ variant: "other", onlyInstalled: undefined },
]);
if (bookingStatus !== "upcoming" || bookingsEmpty) {
return <></>;
}
const wipeMyCalCredentials: { credentialIds: number[] } = data?.other?.items.find(
const wipeMyCalCredentials: { credentialIds: number[] } = data?.items.find(
(item: { type: string }) => item.type === "wipemycal_other"
);

View File

@ -23,12 +23,12 @@ export default function ZapierSetup(props: IZapierSetupProps) {
const [newApiKey, setNewApiKey] = useState("");
const { t } = useLocale();
const utils = trpc.useContext();
const integrations = trpc.useQuery(["viewer.integrations"]);
const integrations = trpc.useQuery(["viewer.integrations", { variant: "other" }]);
// @ts-ignore
const oldApiKey = trpc.useQuery(["viewer.apiKeys.findKeyOfType", { appId: ZAPIER }]);
const deleteApiKey = trpc.useMutation("viewer.apiKeys.delete");
const zapierCredentials: { credentialIds: number[] } | undefined = integrations.data?.other?.items.find(
const zapierCredentials: { credentialIds: number[] } | undefined = integrations.data?.items.find(
(item: { type: string }) => item.type === "zapier_other"
);
const [credentialId] = zapierCredentials?.credentialIds || [false];
@ -49,7 +49,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
if (integrations.isLoading) {
return (
<div className="absolute z-50 flex items-center w-full h-screen bg-gray-200">
<div className="flex absolute z-50 h-screen w-full items-center bg-gray-200">
<Loader />
</div>
);
@ -58,7 +58,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
return (
<div className="flex h-screen bg-gray-200">
{showContent ? (
<div className="p-10 m-auto bg-white rounded">
<div className="m-auto rounded bg-white p-10">
<div className="flex flex-row">
<div className="mr-5">
<Icon />
@ -76,7 +76,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
<>
<div className="mt-1 text-xl">{t("your_unique_api_key")}</div>
<div className="flex my-2 mt-3">
<div className="w-full p-3 pr-5 mr-1 bg-gray-100 rounded">{newApiKey}</div>
<div className="mr-1 w-full rounded bg-gray-100 p-3 pr-5">{newApiKey}</div>
<Tooltip content="copy to clipboard">
<Button
onClick={() => {
@ -85,7 +85,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
}}
type="button"
className="px-4 text-base ">
<ClipboardCopyIcon className="w-5 h-5 mr-2 text-neutral-100" />
<ClipboardCopyIcon className="mr-2 h-5 w-5 text-neutral-100" />
{t("copy")}
</Button>
</Tooltip>
@ -104,8 +104,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
{t("zapier_invite_link")}
</a>
</li>
)
}
)}
<Trans i18nKey="zapier_setup_instructions">
<li>Log into your Zapier account and create a new Zap.</li>
<li>Select Cal.com as your Trigger app. Also choose a Trigger event.</li>

View File

@ -0,0 +1,3 @@
insert into "App" ("slug", "dirName", "updatedAt", "categories")
values ('daily-video', 'dailyvideo', CURRENT_TIMESTAMP, '{video}')
on conflict do nothing

View File

@ -52,7 +52,7 @@ export function Dialog(props: DialogProps) {
return (
<DialogPrimitive.Root {...dialogProps}>
<DialogPrimitive.Overlay className="fixed inset-0 z-40 transition-opacity bg-black bg-opacity-50 fadeIn" />
<DialogPrimitive.Overlay className="fadeIn fixed inset-0 z-40 bg-black bg-opacity-50 transition-opacity" />
{children}
</DialogPrimitive.Root>
);
@ -64,7 +64,7 @@ type DialogContentProps = React.ComponentProps<typeof DialogPrimitive["Content"]
export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps>(
({ children, ...props }, forwardedRef) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="fixed inset-0 z-40 transition-opacity bg-gray-500 bg-opacity-75 fadeIn" />
<DialogPrimitive.Overlay className="fadeIn fixed inset-0 z-40 bg-gray-500 bg-opacity-75 transition-opacity" />
{/*zIndex one less than Toast */}
<DialogPrimitive.Content
{...props}
@ -93,7 +93,7 @@ type DialogHeaderProps = {
export function DialogHeader(props: DialogHeaderProps) {
return (
<div className="mb-8">
<h3 className="text-xl text-gray-900 leading-16 font-cal" id="modal-title">
<h3 className="leading-16 font-cal text-xl text-gray-900" id="modal-title">
{props.title}
</h3>
{props.subtitle && <div className="text-sm text-gray-400">{props.subtitle}</div>}
@ -104,7 +104,7 @@ export function DialogHeader(props: DialogHeaderProps) {
export function DialogFooter(props: { children: ReactNode }) {
return (
<div>
<div className="flex justify-end mt-5 space-x-2 rtl:space-x-reverse">{props.children}</div>
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse">{props.children}</div>
</div>
);
}

View File

@ -13,7 +13,7 @@ export default function EmptyScreen({
}) {
return (
<>
<div className="min-h-80 my-6 flex flex-col items-center justify-center rounded-sm border border-dashed">
<div className="min-h-80 flex my-6 flex-col items-center justify-center rounded-sm border border-dashed">
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
<Icon className="inline-block h-10 w-10 text-white dark:bg-white dark:text-gray-600" />
</div>

View File

@ -27,9 +27,17 @@ const SkeletonText: React.FC<SkeletonBaseProps> = ({ width, height }) => {
return <div className={`rounded-md bg-gray-200 w-${width} h-${height} ${classNames}`} />;
};
const SkeletonButton: React.FC<SkeletonBaseProps> = ({ width, height }) => {
return (
<SkeletonContainer>
<div className={`w-${width} h-${height} bg-gray-200 ${classNames}`} />
</SkeletonContainer>
);
};
const SkeletonContainer: React.FC<SkeletonContainer> = ({ children, as }) => {
const Component = as || "div";
return <Component className="animate-pulse">{children}</Component>;
};
export { SkeletonAvatar, SkeletonText, SkeletonContainer };
export { SkeletonAvatar, SkeletonText, SkeletonButton, SkeletonContainer };

447
yarn.lock
View File

@ -48,11 +48,6 @@
dependencies:
"@babel/highlight" "^7.16.7"
"@babel/compat-data@^7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab"
integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==
"@babel/compat-data@^7.17.7":
version "7.17.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2"
@ -1900,11 +1895,6 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c"
integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==
"@jridgewell/set-array@^1.0.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.11"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec"
@ -2638,7 +2628,7 @@
"@radix-ui/react-use-callback-ref" "0.1.0"
"@radix-ui/react-use-controllable-state" "0.1.0"
"@radix-ui/react-slider@^0.1.0", "@radix-ui/react-slider@^0.1.1":
"@radix-ui/react-slider@^0.1.1":
version "0.1.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-0.1.4.tgz#a7b7a480ee00158195794b08cd3f1583cf102518"
integrity sha512-0z3bCcdrAi+FIcoLXS6r0ESVWuuyMnUJoCsFm7tC7Rtv95x34YtaI8YfSyQmzuMVS4rTsNtCCTZ/s727uRaVkQ==
@ -3011,11 +3001,6 @@
p-queue "^6.6.1"
p-retry "^4.0.0"
"@socket.io/component-emitter@~3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
"@sqltools/formatter@^1.2.2":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20"
@ -3157,19 +3142,6 @@
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
"@typeform/embed-react@^1.2.4":
version "1.16.0"
resolved "https://registry.yarnpkg.com/@typeform/embed-react/-/embed-react-1.16.0.tgz#013f510927525d023fa27b466cd66fbd9f0b42d2"
integrity sha512-MLIPXZ7uxvoyLc5RMK0Tvmf93DoqQXbpu3DleXyRk7ilrYx+TfXUqOtJfaqBK4qR2HpslhSckgvtHPfv0zMGlQ==
dependencies:
"@typeform/embed" "1.35.1"
fast-deep-equal "^3.1.3"
"@typeform/embed@1.35.1":
version "1.35.1"
resolved "https://registry.yarnpkg.com/@typeform/embed/-/embed-1.35.1.tgz#96e0c84e0af385f90411b2f75277ca7ae0d50fa1"
integrity sha512-dDLewxUKwfCfU/nMaVpwQ3nOF1nMhey3wtALAQRgS9fe6XRbZH6YkmtqvTsxTjilOnswJqghGFJ3GfaZh87n/A==
"@types/accept-language-parser@1.5.2":
version "1.5.2"
resolved "https://registry.yarnpkg.com/@types/accept-language-parser/-/accept-language-parser-1.5.2.tgz#ea48ed07a3dc9d2ba6666d45c018ad1b5e59d665"
@ -3281,13 +3253,6 @@
dependencies:
"@types/ms" "*"
"@types/engine.io@*":
version "3.1.7"
resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.7.tgz#86e541a5dc52fb7e97735383564a6ae4cfe2e8f5"
integrity sha512-qNjVXcrp+1sS8YpRUa714r0pgzOwESdW5UjHL7D/2ZFdBX0BXUXtg1LUrp+ylvqbvMcMWUy73YpRoxPN2VoKAQ==
dependencies:
"@types/node" "*"
"@types/estree-jsx@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-0.0.1.tgz#c36d7a1afeb47a95a8ee0b7bc8bc705db38f919d"
@ -3427,7 +3392,7 @@
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138"
integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==
"@types/json-schema@^7.0.6", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9":
"@types/json-schema@^7.0.7":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
@ -3651,22 +3616,6 @@
"@types/mime" "^1"
"@types/node" "*"
"@types/socket.io-parser@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-3.0.0.tgz#9726d3ab9235757a0a30dd5ccf8975dce54e5e2c"
integrity sha512-Ry/rbTE6HQNL9eu3LpL1Ocup5VexXu1bSSGlSho/IR5LuRc8YvxwSNJ3JxqTltVJEATLbZkMQETSbxfKNgp4Ew==
dependencies:
socket.io-parser "*"
"@types/socket.io@2.1.13":
version "2.1.13"
resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.13.tgz#b6d694234e99956c96ff99e197eda824b6f9dc48"
integrity sha512-JRgH3nCgsWel4OPANkhH8TelpXvacAJ9VeryjuqCDiaVDMpLysd6sbt0dr6Z15pqH3p2YpOT3T1C5vQ+O/7uyg==
dependencies:
"@types/engine.io" "*"
"@types/node" "*"
"@types/socket.io-parser" "*"
"@types/stack-utils@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
@ -3928,7 +3877,7 @@ accept-language-parser@^1.5.0:
resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791"
integrity sha1-iHfFQECo3LWeCgfZwf3kIpgzR5E=
accepts@^1.3.7, accepts@~1.3.7, accepts@~1.3.8:
accepts@~1.3.7, accepts@~1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
@ -4090,11 +4039,6 @@ app-root-path@^3.0.0:
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad"
integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
arch@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
@ -4107,14 +4051,6 @@ archive-type@^4.0.0:
dependencies:
file-type "^4.2.0"
are-we-there-yet@~1.1.2:
version "1.1.7"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146"
integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
arg@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050"
@ -4541,7 +4477,7 @@ base-x@^3.0.2, base-x@^3.0.8:
dependencies:
safe-buffer "^5.0.1"
base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@ -4836,17 +4772,6 @@ browserslist@^4.20.2:
node-releases "^2.0.2"
picocolors "^1.0.0"
browserslist@^4.20.3:
version "4.20.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf"
integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==
dependencies:
caniuse-lite "^1.0.30001332"
electron-to-chromium "^1.4.118"
escalade "^3.1.1"
node-releases "^2.0.3"
picocolors "^1.0.0"
bs-logger@0.x:
version "0.2.6"
resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
@ -5057,7 +4982,7 @@ camelcase@^5.0.0, camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelcase@^6.0.0, camelcase@^6.2.0:
camelcase@^6.0.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
@ -5262,11 +5187,6 @@ cjs-module-lexer@^0.6.0:
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f"
integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==
cjs-module-lexer@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
class-is@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
@ -5398,13 +5318,6 @@ co@^4.6.0:
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
cobe@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cobe/-/cobe-0.4.2.tgz#c3787f961a30d6adfbaf6cb446c891f45a516bdf"
integrity sha512-EHHCAWUom+dm1p5l/uy8pUiKnxzKyHXVWr4ky3Qk0Fav6Z0iW4iPMf7+nblF6uDYnd9Lk/ghbjDhwPc6b6EteA==
dependencies:
phenomenon "^1.6.0"
code-block-writer@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4"
@ -5412,11 +5325,6 @@ code-block-writer@^11.0.0:
dependencies:
tslib "2.3.1"
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
collect-v8-coverage@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59"
@ -5486,7 +5394,7 @@ commander@9.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-9.1.0.tgz#a6b263b2327f2e188c6402c42623327909f2dbec"
integrity sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==
commander@^2.7.1, commander@^2.8.1, commander@^2.9.0:
commander@^2.8.1, commander@^2.9.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -5529,7 +5437,7 @@ constant-case@^1.1.0:
snake-case "^1.1.0"
upper-case "^1.1.1"
content-disposition@0.5.4, content-disposition@^0.5.2, content-disposition@^0.5.3:
content-disposition@0.5.4, content-disposition@^0.5.2:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
@ -5825,11 +5733,6 @@ dayjs@^1, dayjs@^1.11.2:
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -5933,11 +5836,6 @@ decompress@^4.2.1:
pify "^2.3.0"
strip-dirs "^2.0.0"
dedent@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
deep-extend@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
@ -6009,11 +5907,6 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
denque@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a"
@ -6029,7 +5922,7 @@ depd@2.0.0:
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@^1.1.0, depd@~1.1.2:
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
@ -6147,13 +6040,6 @@ dlv@^1.1.3:
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
doctrine@3.0.0, doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@ -6161,6 +6047,13 @@ doctrine@^2.1.0:
dependencies:
esutils "^2.0.2"
doctrine@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
@ -6267,11 +6160,6 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.4.118:
version "1.4.132"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.132.tgz#b64599eb018221e52e2e4129de103b03a413c55d"
integrity sha512-JYdZUw/1068NWN+SwXQ7w6Ue0bWYGihvSUNNQwurvcDV/SM7vSiGZ3NuFvFgoEiCs4kB8xs3cX2an3wB7d4TBw==
electron-to-chromium@^1.4.76, electron-to-chromium@^1.4.84:
version "1.4.103"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a"
@ -6340,7 +6228,7 @@ enhanced-resolve@^5.7.0:
graceful-fs "^4.2.4"
tapable "^2.2.0"
env-cmd@10.1.0, env-cmd@^10.1.0:
env-cmd@10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b"
integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==
@ -6705,14 +6593,6 @@ eslint-plugin-react@^7.29.4:
semver "^6.3.0"
string.prototype.matchall "^4.0.6"
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
@ -6807,11 +6687,6 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
@ -7041,7 +6916,7 @@ execa@^4.0.0:
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
execa@^5.0.0, execa@^5.1.1:
execa@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
@ -7572,7 +7447,7 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
fresh@0.5.2, fresh@^0.5.2:
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
@ -7604,15 +7479,6 @@ fs-extra@^4.0.2:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^8.0.1:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
@ -7820,18 +7686,6 @@ glob-parent@^6.0.1, glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
glob@7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.7:
version "7.1.7"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
@ -8012,11 +7866,6 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4,
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
gradient-string@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-2.0.0.tgz#0333846e88e6011bdd12fa73d0fa2a60dfd34f51"
@ -8137,11 +7986,6 @@ has-tostringtag@^1.0.0:
dependencies:
has-symbols "^1.0.2"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@ -8197,26 +8041,11 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hast-util-is-element@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz#fc0b0dc7cef3895e839b8d66979d57b0338c68f3"
integrity sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA==
dependencies:
"@types/hast" "^2.0.0"
"@types/unist" "^2.0.0"
hast-util-parse-selector@^2.0.0:
version "2.2.5"
resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a"
integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==
hast-util-sanitize@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-4.0.0.tgz#71a02ca2e50d04b852a5500846418070ca364f60"
integrity sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ==
dependencies:
"@types/hast" "^2.0.0"
hast-util-to-estree@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.0.2.tgz#79c5bf588915610b3f0d47ca83a74dc0269c7dc2"
@ -8237,22 +8066,6 @@ hast-util-to-estree@^2.0.0:
unist-util-position "^4.0.0"
zwitch "^2.0.0"
hast-util-to-html@^8.0.0:
version "8.0.3"
resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz#4e37580872e143ea9ce0dba87918b19e4ea997e3"
integrity sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==
dependencies:
"@types/hast" "^2.0.0"
ccount "^2.0.0"
comma-separated-tokens "^2.0.0"
hast-util-is-element "^2.0.0"
hast-util-whitespace "^2.0.0"
html-void-elements "^2.0.0"
property-information "^6.0.0"
space-separated-tokens "^2.0.0"
stringify-entities "^4.0.2"
unist-util-is "^5.0.0"
hast-util-whitespace@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c"
@ -8319,11 +8132,6 @@ html-parse-stringify@^3.0.1:
dependencies:
void-elements "3.1.0"
html-void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
http-cache-semantics@3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
@ -8508,11 +8316,6 @@ image-q@^4.0.0:
dependencies:
"@types/node" "16.9.1"
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
immutable@^3.x.x:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
@ -8836,13 +8639,6 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@ -9156,17 +8952,6 @@ istanbul-lib-instrument@^5.0.4:
istanbul-lib-coverage "^3.2.0"
semver "^6.3.0"
istanbul-lib-instrument@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f"
integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==
dependencies:
"@babel/core" "^7.12.3"
"@babel/parser" "^7.14.7"
"@istanbuljs/schema" "^0.1.2"
istanbul-lib-coverage "^3.2.0"
semver "^6.3.0"
istanbul-lib-report@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
@ -9185,7 +8970,7 @@ istanbul-lib-source-maps@^4.0.0:
istanbul-lib-coverage "^3.0.0"
source-map "^0.6.1"
istanbul-reports@^3.0.2, istanbul-reports@^3.1.3:
istanbul-reports@^3.0.2:
version "3.1.4"
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c"
integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==
@ -10193,15 +9978,6 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922"
integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==
dependencies:
universalify "^0.1.2"
optionalDependencies:
graceful-fs "^4.1.6"
jsonwebtoken@^8.5.1:
version "8.5.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
@ -10475,13 +10251,6 @@ loader-utils@^2.0.0:
emojis-list "^3.0.0"
json5 "^2.1.2"
localforage@^1.8.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4"
integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==
dependencies:
lie "3.1.1"
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@ -10532,11 +10301,6 @@ lodash.isboolean@^3.0.3:
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
@ -10562,11 +10326,6 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.mergewith@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.once@^4.0.0, lodash.once@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
@ -10922,21 +10681,6 @@ mdast-util-mdxjs-esm@^1.0.0:
mdast-util-from-markdown "^1.0.0"
mdast-util-to-markdown "^1.0.0"
mdast-util-to-hast@^11.0.0:
version "11.3.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-11.3.0.tgz#ea9220617a710e80aa5cc3ac7cc9d4bb0440ae7a"
integrity sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw==
dependencies:
"@types/hast" "^2.0.0"
"@types/mdast" "^3.0.0"
"@types/mdurl" "^1.0.0"
mdast-util-definitions "^5.0.0"
mdurl "^1.0.0"
unist-builder "^3.0.0"
unist-util-generated "^2.0.0"
unist-util-position "^4.0.0"
unist-util-visit "^4.0.0"
mdast-util-to-hast@^12.1.0:
version "12.1.1"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.1.1.tgz#89a2bb405eaf3b05eb8bf45157678f35eef5dbca"
@ -11023,7 +10767,7 @@ merge-class-names@^1.1.1:
resolved "https://registry.yarnpkg.com/merge-class-names/-/merge-class-names-1.4.2.tgz#78d6d95ab259e7e647252a7988fd25a27d5a8835"
integrity sha512-bOl98VzwCGi25Gcn3xKxnR5p/WrhWFQB59MS/aGENcmUc6iSm96yrFDF0XSNurX9qN4LbJm0R9kfvsQ17i8zCw==
merge-descriptors@1.0.1, merge-descriptors@^1.0.1:
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
@ -11048,7 +10792,7 @@ methods@^1.1.2, methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
micro@9.3.4, micro@^9.3.4:
micro@^9.3.4:
version "9.3.4"
resolved "https://registry.yarnpkg.com/micro/-/micro-9.3.4.tgz#745a494e53c8916f64fb6a729f8cbf2a506b35ad"
integrity sha512-smz9naZwTG7qaFnEZ2vn248YZq9XR+XoOH3auieZbkhDL4xLOxiE+KqG8qqnBeKfXA9c1uEFGCxPN1D+nT6N7w==
@ -11558,13 +11302,6 @@ mockdate@^3.0.5:
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb"
integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==
modify-response-middleware@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/modify-response-middleware/-/modify-response-middleware-1.1.0.tgz#8713182390a7c7ec32dfc79b9bc626d14060d4ce"
integrity sha512-oAyioDzMvyYwbq8tH7DvahHtGzQvDwZlN2CxL2fZQdUZNz8JJvC3PYaagiMGN58sM45Veo1GA8g/aJI7Hogpxw==
dependencies:
brotli "^1.3.2"
module-alias@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
@ -11794,11 +11531,6 @@ next-mdx-remote@^4.0.3:
vfile "^5.3.0"
vfile-matter "^3.0.1"
next-plausible@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-2.2.0.tgz#f825842f97bce0062bdaf897328c4908d7ce0a78"
integrity sha512-pIhs5MikL6ZMJvB7sxkM49xN06W1A6d6RYta5vrqwQmF2/oXoCG+IPoaPzyODZ/vo7f2/NMAOaUm5QM0dKqMdA==
next-seo@^4.26.0:
version "4.29.0"
resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.29.0.tgz#d281e95ba47914117cc99e9e468599f0547d9b9b"
@ -11916,7 +11648,7 @@ node-domexception@1.0.0:
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7:
node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
@ -11938,22 +11670,6 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
node-mocks-http@^1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e"
integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==
dependencies:
accepts "^1.3.7"
content-disposition "^0.5.3"
depd "^1.1.0"
fresh "^0.5.2"
merge-descriptors "^1.0.1"
methods "^1.1.2"
mime "^1.3.4"
parseurl "^1.3.3"
range-parser "^1.2.0"
type-is "^1.6.18"
node-notifier@^8.0.0:
version "8.0.2"
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5"
@ -12056,21 +11772,6 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
dependencies:
are-we-there-yet "~1.1.2"
console-control-strings "~1.1.0"
gauge "~2.7.3"
set-blocking "~2.0.0"
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
number-to-bn@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0"
@ -12542,7 +12243,7 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
parse-json@^5.0.0, parse-json@^5.2.0:
parse-json@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
@ -12569,7 +12270,7 @@ parse5@^5.1.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
parseurl@^1.3.3, parseurl@~1.3.3:
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
@ -12733,11 +12434,6 @@ pgpass@1.x:
dependencies:
split2 "^4.1.0"
phenomenon@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/phenomenon/-/phenomenon-1.6.0.tgz#7b5b7647d0b48152cc0846994da3d92e8f6da677"
integrity sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A==
phin@^2.9.1:
version "2.9.3"
resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c"
@ -13266,7 +12962,7 @@ randomfill@^1.0.3:
randombytes "^2.0.5"
safe-buffer "^5.1.0"
range-parser@^1.2.0, range-parser@~1.2.1:
range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
@ -13331,13 +13027,6 @@ react-colorful@^5.5.1:
resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784"
integrity sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg==
react-confetti@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.0.1.tgz#d4f57b5a021dd908a6243b8f63b6009b00818d10"
integrity sha512-ZpOTBrqSNhWE4rRXCZ6E6U+wGd7iYHF5MGrqwikoiBpgBq9Akdu0DcLW+FdFnLjyZYC+VfAiV2KeFgYRMyMrkA==
dependencies:
tween-functions "^1.2.0"
react-copy-to-clipboard@5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz#42ec519b03eb9413b118af92d1780c403a5f19bf"
@ -13405,7 +13094,7 @@ react-hook-form@^7.16.2, react-hook-form@^7.31.1:
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.31.1.tgz#16c357dd366bc226172e6acbb5a1672873bbfb28"
integrity sha512-QjtjZ8r8KtEBWWpcXLyQordCraTFxILtyQpaz5KLLxN2YzcC+FZ9LLtOnNGuOnzZo9gCoB+viK3ZHV9Mb2htmQ==
react-hot-toast@^2.1.0, react-hot-toast@^2.1.1:
react-hot-toast@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.2.0.tgz#ab6f4caed4214b9534f94bb8cfaaf21b051e62b9"
integrity sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==
@ -13787,17 +13476,6 @@ remark-gfm@^1.0.0:
mdast-util-gfm "^0.1.0"
micromark-extension-gfm "^0.3.0"
remark-html@^14.0.1:
version "14.0.1"
resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-14.0.1.tgz#2118516604c1a6c2ea9d5914a526942554e04e30"
integrity sha512-a/x5bTlFrkwYkz43zuJIk0m0IuS5Rx8zLztGwdzmAdUj0Hsi4C4nkJ8gTQRNXY/ET/gMrqQORMMI0arRItq/aQ==
dependencies:
"@types/mdast" "^3.0.0"
hast-util-sanitize "^4.0.0"
hast-util-to-html "^8.0.0"
mdast-util-to-hast "^11.0.0"
unified "^10.0.0"
remark-mdx@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.1.1.tgz#14021be9ecbc9ad0310f4240980221328aa7ed55"
@ -13832,15 +13510,6 @@ remark-rehype@^10.0.0:
mdast-util-to-hast "^12.1.0"
unified "^10.0.0"
remark-stringify@^10.0.0:
version "10.0.2"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.2.tgz#50414a6983f5008eb9e72eed05f980582d1f69d7"
integrity sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.0.0"
unified "^10.0.0"
remark-stringify@^9.0.0:
version "9.0.1"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894"
@ -13857,16 +13526,6 @@ remark@^13.0.0:
remark-stringify "^9.0.0"
unified "^9.1.0"
remark@^14.0.1:
version "14.0.2"
resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.2.tgz#4a1833f7441a5c29e44b37bb1843fb820797b40f"
integrity sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA==
dependencies:
"@types/mdast" "^3.0.0"
remark-parse "^10.0.0"
remark-stringify "^10.0.0"
unified "^10.0.0"
remarkable@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-2.0.1.tgz#280ae6627384dfb13d98ee3995627ca550a12f31"
@ -14279,7 +13938,7 @@ servify@^0.1.12:
request "^2.79.0"
xhr "^2.3.3"
set-blocking@^2.0.0, set-blocking@~2.0.0:
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
@ -14790,7 +14449,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
stringify-entities@^4.0.0, stringify-entities@^4.0.2:
stringify-entities@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.2.tgz#13d113dc7449dc8ae4cb22c28883ee3fff8753e3"
integrity sha512-MTxTVcEkorNtBbNpoFJPEh0kKdM6+QbMjLbaxmvaPMmayOXdr/AIVIIJX7FReUVweRBFJfZepK4A4AKgwuFpMQ==
@ -14814,7 +14473,7 @@ strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
@ -15233,11 +14892,6 @@ throat@^5.0.0:
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
throat@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375"
integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==
through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -15645,31 +15299,11 @@ turbo@1.2.9:
turbo-windows-64 "1.2.9"
turbo-windows-arm64 "1.2.9"
tween-functions@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff"
integrity sha1-GuOlDnxguz3vd06scHrLynO7w/8=
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
twemoji-parser@13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4"
integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg==
twemoji@^13.0.1:
version "13.1.1"
resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-13.1.1.tgz#6e31409908bb5383cdb1d09c9c8e7856aa6e2e3b"
integrity sha512-IIIoq+n1lk1M1+evBKZD3DO0ud02fDQ4ssbgAv8rp3YBWUeNmskjlisFUPPDacQ50XS3bhrd4Kq9Q2gqhxb0dg==
dependencies:
fs-extra "^8.0.1"
jsonfile "^5.0.0"
twemoji-parser "13.1.0"
universalify "^0.1.2"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@ -15766,11 +15400,6 @@ typescript@4.6.4, typescript@^4.6.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9"
integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==
tzdata@^1.0.30:
version "1.0.30"
resolved "https://registry.yarnpkg.com/tzdata/-/tzdata-1.0.30.tgz#d9d5a4b4b5e1ed95f6255f98c0564c4256316f52"
integrity sha512-/0yogZsIRUVhGIEGZahL+Nnl9gpMD6jtQ9MlVtPVofFwhaqa+cFTgRy1desTAKqdmIJjS6CL+i6F/mnetrLaxw==
uglify-js@^3.1.4:
version "3.15.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471"
@ -16669,13 +16298,6 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
version "1.1.5"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
dependencies:
string-width "^1.0.2 || 2 || 3 || 4"
word-wrap@^1.2.3, word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
@ -16988,17 +16610,6 @@ yup@^0.32.9:
property-expr "^2.0.4"
toposort "^2.0.2"
z-schema@^4.2.3:
version "4.2.4"
resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.2.4.tgz#73102a49512179b12a8ec50b1daa676b984da6e4"
integrity sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==
dependencies:
lodash.get "^4.4.2"
lodash.isequal "^4.5.0"
validator "^13.6.0"
optionalDependencies:
commander "^2.7.1"
zen-observable-ts@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83"