diff --git a/apps/web/components/setup/EnterpriseLicense.tsx b/apps/web/components/setup/EnterpriseLicense.tsx index 5be4a528b1..d30044e920 100644 --- a/apps/web/components/setup/EnterpriseLicense.tsx +++ b/apps/web/components/setup/EnterpriseLicense.tsx @@ -1,4 +1,5 @@ import { zodResolver } from "@hookform/resolvers/zod"; +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useCallback, useState } from "react"; import { Controller, FormProvider, useForm, useFormState } from "react-hook-form"; diff --git a/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx b/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx index f58fd01b50..418133f9d9 100644 --- a/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx +++ b/apps/web/components/ui/UsernameAvailability/PremiumTextfield.tsx @@ -1,4 +1,5 @@ import classNames from "classnames"; +// eslint-disable-next-line no-restricted-imports import { debounce, noop } from "lodash"; import { useSession } from "next-auth/react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; diff --git a/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx b/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx index 316d48a690..e2c046f7aa 100644 --- a/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx +++ b/apps/web/components/ui/UsernameAvailability/UsernameTextfield.tsx @@ -1,4 +1,5 @@ import classNames from "classnames"; +// eslint-disable-next-line no-restricted-imports import { debounce, noop } from "lodash"; import { useSession } from "next-auth/react"; import type { RefCallback } from "react"; diff --git a/apps/web/pages/auth/forgot-password/index.tsx b/apps/web/pages/auth/forgot-password/index.tsx index 2a6717087b..750f86b996 100644 --- a/apps/web/pages/auth/forgot-password/index.tsx +++ b/apps/web/pages/auth/forgot-password/index.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { debounce } from "lodash"; import type { GetServerSidePropsContext } from "next"; import { getCsrfToken } from "next-auth/react"; diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts index 01af676146..3f317ebc95 100644 --- a/apps/web/playwright/lib/testUtils.ts +++ b/apps/web/playwright/lib/testUtils.ts @@ -2,6 +2,7 @@ import type { Page } from "@playwright/test"; import { expect } from "@playwright/test"; import type { IncomingMessage, ServerResponse } from "http"; import { createServer } from "http"; +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { test } from "./fixtures"; diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index c77ca78645..d172f4df25 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -929,7 +929,7 @@ "verify_wallet": "Verify Wallet", "create_events_on": "Create events on", "enterprise_license": "This is an enterprise feature", - "enterprise_license_description": "To enable this feature, have an administrator go to {{setupUrl}} to enter a license key. If a license key is already in place, please contact {{supportMail}} for help.", + "enterprise_license_description": "To enable this feature, have an administrator go to <2>/auth/setup to enter a license key. If a license key is already in place, please contact <5>{{SUPPORT_MAIL_ADDRESS}} for help.", "enterprise_license_development": "You can test this feature on development mode. For production usage please have an administrator go to <2>/auth/setup to enter a license key.", "missing_license": "Missing License", "signup_requires": "Commercial license required", diff --git a/package.json b/package.json index 774d1b8836..7c993a5e7a 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,6 @@ "@playwright/test": "^1.31.2", "@snaplet/copycat": "^0.3.0", "@testing-library/jest-dom": "^5.16.5", - "@types/dompurify": "^2.4.0", "c8": "^7.13.0", "dotenv-checker": "^1.1.5", "husky": "^8.0.0", diff --git a/packages/app-store-cli/src/build.ts b/packages/app-store-cli/src/build.ts index df2f19906a..6469db035c 100644 --- a/packages/app-store-cli/src/build.ts +++ b/packages/app-store-cli/src/build.ts @@ -1,5 +1,6 @@ import chokidar from "chokidar"; import fs from "fs"; +// eslint-disable-next-line no-restricted-imports import { debounce } from "lodash"; import path from "path"; import prettier from "prettier"; @@ -7,7 +8,7 @@ import prettier from "prettier"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore import prettierConfig from "@calcom/config/prettier-preset"; -import { AppMeta } from "@calcom/types/App"; +import type { AppMeta } from "@calcom/types/App"; import { APP_STORE_PATH } from "./constants"; import { getAppName } from "./utils/getAppName"; diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx index 66d230a7a8..4e018496f4 100644 --- a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx +++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx @@ -1,3 +1,4 @@ +import dynamic from "next/dynamic"; import type { ChangeEvent } from "react"; import type { ButtonGroupProps, @@ -7,9 +8,13 @@ import type { ProviderProps, } from "react-awesome-query-builder"; -import { Button as CalButton, SelectWithValidation as Select, TextField, TextArea } from "@calcom/ui"; +import { Button as CalButton, TextField, TextArea } from "@calcom/ui"; import { Trash, Plus } from "@calcom/ui/components/icon"; +const Select = dynamic( + async () => (await import("@calcom/ui")).SelectWithValidation +) as unknown as typeof import("@calcom/ui").SelectWithValidation; + export type CommonProps< TVal extends | string diff --git a/packages/config/eslint-preset.js b/packages/config/eslint-preset.js index 0d364f0b73..e608c4f4df 100644 --- a/packages/config/eslint-preset.js +++ b/packages/config/eslint-preset.js @@ -36,6 +36,12 @@ module.exports = { }, ], "unused-imports/no-unused-imports": "error", + "no-restricted-imports": [ + "error", + { + patterns: ["lodash"], + }, + ], }, overrides: [ { diff --git a/packages/core/CalendarManager.ts b/packages/core/CalendarManager.ts index f1786a97b2..b256eb1cfc 100644 --- a/packages/core/CalendarManager.ts +++ b/packages/core/CalendarManager.ts @@ -1,4 +1,5 @@ import type { SelectedCalendar } from "@prisma/client"; +// eslint-disable-next-line no-restricted-imports import { sortBy } from "lodash"; import { getCalendar } from "@calcom/app-store/_utils/getCalendar"; diff --git a/packages/core/EventManager.ts b/packages/core/EventManager.ts index 0f0b465977..72aa75eb68 100644 --- a/packages/core/EventManager.ts +++ b/packages/core/EventManager.ts @@ -1,4 +1,5 @@ import type { DestinationCalendar, Booking } from "@prisma/client"; +// eslint-disable-next-line no-restricted-imports import { cloneDeep, merge } from "lodash"; import { v5 as uuidv5 } from "uuid"; import type { z } from "zod"; diff --git a/packages/emails/email-manager.ts b/packages/emails/email-manager.ts index 91e381b2b0..1608809787 100644 --- a/packages/emails/email-manager.ts +++ b/packages/emails/email-manager.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { TFunction } from "next-i18next"; diff --git a/packages/emails/templates/attendee-scheduled-email.ts b/packages/emails/templates/attendee-scheduled-email.ts index b483677267..0d22891118 100644 --- a/packages/emails/templates/attendee-scheduled-email.ts +++ b/packages/emails/templates/attendee-scheduled-email.ts @@ -1,5 +1,6 @@ import type { DateArray, ParticipationStatus, ParticipationRole } from "ics"; import { createEvent } from "ics"; +// eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { TFunction } from "next-i18next"; import { RRule } from "rrule"; diff --git a/packages/emails/templates/organizer-scheduled-email.ts b/packages/emails/templates/organizer-scheduled-email.ts index df2c6dd476..9592c63869 100644 --- a/packages/emails/templates/organizer-scheduled-email.ts +++ b/packages/emails/templates/organizer-scheduled-email.ts @@ -1,5 +1,6 @@ import type { DateArray } from "ics"; import { createEvent } from "ics"; +// eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { TFunction } from "next-i18next"; import { RRule } from "rrule"; diff --git a/packages/features/apps/AdminAppsList.tsx b/packages/features/apps/AdminAppsList.tsx index 51f7d30c55..5991687276 100644 --- a/packages/features/apps/AdminAppsList.tsx +++ b/packages/features/apps/AdminAppsList.tsx @@ -1,4 +1,5 @@ import { zodResolver } from "@hookform/resolvers/zod"; +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useSearchParams } from "next/navigation"; import type { FC } from "react"; diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index 31668800f4..eb8ed25479 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -2,6 +2,7 @@ import type { App, Attendee, Credential, EventTypeCustomInput } from "@prisma/cl import { Prisma } from "@prisma/client"; import async from "async"; import { isValidPhoneNumber } from "libphonenumber-js"; +// eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; import type { NextApiRequest } from "next"; import short, { uuid } from "short-uuid"; diff --git a/packages/features/ee/common/components/LicenseRequired.tsx b/packages/features/ee/common/components/LicenseRequired.tsx index 47a960ae47..e34134cc97 100644 --- a/packages/features/ee/common/components/LicenseRequired.tsx +++ b/packages/features/ee/common/components/LicenseRequired.tsx @@ -1,10 +1,9 @@ -import DOMPurify from "dompurify"; import { useSession } from "next-auth/react"; import { Trans } from "next-i18next"; import type { AriaRole, ComponentType } from "react"; import React, { Fragment, useEffect } from "react"; -import { APP_NAME, CONSOLE_URL, SUPPORT_MAIL_ADDRESS, WEBAPP_URL } from "@calcom/lib/constants"; +import { SUPPORT_MAIL_ADDRESS, WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { EmptyScreen, TopBanner } from "@calcom/ui"; import { AlertTriangle } from "@calcom/ui/components/icon"; @@ -62,20 +61,17 @@ const LicenseRequired = ({ children, as = "", ...rest }: LicenseRequiredProps) = Icon={AlertTriangle} headline={t("enterprise_license")} description={ -
- ${APP_NAME} - `, - setupUrl: `/auth/setup`, - supportMail: ` - ${SUPPORT_MAIL_ADDRESS}`, - }) - ), - }} - /> + + To enable this feature, have an administrator go to{" "} + + /auth/setup + + to enter a license key. If a license key is already in place, please contact{" "} + + {{ SUPPORT_MAIL_ADDRESS }} + + for help. + } /> )} diff --git a/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx b/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx index b719d3e2ac..55f3c9922f 100644 --- a/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx +++ b/packages/features/ee/managed-event-types/hooks/useLockedFieldsManager.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { get } from "lodash"; import React from "react"; import type z from "zod"; diff --git a/packages/features/ee/support/lib/intercom/useIntercom.ts b/packages/features/ee/support/lib/intercom/useIntercom.ts index 76e7a68e1d..6675a570f7 100644 --- a/packages/features/ee/support/lib/intercom/useIntercom.ts +++ b/packages/features/ee/support/lib/intercom/useIntercom.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useIntercom as useIntercomLib } from "react-use-intercom"; import { z } from "zod"; diff --git a/packages/features/ee/users/components/UserForm.tsx b/packages/features/ee/users/components/UserForm.tsx index 898641ab0e..130682e2bc 100644 --- a/packages/features/ee/users/components/UserForm.tsx +++ b/packages/features/ee/users/components/UserForm.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { Controller, useForm } from "react-hook-form"; diff --git a/packages/features/package.json b/packages/features/package.json index 5763dbdffb..4f27f21a0f 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -13,7 +13,6 @@ "@calcom/ui": "*", "@lexical/react": "^0.9.0", "@tanstack/react-table": "^8.9.3", - "dompurify": "^2.4.1", "framer-motion": "^10.12.8", "lexical": "^0.9.0", "react-select": "^5.7.0", diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index c14619f141..9216701c78 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -1,6 +1,5 @@ import type { Prisma } from "@prisma/client"; import type { UnitTypeLongPlural } from "dayjs"; -import { pick } from "lodash"; import z, { ZodNullable, ZodObject, ZodOptional } from "zod"; /* eslint-disable no-underscore-dangle */ @@ -589,7 +588,9 @@ export const allManagedEventTypeProps: { [k in keyof Omit = { form: UseFormReturn; handleSubmit: SubmitHandler } & Omit< + JSX.IntrinsicElements["form"], + "onSubmit" +>; + +const PlainForm = (props: FormProps, ref: Ref) => { + const { form, handleSubmit, ...passThrough } = props; + + return ( + +
{ + event.preventDefault(); + event.stopPropagation(); + + form + .handleSubmit(handleSubmit)(event) + .catch((err) => { + // FIXME: Booking Pages don't have toast, so this error is never shown + showToast(`${getErrorFromUnknown(err).message}`, "error"); + }); + }} + {...passThrough}> + {props.children} +
+
+ ); +}; + +export const Form = forwardRef(PlainForm) as ( + p: FormProps & { ref?: Ref } +) => ReactElement; diff --git a/packages/ui/components/form/inputs/Input.tsx b/packages/ui/components/form/inputs/Input.tsx index 5a5619df18..5944b40ec6 100644 --- a/packages/ui/components/form/inputs/Input.tsx +++ b/packages/ui/components/form/inputs/Input.tsx @@ -1,35 +1,14 @@ -import type { ReactElement, ReactNode, Ref } from "react"; +import type { ReactNode } from "react"; import React, { forwardRef, useCallback, useId, useState } from "react"; -import type { FieldValues, SubmitHandler, UseFormReturn } from "react-hook-form"; -import { FormProvider, useFormContext } from "react-hook-form"; +import { useFormContext } from "react-hook-form"; import classNames from "@calcom/lib/classNames"; -import { getErrorFromUnknown } from "@calcom/lib/errors"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Alert, showToast, Skeleton, Tooltip, UnstyledSelect } from "../../.."; -import { Eye, EyeOff, X, Search } from "../../icon"; -import { HintsOrErrors } from "./HintOrErrors"; +import { Alert, Input, InputField, Tooltip } from "../../.."; +import { Eye, EyeOff, Search } from "../../icon"; import { Label } from "./Label"; - -type InputProps = JSX.IntrinsicElements["input"] & { isFullWidth?: boolean }; - -export const Input = forwardRef(function Input( - { isFullWidth = true, ...props }, - ref -) { - return ( - - ); -}); +import type { InputFieldProps } from "./types"; export function InputLeading(props: JSX.IntrinsicElements["div"]) { return ( @@ -39,174 +18,6 @@ export function InputLeading(props: JSX.IntrinsicElements["div"]) { ); } -type InputFieldProps = { - label?: ReactNode; - LockedIcon?: React.ReactNode; - hint?: ReactNode; - hintErrors?: string[]; - addOnLeading?: ReactNode; - addOnSuffix?: ReactNode; - inputIsFullWidth?: boolean; - addOnFilled?: boolean; - addOnClassname?: string; - error?: string; - labelSrOnly?: boolean; - containerClassName?: string; - showAsteriskIndicator?: boolean; - t?: (key: string) => string; -} & React.ComponentProps & { - labelProps?: React.ComponentProps; - labelClassName?: string; - }; - -type AddonProps = { - children: React.ReactNode; - isFilled?: boolean; - className?: string; - error?: boolean; -}; - -const Addon = ({ isFilled, children, className, error }: AddonProps) => ( -
-
- {children} -
-
-); - -export const InputField = forwardRef(function InputField(props, ref) { - const id = useId(); - const { t: _t, isLocaleReady, i18n } = useLocale(); - const t = props.t || _t; - const name = props.name || ""; - const { - label = t(name), - labelProps, - labelClassName, - disabled, - LockedIcon, - placeholder = isLocaleReady && i18n.exists(name + "_placeholder") ? t(name + "_placeholder") : "", - className, - addOnLeading, - addOnSuffix, - addOnFilled = true, - addOnClassname, - inputIsFullWidth, - hint, - type, - hintErrors, - labelSrOnly, - containerClassName, - readOnly, - showAsteriskIndicator, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - t: __t, - ...passThrough - } = props; - - const [inputValue, setInputValue] = useState(""); - - return ( -
- {!!name && ( - - {label} - {showAsteriskIndicator && !readOnly && passThrough.required ? ( - * - ) : null} - {LockedIcon} - - )} - {addOnLeading || addOnSuffix ? ( -
- {addOnLeading && ( - - {addOnLeading} - - )} - { - setInputValue(e.target.value); - props.onChange && props.onChange(e); - }, - value: inputValue, - })} - disabled={readOnly || disabled} - ref={ref} - /> - {addOnSuffix && ( - - {addOnSuffix} - - )} - {type === "search" && inputValue?.toString().length > 0 && ( - { - setInputValue(""); - props.onChange && props.onChange(e as unknown as React.ChangeEvent); - }} - /> - )} -
- ) : ( - - )} - - {hint &&
{hint}
} -
- ); -}); - -export const TextField = forwardRef(function TextField(props, ref) { - return ; -}); - export const PasswordField = forwardRef(function PasswordField( props, ref @@ -335,40 +146,6 @@ export const TextAreaField = forwardRef ); }); -type FormProps = { form: UseFormReturn; handleSubmit: SubmitHandler } & Omit< - JSX.IntrinsicElements["form"], - "onSubmit" ->; - -const PlainForm = (props: FormProps, ref: Ref) => { - const { form, handleSubmit, ...passThrough } = props; - - return ( - -
{ - event.preventDefault(); - event.stopPropagation(); - - form - .handleSubmit(handleSubmit)(event) - .catch((err) => { - // FIXME: Booking Pages don't have toast, so this error is never shown - showToast(`${getErrorFromUnknown(err).message}`, "error"); - }); - }} - {...passThrough}> - {props.children} -
-
- ); -}; - -export const Form = forwardRef(PlainForm) as ( - p: FormProps & { ref?: Ref } -) => ReactElement; - export function FieldsetLegend(props: JSX.IntrinsicElements["legend"]) { return ( @@ -387,21 +164,6 @@ export function InputGroupBox(props: JSX.IntrinsicElements["div"]) { ); } -export const InputFieldWithSelect = forwardRef< - HTMLInputElement, - InputFieldProps & { selectProps: typeof UnstyledSelect } ->(function EmailField(props, ref) { - return ( - } - /> - ); -}); - export const NumberInput = forwardRef(function NumberInput(props, ref) { return ( (function EmailField(props, ref) { + return ( + } + /> + ); +}); diff --git a/packages/ui/components/form/inputs/TextField.tsx b/packages/ui/components/form/inputs/TextField.tsx new file mode 100644 index 0000000000..e393c58cae --- /dev/null +++ b/packages/ui/components/form/inputs/TextField.tsx @@ -0,0 +1,175 @@ +import React, { forwardRef, useId, useState } from "react"; + +import classNames from "@calcom/lib/classNames"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; + +import { Skeleton } from "../../.."; +import { X } from "../../icon"; +import { HintsOrErrors } from "./HintOrErrors"; +import { Label } from "./Label"; +import type { InputFieldProps, InputProps } from "./types"; + +export const Input = forwardRef(function Input( + { isFullWidth = true, ...props }, + ref +) { + return ( + + ); +}); + +type AddonProps = { + children: React.ReactNode; + isFilled?: boolean; + className?: string; + error?: boolean; +}; + +const Addon = ({ isFilled, children, className, error }: AddonProps) => ( +
+
+ {children} +
+
+); + +export const InputField = forwardRef(function InputField(props, ref) { + const id = useId(); + const { t: _t, isLocaleReady, i18n } = useLocale(); + const t = props.t || _t; + const name = props.name || ""; + const { + label = t(name), + labelProps, + labelClassName, + disabled, + LockedIcon, + placeholder = isLocaleReady && i18n.exists(name + "_placeholder") ? t(name + "_placeholder") : "", + className, + addOnLeading, + addOnSuffix, + addOnFilled = true, + addOnClassname, + inputIsFullWidth, + hint, + type, + hintErrors, + labelSrOnly, + containerClassName, + readOnly, + showAsteriskIndicator, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + t: __t, + ...passThrough + } = props; + + const [inputValue, setInputValue] = useState(""); + + return ( +
+ {!!name && ( + + {label} + {showAsteriskIndicator && !readOnly && passThrough.required ? ( + * + ) : null} + {LockedIcon} + + )} + {addOnLeading || addOnSuffix ? ( +
+ {addOnLeading && ( + + {addOnLeading} + + )} + { + setInputValue(e.target.value); + props.onChange && props.onChange(e); + }, + value: inputValue, + })} + disabled={readOnly || disabled} + ref={ref} + /> + {addOnSuffix && ( + + {addOnSuffix} + + )} + {type === "search" && inputValue?.toString().length > 0 && ( + { + setInputValue(""); + props.onChange && props.onChange(e as unknown as React.ChangeEvent); + }} + /> + )} +
+ ) : ( + + )} + + {hint &&
{hint}
} +
+ ); +}); + +export const TextField = forwardRef(function TextField(props, ref) { + return ; +}); diff --git a/packages/ui/components/form/inputs/input.test.tsx b/packages/ui/components/form/inputs/input.test.tsx index 95301ae02f..dbfbd1c160 100644 --- a/packages/ui/components/form/inputs/input.test.tsx +++ b/packages/ui/components/form/inputs/input.test.tsx @@ -4,15 +4,9 @@ import { render, fireEvent } from "@testing-library/react"; import { vi } from "vitest"; import type { UnstyledSelect } from "../../../form/Select"; -import { - EmailField, - TextAreaField, - InputField, - PasswordField, - NumberInput, - FilterSearchField, - InputFieldWithSelect, -} from "./Input"; +import { EmailField, TextAreaField, PasswordField, NumberInput, FilterSearchField } from "./Input"; +import { InputFieldWithSelect } from "./InputFieldWithSelect"; +import { InputField } from "./TextField"; const onChangeMock = vi.fn(); diff --git a/packages/ui/components/form/inputs/types.d.ts b/packages/ui/components/form/inputs/types.d.ts new file mode 100644 index 0000000000..55545c20a8 --- /dev/null +++ b/packages/ui/components/form/inputs/types.d.ts @@ -0,0 +1,25 @@ +import type { ReactNode } from "react"; + +import type { Input } from "./TextField"; + +export type InputFieldProps = { + label?: ReactNode; + LockedIcon?: React.ReactNode; + hint?: ReactNode; + hintErrors?: string[]; + addOnLeading?: ReactNode; + addOnSuffix?: ReactNode; + inputIsFullWidth?: boolean; + addOnFilled?: boolean; + addOnClassname?: string; + error?: string; + labelSrOnly?: boolean; + containerClassName?: string; + showAsteriskIndicator?: boolean; + t?: (key: string) => string; +} & React.ComponentProps & { + labelProps?: React.ComponentProps; + labelClassName?: string; + }; + +export type InputProps = JSX.IntrinsicElements["input"] & { isFullWidth?: boolean }; diff --git a/packages/ui/components/form/wizard/WizardForm.tsx b/packages/ui/components/form/wizard/WizardForm.tsx index 9aa9df385f..bf5e01a13e 100644 --- a/packages/ui/components/form/wizard/WizardForm.tsx +++ b/packages/ui/components/form/wizard/WizardForm.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useRouter, useSearchParams } from "next/navigation"; import type { Dispatch, SetStateAction } from "react"; diff --git a/packages/ui/components/head-seo/HeadSeo.tsx b/packages/ui/components/head-seo/HeadSeo.tsx index a45db2f0a5..63a5cca048 100644 --- a/packages/ui/components/head-seo/HeadSeo.tsx +++ b/packages/ui/components/head-seo/HeadSeo.tsx @@ -1,4 +1,3 @@ -import { merge } from "lodash"; import type { NextSeoProps } from "next-seo"; import { NextSeo } from "next-seo"; import { usePathname } from "next/navigation"; @@ -31,7 +30,7 @@ const buildSeoMeta = (pageProps: { siteName?: string; url?: string; canonical?: string; -}): NextSeoProps => { +}) => { const { title, description, image, canonical, siteName = seoConfig.headSeo.siteName } = pageProps; return { title: title, @@ -123,7 +122,18 @@ export const HeadSeo = (props: HeadSeoProps): JSX.Element => { }); } - const seoProps: NextSeoProps = merge(nextSeoProps, seoObject); + // Instead of doing a blackbox deep merge which can be tricky implementation wise and need a good implementation, we should generate the object manually as we know the properties + // Goal is to avoid big dependency + const seoProps: NextSeoProps = { + ...nextSeoProps, + ...seoObject, + openGraph: { + ...nextSeoProps.openGraph, + ...seoObject.openGraph, + images: [...(nextSeoProps.openGraph?.images || []), ...seoObject.openGraph.images], + }, + additionalMetaTags: [...(nextSeoProps.additionalMetaTags || [])], + }; return ; }; diff --git a/packages/ui/components/top-banner/TopBanner.tsx b/packages/ui/components/top-banner/TopBanner.tsx index a911a1ceb4..3ea60d38f0 100644 --- a/packages/ui/components/top-banner/TopBanner.tsx +++ b/packages/ui/components/top-banner/TopBanner.tsx @@ -1,4 +1,5 @@ import classNames from "classnames"; +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import type { ComponentType, ReactNode } from "react"; diff --git a/packages/ui/layouts/WizardLayout.tsx b/packages/ui/layouts/WizardLayout.tsx index ca4b9d69be..0ca7d4e43f 100644 --- a/packages/ui/layouts/WizardLayout.tsx +++ b/packages/ui/layouts/WizardLayout.tsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { usePathname } from "next/navigation"; import React, { useEffect, useState } from "react"; diff --git a/yarn.lock b/yarn.lock index 4db66d222b..0218ddf599 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4255,7 +4255,6 @@ __metadata: "@lexical/react": ^0.9.0 "@tanstack/react-table": ^8.9.3 "@testing-library/react-hooks": ^8.0.1 - dompurify: ^2.4.1 framer-motion: ^10.12.8 lexical: ^0.9.0 react-select: ^5.7.0 @@ -4608,6 +4607,7 @@ __metadata: rollup-plugin-polyfill-node: ^0.10.2 storybook-addon-designs: ^6.3.1 storybook-addon-next: ^1.6.9 + storybook-addon-next-router: ^4.0.2 storybook-addon-rtl-direction: ^0.0.19 storybook-react-i18next: ^1.1.2 tailwindcss: ^3.3.1 @@ -5012,6 +5012,7 @@ __metadata: next-collect: ^0.2.1 next-i18next: ^13.2.2 next-seo: ^6.0.0 + playwright: ^1.31.2 postcss: ^8.4.18 prism-react-renderer: ^1.3.5 react: ^18.2.0 @@ -12033,15 +12034,6 @@ __metadata: languageName: node linkType: hard -"@types/dompurify@npm:^2.4.0": - version: 2.4.0 - resolution: "@types/dompurify@npm:2.4.0" - dependencies: - "@types/trusted-types": "*" - checksum: b48cd81e997794ebc390c7c5bef1a67ec14a6f2f0521973e07e06af186c7583abe114d94d24868c0632b9573f5bd77131a4b76f3fffdf089ba99a4e53dd46c39 - languageName: node - linkType: hard - "@types/eslint-scope@npm:^3.7.3": version: 3.7.4 resolution: "@types/eslint-scope@npm:3.7.4" @@ -12723,7 +12715,7 @@ __metadata: languageName: node linkType: hard -"@types/trusted-types@npm:*, @types/trusted-types@npm:^2.0.2": +"@types/trusted-types@npm:^2.0.2": version: 2.0.2 resolution: "@types/trusted-types@npm:2.0.2" checksum: 3371eef5f1c50e1c3c07a127c1207b262ba65b83dd167a1c460fc1b135a3fb0c97b9f508efebd383f239cc5dd5b7169093686a692a501fde9c3f7208657d9b0d @@ -15747,7 +15739,6 @@ __metadata: "@playwright/test": ^1.31.2 "@snaplet/copycat": ^0.3.0 "@testing-library/jest-dom": ^5.16.5 - "@types/dompurify": ^2.4.0 c8: ^7.13.0 city-timezones: ^1.2.1 dotenv-checker: ^1.1.5 @@ -18281,13 +18272,6 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:^2.4.1": - version: 2.4.1 - resolution: "dompurify@npm:2.4.1" - checksum: 1169177465b3cbb25a44322937fba549f6c4e1a91b83245d144471be26619c835cccf0f8e20aa78c25ac11a06efd17cc1b9db9cacadceb78a4c08a1029eafee5 - languageName: node - linkType: hard - "domutils@npm:^2.0.0, domutils@npm:^2.5.2, domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" @@ -28929,6 +28913,26 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.37.1": + version: 1.37.1 + resolution: "playwright-core@npm:1.37.1" + bin: + playwright-core: cli.js + checksum: 69f818da2230057584140d5b3af7778a4f4a822b5b18d133abfc5d259128becb943c343a2ddf6b0635277a69f28983e83e2bc3fce23595ececb1e410475b6368 + languageName: node + linkType: hard + +"playwright@npm:^1.31.2": + version: 1.37.1 + resolution: "playwright@npm:1.37.1" + dependencies: + playwright-core: 1.37.1 + bin: + playwright: cli.js + checksum: 99406ef3e15b83a659cb23ef1d92d9935789aad430580d1e0371087dfdf266891483c6f97cfa06bf5f49f081eacd44245d05d20714f98531edef4cc317044d6b + languageName: node + linkType: hard + "pngjs@npm:^3.0.0, pngjs@npm:^3.3.3": version: 3.4.0 resolution: "pngjs@npm:3.4.0" @@ -33188,6 +33192,22 @@ __metadata: languageName: node linkType: hard +"storybook-addon-next-router@npm:^4.0.2": + version: 4.0.2 + resolution: "storybook-addon-next-router@npm:4.0.2" + dependencies: + tslib: 2.4.0 + peerDependencies: + "@storybook/addon-actions": ^6.0.0 + "@storybook/addons": ^6.0.0 + "@storybook/client-api": ^6.0.0 + next: ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 5e3d1b2510700c21d175e10d56bcad970a8b390715bbd8e9767528e60165c4bc651ef94a7a854f042185454c51c57d884b03c625c0ee28000d3916e11a6d865f + languageName: node + linkType: hard + "storybook-addon-next@npm:^1.6.9": version: 1.6.9 resolution: "storybook-addon-next@npm:1.6.9" @@ -34929,6 +34949,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.4.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 + languageName: node + linkType: hard + "tslib@npm:^1.0.0, tslib@npm:^1.11.1, tslib@npm:^1.8.1, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -34936,13 +34963,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.0.3": - version: 2.4.0 - resolution: "tslib@npm:2.4.0" - checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 - languageName: node - linkType: hard - "tslib@npm:^2.2.0": version: 2.4.1 resolution: "tslib@npm:2.4.1"