From 552c10139efe6fa79913233ab4d08ad26cad519e Mon Sep 17 00:00:00 2001 From: Ryan Laurie <30528226+iethree@users.noreply.github.com> Date: Fri, 26 Apr 2024 14:33:15 -0600 Subject: [PATCH] Remove defunct form components (#41902) * remove defunct form components * fix lil type errros --- .../UnsubscribeUserForm.jsx | 2 +- .../SettingsJWTForm/SettingsJWTForm.tsx | 2 +- .../SettingsSAMLForm/SettingsSAMLForm.jsx | 2 +- .../components/ArchiveModal/ArchiveModal.jsx | 2 +- .../UnsubscribeModal/UnsubscribeModal.jsx | 2 +- .../components/DatabaseList/DatabaseList.jsx | 2 +- .../settings/components/SettingsLdapForm.tsx | 2 +- .../components/ArchiveModal/ArchiveModal.jsx | 2 +- .../components/form/FormMessage/index.ts | 2 - .../metabase/components/form/FormWidget.jsx | 62 ----- .../form/FormikCustomForm/CustomForm.tsx | 71 ----- .../form/FormikCustomForm/CustomFormField.tsx | 115 -------- .../FormikCustomForm/CustomFormFooter.tsx | 67 ----- .../FormikCustomForm/CustomFormMessage.tsx | 22 -- .../FormikCustomForm/CustomFormSubmit.tsx | 56 ---- .../form/FormikCustomForm/context.ts | 24 -- .../components/form/FormikCustomForm/index.ts | 9 - .../components/form/FormikCustomForm/types.ts | 104 -------- .../form/FormikFormField/FormField.styled.tsx | 60 ----- .../form/FormikFormField/FormField.tsx | 131 --------- .../FormikFormField/FormFieldDescription.tsx | 21 -- .../form/FormikFormField/FormFieldView.tsx | 96 ------- .../components/form/FormikFormField/index.ts | 2 - .../components/form/FormikStandardForm.tsx | 48 ---- .../form/widgets/FormBooleanWidget.jsx | 13 - .../form/widgets/FormCheckBoxWidget.jsx | 13 - .../form/widgets/FormCollectionWidget.jsx | 6 - .../form/widgets/FormColorWidget.jsx | 15 -- .../form/widgets/FormEmailWidget.jsx | 5 - .../form/widgets/FormHiddenWidget.jsx | 8 - .../form/widgets/FormInfoWidget.jsx | 13 - .../form/widgets/FormInputWidget.jsx | 55 ---- .../form/widgets/FormNumericInputWidget.jsx | 18 -- .../form/widgets/FormPasswordWidget.jsx | 7 - .../form/widgets/FormRadioWidget.jsx | 21 -- .../FormSectionWidget.styled.tsx | 15 -- .../FormSectionWidget/FormSectionWidget.tsx | 30 --- .../form/widgets/FormSectionWidget/index.ts | 2 - .../form/widgets/FormSectionWidget/types.ts | 4 - .../form/widgets/FormSelectWidget.jsx | 21 -- .../widgets/FormSnippetCollectionWidget.jsx | 21 -- .../FormTextAreaWidget/FormTextAreaWidget.jsx | 40 --- .../FormTextAreaWidget.styled.tsx | 6 - .../form/widgets/FormTextAreaWidget/index.js | 1 - .../FormTextFileWidget/FormTextFileWidget.tsx | 60 ----- .../form/widgets/FormTextFileWidget/index.ts | 2 - .../form/widgets/FormTextFileWidget/types.ts | 9 - .../containers/FormikForm/FormView.tsx | 20 -- .../containers/FormikForm/FormikForm.tsx | 252 ------------------ .../FormikForm/FormikFormViewAdapter.tsx | 142 ---------- .../metabase/containers/FormikForm/index.ts | 3 - .../containers/FormikForm/useInlineFields.ts | 27 -- .../entities/containers/EntityCopyModal.tsx | 6 +- .../FormMessage/FormMessage.styled.tsx | 0 .../components}/FormMessage/FormMessage.tsx | 8 +- .../forms/components/FormMessage/index.ts | 1 + .../FormSection/FormSection.styled.tsx} | 0 .../components/FormSection/FormSection.tsx} | 10 +- .../forms/components/FormSection/index.ts | 1 + .../src/metabase/forms/components/index.ts | 2 + .../metabase/plugins/builtin/auth/google.js | 3 +- 61 files changed, 19 insertions(+), 1747 deletions(-) delete mode 100644 frontend/src/metabase/components/form/FormMessage/index.ts delete mode 100644 frontend/src/metabase/components/form/FormWidget.jsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/CustomForm.tsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/CustomFormField.tsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/CustomFormFooter.tsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/CustomFormMessage.tsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/CustomFormSubmit.tsx delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/context.ts delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/index.ts delete mode 100644 frontend/src/metabase/components/form/FormikCustomForm/types.ts delete mode 100644 frontend/src/metabase/components/form/FormikFormField/FormField.styled.tsx delete mode 100644 frontend/src/metabase/components/form/FormikFormField/FormField.tsx delete mode 100644 frontend/src/metabase/components/form/FormikFormField/FormFieldDescription.tsx delete mode 100644 frontend/src/metabase/components/form/FormikFormField/FormFieldView.tsx delete mode 100644 frontend/src/metabase/components/form/FormikFormField/index.ts delete mode 100644 frontend/src/metabase/components/form/FormikStandardForm.tsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormBooleanWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormCheckBoxWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormCollectionWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormColorWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormEmailWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormHiddenWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormInfoWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormInputWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormNumericInputWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormPasswordWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormRadioWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.styled.tsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.tsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormSectionWidget/index.ts delete mode 100644 frontend/src/metabase/components/form/widgets/FormSectionWidget/types.ts delete mode 100644 frontend/src/metabase/components/form/widgets/FormSelectWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormSnippetCollectionWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.jsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.styled.tsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextAreaWidget/index.js delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextFileWidget/FormTextFileWidget.tsx delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextFileWidget/index.ts delete mode 100644 frontend/src/metabase/components/form/widgets/FormTextFileWidget/types.ts delete mode 100644 frontend/src/metabase/containers/FormikForm/FormView.tsx delete mode 100644 frontend/src/metabase/containers/FormikForm/FormikForm.tsx delete mode 100644 frontend/src/metabase/containers/FormikForm/FormikFormViewAdapter.tsx delete mode 100644 frontend/src/metabase/containers/FormikForm/index.ts delete mode 100644 frontend/src/metabase/containers/FormikForm/useInlineFields.ts rename frontend/src/metabase/{components/form => forms/components}/FormMessage/FormMessage.styled.tsx (100%) rename frontend/src/metabase/{components/form => forms/components}/FormMessage/FormMessage.tsx (90%) create mode 100644 frontend/src/metabase/forms/components/FormMessage/index.ts rename frontend/src/metabase/{components/form/FormikCustomForm/CustomFormSection.styled.tsx => forms/components/FormSection/FormSection.styled.tsx} (100%) rename frontend/src/metabase/{components/form/FormikCustomForm/CustomFormSection.tsx => forms/components/FormSection/FormSection.tsx} (80%) create mode 100644 frontend/src/metabase/forms/components/FormSection/index.ts diff --git a/enterprise/frontend/src/metabase-enterprise/audit_app/components/UnsubscribeUserForm/UnsubscribeUserForm.jsx b/enterprise/frontend/src/metabase-enterprise/audit_app/components/UnsubscribeUserForm/UnsubscribeUserForm.jsx index 9d4548a1961..1ba9b63ef12 100644 --- a/enterprise/frontend/src/metabase-enterprise/audit_app/components/UnsubscribeUserForm/UnsubscribeUserForm.jsx +++ b/enterprise/frontend/src/metabase-enterprise/audit_app/components/UnsubscribeUserForm/UnsubscribeUserForm.jsx @@ -3,8 +3,8 @@ import { useCallback, useState } from "react"; import { t } from "ttag"; import ModalContent from "metabase/components/ModalContent"; -import FormMessage from "metabase/components/form/FormMessage"; import Button from "metabase/core/components/Button"; +import { FormMessage } from "metabase/forms"; import { ModalMessage } from "./UnsubscribeUserForm.styled"; diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsJWTForm/SettingsJWTForm.tsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsJWTForm/SettingsJWTForm.tsx index 41ffccb945f..5e943e260a2 100644 --- a/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsJWTForm/SettingsJWTForm.tsx +++ b/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsJWTForm/SettingsJWTForm.tsx @@ -8,9 +8,9 @@ import GroupMappingsWidget from "metabase/admin/settings/containers/GroupMapping import { updateSettings } from "metabase/admin/settings/settings"; import type { SettingElement } from "metabase/admin/settings/types"; import Breadcrumbs from "metabase/components/Breadcrumbs"; -import { FormSection } from "metabase/containers/FormikForm"; import CS from "metabase/css/core/index.css"; import { + FormSection, Form, FormErrorMessage, FormProvider, diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsSAMLForm/SettingsSAMLForm.jsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsSAMLForm/SettingsSAMLForm.jsx index 4ce902d3692..327a95ffd35 100644 --- a/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsSAMLForm/SettingsSAMLForm.jsx +++ b/enterprise/frontend/src/metabase-enterprise/auth/components/SettingsSAMLForm/SettingsSAMLForm.jsx @@ -10,10 +10,10 @@ import GroupMappingsWidget from "metabase/admin/settings/containers/GroupMapping import { updateSamlSettings } from "metabase/admin/settings/settings"; import { settingToFormField } from "metabase/admin/settings/utils"; import Breadcrumbs from "metabase/components/Breadcrumbs"; -import { FormSection } from "metabase/containers/FormikForm"; import ExternalLink from "metabase/core/components/ExternalLink"; import CS from "metabase/css/core/index.css"; import { + FormSection, Form, FormErrorMessage, FormProvider, diff --git a/frontend/src/metabase/account/notifications/components/ArchiveModal/ArchiveModal.jsx b/frontend/src/metabase/account/notifications/components/ArchiveModal/ArchiveModal.jsx index bda4add0c32..e7cdbd06629 100644 --- a/frontend/src/metabase/account/notifications/components/ArchiveModal/ArchiveModal.jsx +++ b/frontend/src/metabase/account/notifications/components/ArchiveModal/ArchiveModal.jsx @@ -3,8 +3,8 @@ import { useCallback, useState } from "react"; import { t } from "ttag"; import ModalContent from "metabase/components/ModalContent"; -import FormMessage from "metabase/components/form/FormMessage"; import Button from "metabase/core/components/Button"; +import { FormMessage } from "metabase/forms"; import { formatDateTimeWithUnit } from "metabase/lib/formatting"; import { formatChannelRecipients } from "metabase/lib/notifications"; import Settings from "metabase/lib/settings"; diff --git a/frontend/src/metabase/account/notifications/components/UnsubscribeModal/UnsubscribeModal.jsx b/frontend/src/metabase/account/notifications/components/UnsubscribeModal/UnsubscribeModal.jsx index ae184a55bbe..19febfdb1d4 100644 --- a/frontend/src/metabase/account/notifications/components/UnsubscribeModal/UnsubscribeModal.jsx +++ b/frontend/src/metabase/account/notifications/components/UnsubscribeModal/UnsubscribeModal.jsx @@ -3,8 +3,8 @@ import { useCallback, useState } from "react"; import { t } from "ttag"; import ModalContent from "metabase/components/ModalContent"; -import FormMessage from "metabase/components/form/FormMessage"; import Button from "metabase/core/components/Button"; +import { FormMessage } from "metabase/forms"; const propTypes = { item: PropTypes.object.isRequired, diff --git a/frontend/src/metabase/admin/databases/components/DatabaseList/DatabaseList.jsx b/frontend/src/metabase/admin/databases/components/DatabaseList/DatabaseList.jsx index de16ec2ff85..56d8df57c5f 100644 --- a/frontend/src/metabase/admin/databases/components/DatabaseList/DatabaseList.jsx +++ b/frontend/src/metabase/admin/databases/components/DatabaseList/DatabaseList.jsx @@ -7,11 +7,11 @@ import { t } from "ttag"; import LoadingSpinner from "metabase/components/LoadingSpinner"; import Modal from "metabase/components/Modal"; -import FormMessage from "metabase/components/form/FormMessage"; import AdminS from "metabase/css/admin.module.css"; import ButtonsS from "metabase/css/components/buttons.module.css"; import CS from "metabase/css/core/index.css"; import { DatabaseSyncModal } from "metabase/databases/components/DatabaseSyncModal"; +import { FormMessage } from "metabase/forms"; import { isSyncCompleted } from "metabase/lib/syncing"; import { PLUGIN_FEATURE_LEVEL_PERMISSIONS } from "metabase/plugins"; diff --git a/frontend/src/metabase/admin/settings/components/SettingsLdapForm.tsx b/frontend/src/metabase/admin/settings/components/SettingsLdapForm.tsx index 25e8553bc95..d5ee70d7bea 100644 --- a/frontend/src/metabase/admin/settings/components/SettingsLdapForm.tsx +++ b/frontend/src/metabase/admin/settings/components/SettingsLdapForm.tsx @@ -9,9 +9,9 @@ import GroupMappingsWidget from "metabase/admin/settings/containers/GroupMapping import { updateLdapSettings } from "metabase/admin/settings/settings"; import type { SettingElement } from "metabase/admin/settings/types"; import Breadcrumbs from "metabase/components/Breadcrumbs"; -import { FormSection } from "metabase/containers/FormikForm"; import CS from "metabase/css/core/index.css"; import { + FormSection, Form, FormErrorMessage, FormProvider, diff --git a/frontend/src/metabase/components/ArchiveModal/ArchiveModal.jsx b/frontend/src/metabase/components/ArchiveModal/ArchiveModal.jsx index dcb0eef9a5d..02f991bf8d7 100644 --- a/frontend/src/metabase/components/ArchiveModal/ArchiveModal.jsx +++ b/frontend/src/metabase/components/ArchiveModal/ArchiveModal.jsx @@ -3,8 +3,8 @@ import { Component } from "react"; import { t } from "ttag"; import ModalContent from "metabase/components/ModalContent"; -import FormMessage from "metabase/components/form/FormMessage"; import Button from "metabase/core/components/Button"; +import { FormMessage } from "metabase/forms"; class ArchiveModal extends Component { state = { diff --git a/frontend/src/metabase/components/form/FormMessage/index.ts b/frontend/src/metabase/components/form/FormMessage/index.ts deleted file mode 100644 index 686319e3576..00000000000 --- a/frontend/src/metabase/components/form/FormMessage/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FormMessage"; diff --git a/frontend/src/metabase/components/form/FormWidget.jsx b/frontend/src/metabase/components/form/FormWidget.jsx deleted file mode 100644 index d4222cbb2f5..00000000000 --- a/frontend/src/metabase/components/form/FormWidget.jsx +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-disable react/prop-types */ -import { forwardRef } from "react"; - -import { PLUGIN_FORM_WIDGETS } from "metabase/plugins"; - -import FormBooleanWidget from "./widgets/FormBooleanWidget"; -import FormCheckBoxWidget from "./widgets/FormCheckBoxWidget"; -import FormCollectionWidget from "./widgets/FormCollectionWidget"; -import FormColorWidget from "./widgets/FormColorWidget"; -import FormEmailWidget from "./widgets/FormEmailWidget"; -import FormHiddenWidget from "./widgets/FormHiddenWidget"; -import FormInfoWidget from "./widgets/FormInfoWidget"; -import FormInputWidget from "./widgets/FormInputWidget"; -import FormNumericInputWidget from "./widgets/FormNumericInputWidget"; -import FormPasswordWidget from "./widgets/FormPasswordWidget"; -import FormRadioWidget from "./widgets/FormRadioWidget"; -import FormSectionWidget from "./widgets/FormSectionWidget"; -import FormSelectWidget from "./widgets/FormSelectWidget"; -import FormSnippetCollectionWidget from "./widgets/FormSnippetCollectionWidget"; -import FormTextAreaWidget from "./widgets/FormTextAreaWidget"; -import FormTextFileWidget from "./widgets/FormTextFileWidget"; - -const WIDGETS = { - info: FormInfoWidget, - input: FormInputWidget, - email: FormEmailWidget, - text: FormTextAreaWidget, - checkbox: FormCheckBoxWidget, - color: FormColorWidget, - password: FormPasswordWidget, - radio: FormRadioWidget, - section: FormSectionWidget, - select: FormSelectWidget, - integer: FormNumericInputWidget, - boolean: FormBooleanWidget, - collection: FormCollectionWidget, - snippetCollection: FormSnippetCollectionWidget, - hidden: FormHiddenWidget, - textFile: FormTextFileWidget, -}; - -export function getWidgetComponent(formField) { - if (typeof formField.type === "string") { - const widget = - WIDGETS[formField.type] || PLUGIN_FORM_WIDGETS[formField.type]; - return widget || FormInputWidget; - } - return formField.type || FormInputWidget; -} - -/** - * @deprecated - */ -const FormWidget = forwardRef(function FormWidget( - { field, formField, ...props }, - ref, -) { - const Widget = getWidgetComponent(formField); - return <Widget field={field} {...formField} {...props} ref={ref} />; -}); - -export default FormWidget; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomForm.tsx b/frontend/src/metabase/components/form/FormikCustomForm/CustomForm.tsx deleted file mode 100644 index e2b97433af3..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomForm.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Form } from "formik"; -import type * as React from "react"; - -import type { - BaseFieldValues, - FormFieldDefinition, - PopulatedFormObject, -} from "metabase-types/forms"; - -import type { CustomFormFieldProps } from "./CustomFormField"; -import CustomFormField from "./CustomFormField"; -import type { CustomFormFooterProps } from "./CustomFormFooter"; -import CustomFormFooter from "./CustomFormFooter"; -import type { CustomFormMessageProps } from "./CustomFormMessage"; -import CustomFormMessage from "./CustomFormMessage"; -import CustomFormSubmit from "./CustomFormSubmit"; -import { FormContext } from "./context"; -import type { BaseFormProps, OptionalFormViewProps } from "./types"; - -interface FormRenderProps<Values extends BaseFieldValues> - extends BaseFormProps<Values> { - form: PopulatedFormObject<Values>; - formFields: FormFieldDefinition[]; - Form: React.ComponentType<{ children: React.ReactNode }>; - FormField: React.ComponentType<CustomFormFieldProps>; - FormSubmit: React.ComponentType<{ children: React.ReactNode }>; - FormMessage: React.ComponentType<CustomFormMessageProps>; - FormFooter: React.ComponentType<CustomFormFooterProps>; -} - -export interface CustomFormProps<Values extends BaseFieldValues> - extends BaseFormProps<Values>, - OptionalFormViewProps { - children?: - | React.ReactNode - | ((props: FormRenderProps<Values>) => JSX.Element); -} - -/** - * @deprecated - */ -function CustomForm<Values extends BaseFieldValues>( - props: CustomFormProps<Values>, -) { - const { formObject: form, values, children } = props; - if (typeof children === "function") { - return ( - <FormContext.Provider value={props}> - {children({ - ...props, - form, - formFields: form.fields(values), - Form, - FormField: CustomFormField, - FormSubmit: CustomFormSubmit, - FormMessage: CustomFormMessage, - FormFooter: CustomFormFooter, - })} - </FormContext.Provider> - ); - } - - return ( - <FormContext.Provider value={props}> - <Form {...props} /> - </FormContext.Provider> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomForm; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormField.tsx b/frontend/src/metabase/components/form/FormikCustomForm/CustomFormField.tsx deleted file mode 100644 index e45d515c557..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormField.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { forwardRef, useCallback, useMemo } from "react"; -import { useMount, useUnmount } from "react-use"; -import _ from "underscore"; - -import FormWidget from "metabase/components/form/FormWidget"; -import FormField from "metabase/components/form/FormikFormField"; -import type { - BaseFieldDefinition, - StandardFormFieldDefinition, - FormFieldDefinition, -} from "metabase-types/forms"; -import { isCustomWidget } from "metabase-types/guards"; - -import { useForm } from "./context"; - -export interface CustomFormFieldProps extends BaseFieldDefinition { - onChange?: (e: unknown) => void; -} - -function getFieldDefinition( - props: StandardFormFieldDefinition, -): FormFieldDefinition { - return _.pick( - props, - "name", - "type", - "title", - "description", - "initial", - "validate", - "normalize", - ); -} - -/** - * @deprecated - */ -function RawCustomFormField( - props: CustomFormFieldProps & { forwardedRef?: any }, -) { - const { name, onChange, forwardedRef } = props; - const { - fields, - formFieldsByName, - values, - onChangeField, - registerFormField, - unregisterFormField, - } = useForm(); - - const field = fields[name]; - const formField = formFieldsByName[name]; - - useMount(() => { - registerFormField?.( - getFieldDefinition(props as StandardFormFieldDefinition), - ); - }); - - useUnmount(() => { - unregisterFormField?.( - getFieldDefinition(props as StandardFormFieldDefinition), - ); - }); - - const handleChange = useCallback( - e => { - field.onChange(e); - onChange?.(e); - }, - [field, onChange], - ); - - const fieldProps = useMemo( - () => ({ - ...props, - values, - onChangeField, - formField, - field: - typeof onChange === "function" - ? { - ...field, - onChange: handleChange, - } - : field, - }), - [props, values, formField, field, onChange, onChangeField, handleChange], - ); - - if (!field || !formField) { - return null; - } - - const hasCustomWidget = isCustomWidget(formField); - const Widget = hasCustomWidget ? formField.widget : FormWidget; - - return ( - <FormField {...fieldProps}> - <Widget {...fieldProps} ref={forwardedRef} /> - </FormField> - ); -} - -/** - * @deprecated - */ -const CustomFormField = forwardRef<HTMLInputElement, CustomFormFieldProps>( - function CustomFormField(props, ref) { - return <RawCustomFormField {...props} forwardedRef={ref} />; - }, -); - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomFormField; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormFooter.tsx b/frontend/src/metabase/components/form/FormikCustomForm/CustomFormFooter.tsx deleted file mode 100644 index 122629f0016..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormFooter.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import cx from "classnames"; -import PropTypes from "prop-types"; -import type * as React from "react"; -import { t } from "ttag"; - -import Button from "metabase/core/components/Button"; -import CS from "metabase/css/core/index.css"; - -import CustomFormMessage from "./CustomFormMessage"; -import CustomFormSubmit from "./CustomFormSubmit"; - -export interface CustomFormFooterProps { - submitTitle?: string; - cancelTitle?: string; - fullWidth?: boolean; - isModal?: boolean; - isContextModal?: boolean; - footerExtraButtons?: React.ReactElement[]; - onCancel?: () => void; -} - -function CustomFormFooter({ - submitTitle = t`Submit`, - cancelTitle = t`Cancel`, - onCancel, - footerExtraButtons, - fullWidth, - isModal, - isContextModal, -}: CustomFormFooterProps) { - return ( - <div - className={cx(CS.flex, CS.alignCenter, { - [CS.flexReverse]: isModal || isContextModal, - })} - > - <CustomFormSubmit fullWidth={fullWidth}>{submitTitle}</CustomFormSubmit> - {onCancel && ( - <Button className={CS.mx1} type="button" onClick={onCancel}> - {cancelTitle} - </Button> - )} - <div className={CS.flexFull} /> - <CustomFormMessage className={CS.ml1} noPadding /> - {footerExtraButtons} - </div> - ); -} -interface LegacyContextProps { - isModal?: boolean; -} - -// Modal components uses legacy React context to pass `isModal` prop -/** - * @deprecated - */ -const CustomFormFooterLegacyContext = ( - props: CustomFormFooterProps, - { isModal }: LegacyContextProps, -) => <CustomFormFooter {...props} isContextModal={isModal} />; - -CustomFormFooterLegacyContext.contextTypes = { - isModal: PropTypes.bool, -}; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomFormFooterLegacyContext; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormMessage.tsx b/frontend/src/metabase/components/form/FormikCustomForm/CustomFormMessage.tsx deleted file mode 100644 index 519b03dd196..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormMessage.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import FormMessage from "metabase/components/form/FormMessage"; - -import { useForm } from "./context"; - -export interface CustomFormMessageProps { - className?: string; - noPadding?: boolean; -} - -/** - * @deprecated - */ -function CustomFormMessage(props: CustomFormMessageProps) { - const { error } = useForm(); - if (error) { - return <FormMessage {...props} message={error} />; - } - return null; -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomFormMessage; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSubmit.tsx b/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSubmit.tsx deleted file mode 100644 index dcfd0cd7022..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSubmit.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import type * as React from "react"; -import { t } from "ttag"; - -import ActionButton from "metabase/components/ActionButton"; - -import { useForm } from "./context"; - -export interface CustomFormSubmitProps { - children: React.ReactNode; - - // ActionButton props - fullWidth?: boolean; -} - -/** - * @deprecated - */ -function CustomFormSubmit(props: CustomFormSubmitProps) { - const { - submitting, - invalid, - pristine, - handleSubmit, - submitTitle, - renderSubmit, - disablePristineSubmit, - } = useForm(); - - const title = props.children || submitTitle || t`Submit`; - const canSubmit = !( - submitting || - invalid || - (pristine && disablePristineSubmit) - ); - - if (renderSubmit) { - return renderSubmit({ title, canSubmit, handleSubmit }); - } - - return ( - <ActionButton - normalText={title} - activeText={title} - failedText={t`Failed`} - successText={t`Success`} - primary={canSubmit} - disabled={!canSubmit} - {...props} - type="submit" - actionFn={handleSubmit} - /> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomFormSubmit; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/context.ts b/frontend/src/metabase/components/form/FormikCustomForm/context.ts deleted file mode 100644 index 905901383a4..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/context.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createContext, useContext } from "react"; -import _ from "underscore"; - -import type { FormLegacyContext } from "./types"; - -export const FormContext = createContext<FormLegacyContext<any>>({ - fields: {}, - formFields: [], - formFieldsByName: {}, - values: {}, - submitting: false, - invalid: false, - pristine: true, - error: undefined, - disablePristineSubmit: true, - handleSubmit: _.noop, - onChangeField: _.noop, - registerFormField: _.noop, - unregisterFormField: _.noop, -}); - -export function useForm() { - return useContext(FormContext); -} diff --git a/frontend/src/metabase/components/form/FormikCustomForm/index.ts b/frontend/src/metabase/components/form/FormikCustomForm/index.ts deleted file mode 100644 index 0c3f2cdd0e0..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { default as CustomFormField } from "./CustomFormField"; -export { default as CustomFormFooter } from "./CustomFormFooter"; -export { default as CustomFormMessage } from "./CustomFormMessage"; -export { default as CustomFormSection } from "./CustomFormSection"; -export { default as CustomFormSubmit } from "./CustomFormSubmit"; - -export * from "./CustomForm"; -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./CustomForm"; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/types.ts b/frontend/src/metabase/components/form/FormikCustomForm/types.ts deleted file mode 100644 index 4f5459c2d2a..00000000000 --- a/frontend/src/metabase/components/form/FormikCustomForm/types.ts +++ /dev/null @@ -1,104 +0,0 @@ -import PropTypes from "prop-types"; - -import type { - FieldName, - BaseFieldValues, - DefaultFieldValue, - FormFieldDefinition, - FormField, - PopulatedFormObject, -} from "metabase-types/forms"; - -export interface BaseFormProps<Values extends BaseFieldValues> { - formKey?: string; - formName?: string; - formObject: PopulatedFormObject<Values>; - - formFields: FormFieldDefinition[]; - formFieldsByName: Record<string, FormFieldDefinition>; - disablePristineSubmit?: boolean; - - registerFormField: (fieldDef: FormFieldDefinition) => void; - unregisterFormField: (fieldDef: FormFieldDefinition) => void; - - fields: Record<keyof Values, FormField<Values>>; - values: Values; - errors: Record<keyof Values, string>; - - active?: boolean; - asyncValidating?: boolean; - dirty: boolean; - error?: string | null; - invalid: boolean; - overwriteOnInitialValuesChange?: boolean; - pristine: boolean; - readonly?: boolean; - submitFailed: boolean; - submitting: boolean; - valid: boolean; - - asyncValidate: () => void; - destroyForm: () => void; - handleSubmit: () => void; - initializeForm: () => void; - onChangeField: (fieldName: FieldName, value: DefaultFieldValue) => void; - onSubmitSuccess: () => void; - resetForm: () => void; - - submitPassback?: () => void; - touch?: () => void; - touchAll?: () => void; - untouch?: () => void; - untouchAll?: () => void; -} - -type RenderSubmitProps = { - title: React.ReactNode; - canSubmit: boolean; - handleSubmit: () => void; -}; - -export interface OptionalFormViewProps { - submitTitle?: string; - renderSubmit?: (props: RenderSubmitProps) => JSX.Element; - className?: string; - style?: React.CSSProperties; -} - -export interface FormLegacyContext< - Values extends BaseFieldValues = BaseFieldValues, -> extends OptionalFormViewProps, - Pick< - BaseFormProps<Values>, - | "formFields" - | "formFieldsByName" - | "registerFormField" - | "unregisterFormField" - | "disablePristineSubmit" - | "handleSubmit" - | "fields" - | "values" - | "submitting" - | "invalid" - | "pristine" - | "error" - | "onChangeField" - > {} - -export const LegacyContextTypes = { - handleSubmit: PropTypes.func, - submitTitle: PropTypes.string, - renderSubmit: PropTypes.func, - className: PropTypes.string, - style: PropTypes.object, - fields: PropTypes.object, - formFields: PropTypes.array, - formFieldsByName: PropTypes.object, - values: PropTypes.object, - submitting: PropTypes.bool, - invalid: PropTypes.bool, - pristine: PropTypes.bool, - error: PropTypes.string, - onChangeField: PropTypes.func, - disablePristineSubmit: PropTypes.bool, -}; diff --git a/frontend/src/metabase/components/form/FormikFormField/FormField.styled.tsx b/frontend/src/metabase/components/form/FormikFormField/FormField.styled.tsx deleted file mode 100644 index 87cf26d3c05..00000000000 --- a/frontend/src/metabase/components/form/FormikFormField/FormField.styled.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { css } from "@emotion/react"; -import styled from "@emotion/styled"; - -import FormS from "metabase/css/components/form.module.css"; -import { color } from "metabase/lib/colors"; -import { Icon } from "metabase/ui"; - -export const FieldRow = styled.div` - display: flex; - align-items: center; - margin-bottom: 0.5em; -`; - -export const Label = styled.label<{ - horizontal?: boolean; - standAlone?: boolean; -}>` - margin-bottom: 0; - ${props => - props.horizontal && - css` - margin-right: auto; - `} - ${props => - props.standAlone && - css` - margin-top: 0.8em; - `} -`; - -Label.defaultProps = { className: FormS.FormLabel }; - -export const InfoIcon = styled(Icon)` - margin-left: 8px; - color: ${color("bg-dark")}; - - &:hover { - color: ${color("brand")}; - } -`; - -export const InfoLabel = styled.span` - color: ${color("text-medium")}; - font-size: 0.88em; - margin-left: auto; - cursor: default; -`; - -export const FieldContainer = styled.div<{ - horizontal?: boolean; - align?: "left" | "right"; -}>` - width: 100%; - margin-right: ${props => (props.horizontal ? "1rem" : "")}; - margin-left: ${props => (props.align === "left" ? "0.5rem" : "")}; -`; - -export const InputContainer = styled.div` - flex-shrink: 0; -`; diff --git a/frontend/src/metabase/components/form/FormikFormField/FormField.tsx b/frontend/src/metabase/components/form/FormikFormField/FormField.tsx deleted file mode 100644 index 15a4083d8a9..00000000000 --- a/frontend/src/metabase/components/form/FormikFormField/FormField.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import type * as React from "react"; - -import type { - FieldName, - FieldValues, - FormField as FormFieldType, - BaseFieldDefinition, - FormFieldDefinition, -} from "metabase-types/forms"; - -import FormFieldView from "./FormFieldView"; - -type ReduxFormProps<Values> = Pick<FormFieldType<Values>, "name"> & - Partial<Pick<FormFieldType<Values>, "error" | "visited" | "active">>; - -interface FormFieldProps<Values> - extends BaseFieldDefinition, - Omit<ReduxFormProps<Values>, "name"> { - field: FormFieldType<Values>; - formField: FormFieldDefinition; - values: FieldValues; - className?: string; - children: React.ReactNode; - onChangeField: (fieldName: FieldName, value: unknown) => void; -} - -const ALL_DOT_CHARS = /\./g; - -function getFieldId(formFieldName: FieldName) { - return `formField-${formFieldName.replace(ALL_DOT_CHARS, "-")}`; -} - -function getDescriptionPositionPropValue( - descriptionPosition?: "top" | "bottom", - formField?: FormFieldDefinition, -) { - return descriptionPosition ?? formField?.descriptionPosition ?? "top"; -} - -function getHiddenPropValue(hidden?: boolean, formField?: FormFieldDefinition) { - if (typeof hidden === "boolean") { - return hidden; - } - if (formField) { - return formField.hidden || formField.type === "hidden"; - } - return false; -} - -function getHorizontalPropValue( - horizontal?: boolean, - formField?: FormFieldDefinition, -) { - if (typeof horizontal === "boolean") { - return horizontal; - } - if (formField) { - return formField.horizontal || formField.type === "boolean"; - } - return false; -} - -/** - * @deprecated - */ -function FormField<Values>({ - className, - formField, - children, - ...props -}: FormFieldProps<Values>) { - const title = props.title ?? formField?.title; - const type = props.type ?? formField.type; - const description = props.description ?? formField?.description; - const descriptionPosition = getDescriptionPositionPropValue( - props.descriptionPosition, - formField, - ); - - const info = props.info ?? formField?.info; - const infoLabel = props.infoLabel ?? formField?.infoLabel; - const infoLabelTooltip = - props.infoLabelTooltip ?? formField?.infoLabelTooltip; - - const align = props.align ?? formField?.align ?? "right"; - const hidden = getHiddenPropValue(props.hidden, formField); - const horizontal = getHorizontalPropValue(props.horizontal, formField); - - const isToggle = type === "boolean"; - const standAloneLabel = isToggle && align === "right" && !description; - - if (hidden) { - return null; - } - - const { - name, - error: errorProp, - visited, - active, - } = { - ...(props.field || {}), - ...props, - }; - - const shouldShowError = visited && !active; - const error = !shouldShowError ? undefined : errorProp; - - return ( - <FormFieldView - fieldId={getFieldId(name)} - className={className} - name={name} - error={error} - title={title} - description={description} - descriptionPosition={descriptionPosition} - info={info} - infoLabel={infoLabel} - infoLabelTooltip={infoLabelTooltip} - align={align} - standAloneLabel={standAloneLabel} - horizontal={horizontal} - > - {children} - </FormFieldView> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormField; diff --git a/frontend/src/metabase/components/form/FormikFormField/FormFieldDescription.tsx b/frontend/src/metabase/components/form/FormikFormField/FormFieldDescription.tsx deleted file mode 100644 index 5dfd1be41f9..00000000000 --- a/frontend/src/metabase/components/form/FormikFormField/FormFieldDescription.tsx +++ /dev/null @@ -1,21 +0,0 @@ -interface FormFieldDescriptionProps { - className: string; - description: string; -} - -export const FormFieldDescription = ({ - className, - description, -}: FormFieldDescriptionProps) => { - if (typeof description === "string") { - return ( - <div - className={className} - dangerouslySetInnerHTML={{ - __html: description, - }} - /> - ); - } - return <div className={className}>{description}</div>; -}; diff --git a/frontend/src/metabase/components/form/FormikFormField/FormFieldView.tsx b/frontend/src/metabase/components/form/FormikFormField/FormFieldView.tsx deleted file mode 100644 index 65552fd72e5..00000000000 --- a/frontend/src/metabase/components/form/FormikFormField/FormFieldView.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import cx from "classnames"; -import type * as React from "react"; - -import PopoverS from "metabase/components/Popover/Popover.module.css"; -import Tooltip from "metabase/core/components/Tooltip"; -import FormS from "metabase/css/components/form.module.css"; -import CS from "metabase/css/core/index.css"; -import type { BaseFieldDefinition } from "metabase-types/forms"; - -import { - FieldRow, - Label, - InfoIcon, - InputContainer, - FieldContainer, - InfoLabel, -} from "./FormField.styled"; -import { FormFieldDescription } from "./FormFieldDescription"; - -interface FormFieldViewProps extends BaseFieldDefinition { - fieldId: string; - error?: string; - className?: string; - standAloneLabel?: boolean; - children: React.ReactNode; -} - -function FormFieldView({ - fieldId, - className, - name, - error, - title, - description, - descriptionPosition, - info, - infoLabel, - infoLabelTooltip, - align, - horizontal, - standAloneLabel, - children, -}: FormFieldViewProps) { - return ( - <div - id={fieldId} - data-testid="form-field" - className={cx(FormS.FormField, PopoverS.FormField, className, { - [FormS.FormFieldError]: !!error, - [CS.flex]: horizontal, - })} - > - {align === "left" && <InputContainer>{children}</InputContainer>} - {(title || description) && ( - <FieldContainer horizontal={horizontal} align={align}> - <FieldRow> - {title && ( - <Label - id={`${name}-label`} - htmlFor={name} - horizontal={horizontal} - standAlone={standAloneLabel} - > - {title} - {error && <span className={CS.textError}>: {error}</span>} - </Label> - )} - {info && ( - <Tooltip tooltip={info}> - <InfoIcon name="info" size={12} /> - </Tooltip> - )} - {infoLabel && ( - <Tooltip tooltip={infoLabelTooltip} maxWidth="100%"> - <InfoLabel>{infoLabel}</InfoLabel> - </Tooltip> - )} - </FieldRow> - {description && descriptionPosition === "top" && ( - <FormFieldDescription - className={CS.mb1} - description={description} - /> - )} - </FieldContainer> - )} - {align !== "left" && <InputContainer>{children}</InputContainer>} - {description && descriptionPosition === "bottom" && ( - <FormFieldDescription className={CS.mt1} description={description} /> - )} - </div> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormFieldView; diff --git a/frontend/src/metabase/components/form/FormikFormField/index.ts b/frontend/src/metabase/components/form/FormikFormField/index.ts deleted file mode 100644 index 8824a3b7a61..00000000000 --- a/frontend/src/metabase/components/form/FormikFormField/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FormField"; diff --git a/frontend/src/metabase/components/form/FormikStandardForm.tsx b/frontend/src/metabase/components/form/FormikStandardForm.tsx deleted file mode 100644 index 4faadbdfd41..00000000000 --- a/frontend/src/metabase/components/form/FormikStandardForm.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { t } from "ttag"; - -import type { BaseFieldValues } from "metabase-types/forms"; - -import CustomForm from "./FormikCustomForm"; -import type { CustomFormFooterProps } from "./FormikCustomForm/CustomFormFooter"; -import type { BaseFormProps } from "./FormikCustomForm/types"; - -interface Props<Values extends BaseFieldValues> - extends BaseFormProps<Values>, - CustomFormFooterProps { - submitFullWidth?: boolean; - onClose?: () => void; -} - -/** - * @deprecated - */ -function StandardForm<Values extends BaseFieldValues>({ - submitTitle, - submitFullWidth, - onClose, - ...props -}: Props<Values>) { - return ( - <CustomForm {...props}> - {({ values, formFields, Form, FormField, FormFooter }) => ( - <Form> - {formFields.map(formField => ( - <FormField key={formField.name} name={formField.name} /> - ))} - <FormFooter - isModal={props.isModal} - footerExtraButtons={props.footerExtraButtons} - onCancel={onClose} - submitTitle={ - submitTitle || (values.id != null ? t`Update` : t`Create`) - } - fullWidth={submitFullWidth} - /> - </Form> - )} - </CustomForm> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default StandardForm; diff --git a/frontend/src/metabase/components/form/widgets/FormBooleanWidget.jsx b/frontend/src/metabase/components/form/widgets/FormBooleanWidget.jsx deleted file mode 100644 index ce48dd17f4e..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormBooleanWidget.jsx +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable react/prop-types */ -import Toggle from "metabase/core/components/Toggle"; - -const FormBooleanWidget = ({ field }) => ( - <Toggle - aria-labelledby={`${field.name}-label`} - aria-checked={field.value} - role="switch" - {...field} - /> -); - -export default FormBooleanWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormCheckBoxWidget.jsx b/frontend/src/metabase/components/form/widgets/FormCheckBoxWidget.jsx deleted file mode 100644 index 812b55b01d0..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormCheckBoxWidget.jsx +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable react/prop-types */ -import CheckBox from "metabase/core/components/CheckBox"; -import { formDomOnlyProps } from "metabase/lib/redux"; - -const FormCheckBoxWidget = ({ field }) => ( - <CheckBox - {...formDomOnlyProps(field)} - checked={field.value} - onChange={e => field.onChange(e.target.checked)} - /> -); - -export default FormCheckBoxWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormCollectionWidget.jsx b/frontend/src/metabase/components/form/widgets/FormCollectionWidget.jsx deleted file mode 100644 index 3eec719cf72..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormCollectionWidget.jsx +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable react/prop-types */ -import CollectionSelect from "metabase/containers/CollectionSelect"; - -const FormCollectionWidget = ({ field }) => <CollectionSelect {...field} />; - -export default FormCollectionWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormColorWidget.jsx b/frontend/src/metabase/components/form/widgets/FormColorWidget.jsx deleted file mode 100644 index e8131c4ecec..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormColorWidget.jsx +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable react/prop-types */ -import ColorSelector from "metabase/core/components/ColorSelector"; -import { getAccentColors } from "metabase/lib/colors/groups"; - -const FormColorWidget = ({ field, initial }) => ( - <div> - <ColorSelector - {...field} - value={field.value || initial()} - colors={getAccentColors()} - /> - </div> -); - -export default FormColorWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormEmailWidget.jsx b/frontend/src/metabase/components/form/widgets/FormEmailWidget.jsx deleted file mode 100644 index 114cdea075e..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormEmailWidget.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import FormInputWidget from "./FormInputWidget"; - -const FormEmailWidget = props => <FormInputWidget {...props} type="email" />; - -export default FormEmailWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormHiddenWidget.jsx b/frontend/src/metabase/components/form/widgets/FormHiddenWidget.jsx deleted file mode 100644 index f1b895988ec..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormHiddenWidget.jsx +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable react/prop-types */ -import { formDomOnlyProps } from "metabase/lib/redux"; - -const FormHiddenWidget = ({ type = "hidden", field }) => ( - <input type={type} {...formDomOnlyProps(field)} /> -); - -export default FormHiddenWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormInfoWidget.jsx b/frontend/src/metabase/components/form/widgets/FormInfoWidget.jsx deleted file mode 100644 index 3391c4026fc..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormInfoWidget.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import PropTypes from "prop-types"; - -import Banner from "metabase/components/Banner"; - -const propTypes = { - placeholder: PropTypes.string, -}; - -const FormInfoWidget = ({ placeholder }) => <Banner>{placeholder}</Banner>; - -FormInfoWidget.propTypes = propTypes; - -export default FormInfoWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormInputWidget.jsx b/frontend/src/metabase/components/form/widgets/FormInputWidget.jsx deleted file mode 100644 index b0a7971df87..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormInputWidget.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import PropTypes from "prop-types"; -import { forwardRef } from "react"; - -import Input from "metabase/core/components/Input"; -import { formDomOnlyProps } from "metabase/lib/redux"; - -// Important: do NOT use this as an input of type="file" -// For file inputs, See component FormTextFileWidget.tsx - -const propTypes = { - type: PropTypes.string, - placeholder: PropTypes.string, - field: PropTypes.object, - readOnly: PropTypes.bool, - autoFocus: PropTypes.bool, - helperText: PropTypes.node, - tabIndex: PropTypes.string, - subtitle: PropTypes.string, -}; - -const FormInputWidget = forwardRef(function FormInputWidget( - { - type = "text", - placeholder, - field, - readOnly, - autoFocus, - helperText, - tabIndex, - subtitle, - }, - ref, -) { - return ( - <Input - {...formDomOnlyProps(field)} - type={type} - placeholder={placeholder} - aria-labelledby={`${field.name}-label`} - readOnly={readOnly} - autoFocus={autoFocus} - error={field.visited && !field.active && field.error != null} - rightIcon={helperText && "info"} - rightIconTooltip={helperText} - tabIndex={tabIndex} - fullWidth - subtitle={subtitle} - ref={ref} - /> - ); -}); - -FormInputWidget.propTypes = propTypes; - -export default FormInputWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormNumericInputWidget.jsx b/frontend/src/metabase/components/form/widgets/FormNumericInputWidget.jsx deleted file mode 100644 index f3254790c12..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormNumericInputWidget.jsx +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable react/prop-types */ -import cx from "classnames"; - -import NumericInput from "metabase/components/NumericInput"; -import FormS from "metabase/css/components/form.module.css"; -import CS from "metabase/css/core/index.css"; -import { formDomOnlyProps } from "metabase/lib/redux"; - -const FormInputWidget = ({ placeholder, field }) => ( - <NumericInput - className={cx(FormS.FormInput, CS.full)} - placeholder={placeholder} - aria-labelledby={`${field.name}-label`} - {...formDomOnlyProps(field)} - /> -); - -export default FormInputWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormPasswordWidget.jsx b/frontend/src/metabase/components/form/widgets/FormPasswordWidget.jsx deleted file mode 100644 index 9dadba5d1c6..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormPasswordWidget.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import FormInputWidget from "./FormInputWidget"; - -const FormPasswordWidget = props => ( - <FormInputWidget {...props} type="password" /> -); - -export default FormPasswordWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormRadioWidget.jsx b/frontend/src/metabase/components/form/widgets/FormRadioWidget.jsx deleted file mode 100644 index 6ff90a3e581..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormRadioWidget.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import styled from "@emotion/styled"; -import PropTypes from "prop-types"; - -import Radio from "metabase/core/components/Radio"; - -const StyledRadio = styled(Radio)` - font-weight: bold; -`; - -const propTypes = { - field: PropTypes.object.isRequired, - options: PropTypes.array.isRequired, -}; - -function FormRadioWidget({ field, options }) { - return <StyledRadio showButtons vertical {...field} options={options} />; -} - -FormRadioWidget.propTypes = propTypes; - -export default FormRadioWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.styled.tsx b/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.styled.tsx deleted file mode 100644 index cf24575e261..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.styled.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import styled from "@emotion/styled"; - -import Button from "metabase/core/components/Button"; -import { color } from "metabase/lib/colors"; - -export const WidgetButton = styled(Button)` - color: ${color("brand")}; - padding: 0; - border: none; - border-radius: 0; - - &:hover { - background-color: transparent; - } -`; diff --git a/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.tsx b/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.tsx deleted file mode 100644 index 9b42a4dab44..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSectionWidget/FormSectionWidget.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useCallback } from "react"; -import { t } from "ttag"; - -import { WidgetButton } from "./FormSectionWidget.styled"; -import type { FormField } from "./types"; - -export interface FormSectionWidgetProps { - field: FormField; -} - -const FormSectionWidget = ({ field }: FormSectionWidgetProps): JSX.Element => { - const { value, onChange } = field; - - const handleClick = useCallback(() => { - onChange(!value); - }, [value, onChange]); - - return ( - <WidgetButton - type="button" - iconRight={value ? "chevronup" : "chevrondown"} - onClick={handleClick} - > - {value ? t`Hide advanced options` : t`Show advanced options`} - </WidgetButton> - ); -}; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormSectionWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormSectionWidget/index.ts b/frontend/src/metabase/components/form/widgets/FormSectionWidget/index.ts deleted file mode 100644 index 529dddb720f..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSectionWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FormSectionWidget"; diff --git a/frontend/src/metabase/components/form/widgets/FormSectionWidget/types.ts b/frontend/src/metabase/components/form/widgets/FormSectionWidget/types.ts deleted file mode 100644 index b1cce813a00..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSectionWidget/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface FormField { - value: boolean; - onChange: (value: boolean) => void; -} diff --git a/frontend/src/metabase/components/form/widgets/FormSelectWidget.jsx b/frontend/src/metabase/components/form/widgets/FormSelectWidget.jsx deleted file mode 100644 index 57547f29a84..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSelectWidget.jsx +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable react/prop-types */ -import Select, { Option } from "metabase/core/components/Select"; - -const FormSelectWidget = ({ placeholder, options = [], field, disabled }) => ( - <Select - placeholder={placeholder} - {...field} - // react-redux expects to be raw value - onChange={e => field.onChange(e.target.value)} - disabled={disabled} - buttonProps={{ style: { minWidth: 200 } }} - > - {options.map(({ name, value, icon }) => ( - <Option key={value} value={value} icon={icon}> - {name} - </Option> - ))} - </Select> -); - -export default FormSelectWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormSnippetCollectionWidget.jsx b/frontend/src/metabase/components/form/widgets/FormSnippetCollectionWidget.jsx deleted file mode 100644 index 97041e901f7..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormSnippetCollectionWidget.jsx +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable react/prop-types */ -import CollectionPicker from "metabase/containers/CollectionPicker"; -import ItemSelect from "metabase/containers/ItemSelect"; -import { ROOT_COLLECTION } from "metabase/entities/collections"; -import SnippetCollections from "metabase/entities/snippet-collections"; - -const CollectionSelect = ItemSelect( - CollectionPicker, - SnippetCollections.Name, - "collection", -); - -const FormSnippetCollectionWidget = ({ field }) => ( - <CollectionSelect - entity={SnippetCollections} - showSearch={false} // seems that search endpoint doesn't support namespace yet - {...field} - value={field.value || ROOT_COLLECTION.id} // needed so SnippetCollections.Name finds the right collection - /> -); -export default FormSnippetCollectionWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.jsx b/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.jsx deleted file mode 100644 index 00541d9491a..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.jsx +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable react/prop-types */ -import cx from "classnames"; - -import FormS from "metabase/css/components/form.module.css"; -import CS from "metabase/css/core/index.css"; -import { formDomOnlyProps } from "metabase/lib/redux"; - -import { HelpText } from "./FormTextAreaWidget.styled"; - -const FormTextAreaWidget = ({ - placeholder, - field, - className, - rows, - autoFocus, - helperText, - tabIndex, -}) => ( - <> - <textarea - autoFocus={autoFocus} - className={cx(className, FormS.FormInput, CS.full)} - rows={rows} - placeholder={placeholder} - aria-labelledby={`${field.name}-label`} - tabIndex={tabIndex} - {...formDomOnlyProps(field)} - value={field.value || ""} - /> - {helperText && ( - <HelpText - dangerouslySetInnerHTML={{ - __html: helperText, - }} - /> - )} - </> -); - -export default FormTextAreaWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.styled.tsx b/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.styled.tsx deleted file mode 100644 index b77ae17d63a..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/FormTextAreaWidget.styled.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import styled from "@emotion/styled"; - -export const HelpText = styled.span` - font-size: 12px; - margin-top: 0.5rem; -`; diff --git a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/index.js b/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/index.js deleted file mode 100644 index c3edefc178b..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextAreaWidget/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FormTextAreaWidget"; diff --git a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/FormTextFileWidget.tsx b/frontend/src/metabase/components/form/widgets/FormTextFileWidget/FormTextFileWidget.tsx deleted file mode 100644 index cb6cb68ca9e..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/FormTextFileWidget.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import type { ChangeEvent, FocusEvent } from "react"; - -import FileInput from "metabase/core/components/FileInput"; - -import type { FormField, TreatBeforePosting } from "./types"; - -export interface FormTextFileWidgetProps { - field: FormField; - treatBeforePosting?: TreatBeforePosting; -} - -const FormTextFileWidget = ({ - field, - treatBeforePosting, -}: FormTextFileWidgetProps): JSX.Element => { - const { name, autoFocus, onChange, onBlur } = field; - - const handleChange = async (event: ChangeEvent<HTMLInputElement>) => { - onChange(await getFieldValue(event.target, treatBeforePosting)); - }; - - const handleBlur = async (event: FocusEvent<HTMLInputElement>) => { - onBlur(await getFieldValue(event.target, treatBeforePosting)); - }; - - return ( - <FileInput - name={name} - autoFocus={autoFocus} - aria-labelledby={`${field.name}-label`} - onChange={handleChange} - onBlur={handleBlur} - /> - ); -}; - -const getFieldValue = ( - { files }: HTMLInputElement, - treatBeforePosting?: TreatBeforePosting, -): Promise<string> => { - return new Promise((resolve, reject) => { - if (!files?.length) { - resolve(""); - return; - } - - const reader = new FileReader(); - reader.onload = () => resolve(String(reader.result)); - reader.onerror = () => reject(); - - if (treatBeforePosting === "base64") { - reader.readAsDataURL(files[0]); - } else { - reader.readAsText(files[0]); - } - }); -}; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormTextFileWidget; diff --git a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/index.ts b/frontend/src/metabase/components/form/widgets/FormTextFileWidget/index.ts deleted file mode 100644 index 5a2d7e0f824..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FormTextFileWidget"; diff --git a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/types.ts b/frontend/src/metabase/components/form/widgets/FormTextFileWidget/types.ts deleted file mode 100644 index 8cc0e594328..00000000000 --- a/frontend/src/metabase/components/form/widgets/FormTextFileWidget/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface FormField { - name: string; - value?: string; - autoFocus?: boolean; - onChange: (value: string) => void; - onBlur: (value: string) => void; -} - -export type TreatBeforePosting = "base64"; diff --git a/frontend/src/metabase/containers/FormikForm/FormView.tsx b/frontend/src/metabase/containers/FormikForm/FormView.tsx deleted file mode 100644 index 7123b434dbb..00000000000 --- a/frontend/src/metabase/containers/FormikForm/FormView.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type * as React from "react"; - -import type { CustomFormProps } from "metabase/components/form/FormikCustomForm"; -import CustomForm from "metabase/components/form/FormikCustomForm"; -import StandardForm from "metabase/components/form/FormikStandardForm"; -import type { BaseFieldValues } from "metabase-types/forms"; - -function FormView<Values extends BaseFieldValues>( - props: CustomFormProps<Values> & { - formComponent?: React.ComponentType<CustomFormProps<Values>>; - }, -) { - const FormComponent = - props.formComponent || (props.children ? CustomForm : StandardForm); - - return <FormComponent {...props} />; -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormView; diff --git a/frontend/src/metabase/containers/FormikForm/FormikForm.tsx b/frontend/src/metabase/containers/FormikForm/FormikForm.tsx deleted file mode 100644 index e933cb99e22..00000000000 --- a/frontend/src/metabase/containers/FormikForm/FormikForm.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import type { FormikErrors, FormikHelpers } from "formik"; -import { Formik } from "formik"; -import { assocIn, getIn, merge } from "icepick"; -import type { ReactNode } from "react"; -import { useCallback, useMemo, useState } from "react"; -import { t } from "ttag"; -import _ from "underscore"; - -import type { OptionalFormViewProps } from "metabase/components/form/FormikCustomForm/types"; -import type { GenericErrorResponse } from "metabase/lib/errors"; -import { getResponseErrorMessage } from "metabase/lib/errors"; -import type { - BaseFieldValues, - FormFieldDefinition, - FormObject, - FieldValues, - PopulatedFormObject, -} from "metabase-types/forms"; - -import { makeFormObject, cleanObject, isNestedFieldName } from "../formUtils"; - -import FormikFormViewAdapter from "./FormikFormViewAdapter"; -import useInlineFields from "./useInlineFields"; - -export interface FormContainerProps<Values extends BaseFieldValues> - extends OptionalFormViewProps { - form?: FormObject<Values>; - - fields?: FormFieldDefinition[]; - initialValues?: Partial<Values>; - - overwriteOnInitialValuesChange?: boolean; - - validate?: () => void; - asyncValidate?: (values: FieldValues) => Promise<FieldValues | string>; - initial?: () => void; - normalize?: () => void; - - onValuesChange?: (newValues: Record<string, any>) => void; - onSubmit: ( - values: Values, - formikHelpers?: FormikHelpers<Values>, - ) => void | Promise<void>; - onSubmitSuccess?: (action: unknown) => void; - - // various props - isModal?: boolean; - submitTitle?: string; - onClose?: () => void; - footerExtraButtons?: any; - disablePristineSubmit?: boolean; - children?: ReactNode | ((opts: any) => any); -} - -function maybeBlurActiveElement() { - // HACK: blur the current element to ensure we show the error - if (document.activeElement && "blur" in document.activeElement) { - (document.activeElement as HTMLInputElement).blur(); - } -} - -/** - * @deprecated - */ -function Form<Values extends BaseFieldValues>({ - form, - fields, - initialValues: initialValuesProp = {}, - overwriteOnInitialValuesChange = false, - asyncValidate, - validate, - initial, - normalize, - onValuesChange, - onSubmit, - onSubmitSuccess, - ...props -}: FormContainerProps<Values>) { - const [error, setError] = useState<string | null>(null); - const [values, setValues] = useState({}); - - const handleValuesChange = (newValues: any) => { - onValuesChange?.(newValues); - setValues(newValues); - }; - - const { inlineFields, registerFormField, unregisterFormField } = - useInlineFields(); - - const formDefinition = useMemo(() => { - const formDef = form || { - fields: fields || Object.values(inlineFields), - validate, - initial, - normalize, - }; - return { - ...formDef, - fields: (values: Values) => { - const fieldList = - typeof formDef.fields === "function" - ? formDef.fields(values) - : formDef.fields; - return fieldList.map(fieldDef => ({ - ...fieldDef, - ...inlineFields[fieldDef.name], - })); - }, - }; - }, [form, fields, inlineFields, validate, initial, normalize]); - - const formObject: PopulatedFormObject<Values> = useMemo( - () => makeFormObject(formDefinition), - [formDefinition], - ); - - const initialValues = useMemo(() => { - const fieldNames = formObject.fieldNames(values); - const [nestedFieldNames, regularFieldNames] = _.partition( - fieldNames, - isNestedFieldName, - ); - - let filteredInitialValues: FieldValues = {}; - - Object.keys(initialValuesProp || {}).forEach(fieldName => { - if (regularFieldNames.includes(fieldName)) { - filteredInitialValues[fieldName] = initialValuesProp[fieldName]; - } - }); - - nestedFieldNames.forEach(nestedFieldName => { - const fieldValuePath = (nestedFieldName as string).split("."); - filteredInitialValues = assocIn( - filteredInitialValues, - fieldValuePath, - getIn(initialValuesProp, fieldValuePath), - ); - }); - - return merge(formObject.initial(values), filteredInitialValues); - }, [values, initialValuesProp, formObject]); - - const fieldNames = useMemo( - () => formObject.fieldNames({ ...initialValues, ...values }), - [formObject, values, initialValues], - ); - - const handleValidation = useCallback( - async (values: Values) => { - const result = formObject.validate(values, { values }); - - // Ensure errors don't have empty strings - // as they will also be treated as errors - let errors = cleanObject(result); - - if (asyncValidate) { - const asyncErrors = await asyncValidate(values); - if (typeof asyncErrors === "object") { - errors = merge(cleanObject(asyncErrors), errors); - } else if (typeof asyncErrors === "string") { - setError(asyncErrors); - } - } - - return errors; - }, - [asyncValidate, formObject], - ); - - const handleError = useCallback( - (error: GenericErrorResponse, formikHelpers: FormikHelpers<Values>) => { - maybeBlurActiveElement(); - const DEFAULT_ERROR_MESSAGE = t`An error occurred`; - - if (typeof error?.data === "object" && error?.data?.errors) { - const errorNames = Object.keys(error.data.errors); - const hasUnknownFields = errorNames.some( - name => !fieldNames.includes(name), - ); - - if (hasUnknownFields) { - const generalMessage = getResponseErrorMessage(error); - setError(generalMessage ?? DEFAULT_ERROR_MESSAGE); - } - - formikHelpers.setErrors(error.data.errors as FormikErrors<Values>); - return error.data.errors; - } - - if (error) { - const message = getResponseErrorMessage(error); - setError(message ?? DEFAULT_ERROR_MESSAGE); - return message; - } - - return DEFAULT_ERROR_MESSAGE; - }, - [fieldNames], - ); - - const handleSubmit = useCallback( - async (values: Values, formikHelpers: FormikHelpers<Values>) => { - try { - const normalized = formObject.normalize(values); - const result = await onSubmit(normalized, formikHelpers); - onSubmitSuccess?.(result); - setError(null); // clear any previous errors - return result; - } catch (e) { - const error = handleError(e as GenericErrorResponse, formikHelpers); - // Need to throw, so e.g. submit button can react to an error - throw error; - } - }, - [formObject, onSubmit, onSubmitSuccess, handleError], - ); - - return ( - <Formik<Values> - validateOnBlur - validateOnMount - initialValues={initialValues} - enableReinitialize={overwriteOnInitialValuesChange} - validate={handleValidation} - onSubmit={handleSubmit} - > - {formikProps => ( - <FormikFormViewAdapter<Values> - {...formikProps} - {...props} - formObject={formObject} - error={error} - registerFormField={registerFormField} - unregisterFormField={unregisterFormField} - onValuesChange={handleValuesChange} - /> - )} - </Formik> - ); -} - -export { - CustomFormField as FormField, - CustomFormSubmit as FormSubmit, - CustomFormMessage as FormMessage, - CustomFormFooter as FormFooter, - CustomFormSection as FormSection, -} from "metabase/components/form/FormikCustomForm"; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default Form; diff --git a/frontend/src/metabase/containers/FormikForm/FormikFormViewAdapter.tsx b/frontend/src/metabase/containers/FormikForm/FormikFormViewAdapter.tsx deleted file mode 100644 index f9b8641c77d..00000000000 --- a/frontend/src/metabase/containers/FormikForm/FormikFormViewAdapter.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import type { FormikProps } from "formik"; -import type * as React from "react"; -import { useEffect, useState } from "react"; -import { usePrevious } from "react-use"; -import _ from "underscore"; - -import type { CustomFormProps } from "metabase/components/form/FormikCustomForm"; -import type { BaseFieldValues, FormField } from "metabase-types/forms"; - -import { getMaybeNestedValue } from "../formUtils"; - -import FormView from "./FormView"; - -type FormProps<Values extends BaseFieldValues> = Omit< - CustomFormProps<Values>, - | "fields" - | "errors" - | "formFields" - | "formFieldsByName" - | "invalid" - | "valid" - | "pristine" - | "submitting" - | "asyncValidate" - | "asyncValidating" - | "initializeForm" - | "destroyForm" - | "onSubmitSuccess" - | "resetForm" - | "handleSubmit" - | "onChangeField" - | "submitFailed" ->; - -interface FormikFormViewAdapterOwnProps<Values> { - onValuesChange: (values: Values) => void; -} - -type FormikFormViewAdapterProps<Values> = FormikProps<Values> & - FormProps<Values> & - FormikFormViewAdapterOwnProps<Values>; - -function FormikFormViewAdapter<Values extends BaseFieldValues>({ - formObject, - onValuesChange, - - errors, - dirty, - isValid, - values, - touched, - isValidating, - isSubmitting, - validateForm, - handleSubmit, - setFieldValue, - setFieldTouched, - resetForm, - initialValues, - submitForm, - disablePristineSubmit = formObject.disablePristineSubmit, - ...rest -}: FormikFormViewAdapterProps<Values>) { - const [active, setActive] = useState<string | null>(null); - const previousValues = usePrevious(values); - - useEffect(() => { - if (!_.isEqual(previousValues, values)) { - onValuesChange(values); - } - }, [previousValues, values, onValuesChange]); - - const fields = formObject.fields(values); - const formFieldsByName = _.indexBy(fields, "name"); - - const smartFields = fields.map(field => { - const { name } = field; - - const value = getMaybeNestedValue(values, name); - const initialValue = getMaybeNestedValue(initialValues, name); - const error = getMaybeNestedValue(errors as Record<string, string>, name); - const isTouched = !!getMaybeNestedValue( - touched as Record<string, boolean>, - name, - ); - - return { - ...field, - dirty: value !== initialValue, - error, - initialValue: initialValues[name], - invalid: !!error, - pristine: !isTouched, - touched: isTouched, - valid: !error, - value: value, - visited: isTouched, - active: active === name, - onFocus: () => setActive(name), - onBlur: () => setActive(null), - onChange: (e: React.ChangeEvent | unknown) => { - const isEvent = _.isObject(e) && "target" in e; - setFieldValue(field.name, isEvent ? e.target.value : e); - setFieldTouched(field.name, true, false); - }, - }; - }); - - const smartFieldsByName = _.indexBy(smartFields, "name"); - - return ( - <FormView<Values> - {...rest} - fields={ - smartFieldsByName as unknown as Record<keyof Values, FormField<Values>> - } - formFields={fields} - formFieldsByName={formFieldsByName} - formObject={formObject} - dirty={dirty} - errors={errors as Record<keyof Values, string>} - invalid={!isValid} - valid={isValid} - pristine={!dirty} - disablePristineSubmit={disablePristineSubmit} - values={values} - submitting={isSubmitting} - asyncValidate={validateForm} - asyncValidating={isValidating} - initializeForm={_.noop} - destroyForm={_.noop} - onSubmitSuccess={_.noop} - resetForm={resetForm} - handleSubmit={submitForm} - onChangeField={setFieldValue} - submitFailed={false} - /> - ); -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormikFormViewAdapter; diff --git a/frontend/src/metabase/containers/FormikForm/index.ts b/frontend/src/metabase/containers/FormikForm/index.ts deleted file mode 100644 index cd8b3568d27..00000000000 --- a/frontend/src/metabase/containers/FormikForm/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./FormikForm"; -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FormikForm"; diff --git a/frontend/src/metabase/containers/FormikForm/useInlineFields.ts b/frontend/src/metabase/containers/FormikForm/useInlineFields.ts deleted file mode 100644 index 8a8f02b9c39..00000000000 --- a/frontend/src/metabase/containers/FormikForm/useInlineFields.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useCallback, useState } from "react"; -import _ from "underscore"; - -import type { FormFieldDefinition } from "metabase-types/forms"; - -type FieldsMap = Record<string, FormFieldDefinition>; - -function useInlineFields() { - const [inlineFields, setInlineFields] = useState<FieldsMap>({}); - - const registerFormField = useCallback((field: FormFieldDefinition) => { - setInlineFields(fields => ({ ...fields, [field.name]: field })); - }, []); - - const unregisterFormField = useCallback((field: FormFieldDefinition) => { - setInlineFields(fields => _.omit(fields, field.name)); - }, []); - - return { - inlineFields, - registerFormField, - unregisterFormField, - }; -} - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default useInlineFields; diff --git a/frontend/src/metabase/entities/containers/EntityCopyModal.tsx b/frontend/src/metabase/entities/containers/EntityCopyModal.tsx index 75b4833a20d..595f6ff4224 100644 --- a/frontend/src/metabase/entities/containers/EntityCopyModal.tsx +++ b/frontend/src/metabase/entities/containers/EntityCopyModal.tsx @@ -8,11 +8,9 @@ import { import { useCollectionListQuery } from "metabase/common/hooks"; import ModalContent from "metabase/components/ModalContent"; import { CreateCollectionOnTheGo } from "metabase/containers/CreateCollectionOnTheGo"; -import type { FormContainerProps } from "metabase/containers/FormikForm"; import { CopyDashboardFormConnected } from "metabase/dashboard/containers/CopyDashboardForm"; import { CopyQuestionForm } from "metabase/questions/components/CopyQuestionForm"; import { Flex, Loader } from "metabase/ui"; -import type { BaseFieldValues } from "metabase-types/forms"; interface EntityCopyModalProps { entityType: string; @@ -21,6 +19,8 @@ interface EntityCopyModalProps { title?: string; onClose: () => void; onSaved: (newEntityObject: any) => void; + overwriteOnInitialValuesChange?: boolean; + onValuesChange?: (values: Record<string, unknown>) => void; form?: any; } @@ -32,7 +32,7 @@ const EntityCopyModal = ({ onClose, onSaved, ...props -}: EntityCopyModalProps & Partial<FormContainerProps<BaseFieldValues>>) => { +}: EntityCopyModalProps) => { const { data: collections = [] } = useCollectionListQuery(); const resolvedObject = diff --git a/frontend/src/metabase/components/form/FormMessage/FormMessage.styled.tsx b/frontend/src/metabase/forms/components/FormMessage/FormMessage.styled.tsx similarity index 100% rename from frontend/src/metabase/components/form/FormMessage/FormMessage.styled.tsx rename to frontend/src/metabase/forms/components/FormMessage/FormMessage.styled.tsx diff --git a/frontend/src/metabase/components/form/FormMessage/FormMessage.tsx b/frontend/src/metabase/forms/components/FormMessage/FormMessage.tsx similarity index 90% rename from frontend/src/metabase/components/form/FormMessage/FormMessage.tsx rename to frontend/src/metabase/forms/components/FormMessage/FormMessage.tsx index a32d563a6c2..45ca5b54f25 100644 --- a/frontend/src/metabase/components/form/FormMessage/FormMessage.tsx +++ b/frontend/src/metabase/forms/components/FormMessage/FormMessage.tsx @@ -53,10 +53,7 @@ export const getSuccessMessage = (formSuccess?: Response) => { return formSuccess?.data?.message; }; -/** - * @deprecated - */ -function FormMessage({ +export function FormMessage({ className, message, formSuccess, @@ -75,6 +72,3 @@ function FormMessage({ </FormMessageStyled> ); } - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default FormMessage; diff --git a/frontend/src/metabase/forms/components/FormMessage/index.ts b/frontend/src/metabase/forms/components/FormMessage/index.ts new file mode 100644 index 00000000000..c5de0d19f91 --- /dev/null +++ b/frontend/src/metabase/forms/components/FormMessage/index.ts @@ -0,0 +1 @@ +export * from "./FormMessage"; diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSection.styled.tsx b/frontend/src/metabase/forms/components/FormSection/FormSection.styled.tsx similarity index 100% rename from frontend/src/metabase/components/form/FormikCustomForm/CustomFormSection.styled.tsx rename to frontend/src/metabase/forms/components/FormSection/FormSection.styled.tsx diff --git a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSection.tsx b/frontend/src/metabase/forms/components/FormSection/FormSection.tsx similarity index 80% rename from frontend/src/metabase/components/form/FormikCustomForm/CustomFormSection.tsx rename to frontend/src/metabase/forms/components/FormSection/FormSection.tsx index bdb9c8dcbf7..dd263b9422c 100644 --- a/frontend/src/metabase/components/form/FormikCustomForm/CustomFormSection.tsx +++ b/frontend/src/metabase/forms/components/FormSection/FormSection.tsx @@ -4,7 +4,7 @@ import DisclosureTriangle from "metabase/components/DisclosureTriangle"; import CS from "metabase/css/core/index.css"; import { useToggle } from "metabase/hooks/use-toggle"; -import { CollapsibleSectionContent } from "./CustomFormSection.styled"; +import { CollapsibleSectionContent } from "./FormSection.styled"; interface SectionProps { title?: string; @@ -37,13 +37,7 @@ interface CustomFormSectionProps extends SectionProps { collapsible?: boolean; } -/** - * @deprecated - */ -function CustomFormSection({ collapsible, ...props }: CustomFormSectionProps) { +export function FormSection({ collapsible, ...props }: CustomFormSectionProps) { const Section = collapsible ? CollapsibleSection : StandardSection; return <Section {...props} />; } - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default CustomFormSection; diff --git a/frontend/src/metabase/forms/components/FormSection/index.ts b/frontend/src/metabase/forms/components/FormSection/index.ts new file mode 100644 index 00000000000..b022861335e --- /dev/null +++ b/frontend/src/metabase/forms/components/FormSection/index.ts @@ -0,0 +1 @@ +export * from "./FormSection"; diff --git a/frontend/src/metabase/forms/components/index.ts b/frontend/src/metabase/forms/components/index.ts index d469ab767ee..cd36d8d229d 100644 --- a/frontend/src/metabase/forms/components/index.ts +++ b/frontend/src/metabase/forms/components/index.ts @@ -4,11 +4,13 @@ export * from "./FormCheckboxGroup"; export * from "./FormErrorMessage"; export * from "./FormGroupsWidget"; export * from "./FormGroupWidget"; +export * from "./FormMessage"; export * from "./FormNumberInput"; export * from "./FormObserver"; export * from "./FormProvider"; export * from "./FormRadioGroup"; export * from "./FormSecretKey"; +export * from "./FormSection"; export * from "./FormSelect"; export * from "./FormSubmitButton"; export * from "./FormSwitch"; diff --git a/frontend/src/metabase/plugins/builtin/auth/google.js b/frontend/src/metabase/plugins/builtin/auth/google.js index 3af20da19ca..b77276ccd96 100644 --- a/frontend/src/metabase/plugins/builtin/auth/google.js +++ b/frontend/src/metabase/plugins/builtin/auth/google.js @@ -2,7 +2,6 @@ import { updateIn } from "icepick"; import GoogleAuthCard from "metabase/admin/settings/auth/containers/GoogleAuthCard"; import GoogleSettingsForm from "metabase/admin/settings/auth/containers/GoogleAuthForm"; -import FormikForm from "metabase/containers/FormikForm"; import MetabaseSettings from "metabase/lib/settings"; import { PLUGIN_AUTH_PROVIDERS, @@ -37,7 +36,7 @@ PLUGIN_ADMIN_SETTINGS_UPDATES.push(sections => PLUGIN_ADMIN_SETTINGS_UPDATES.push(sections => ({ ...sections, "authentication/google": { - component: GoogleSettingsForm ?? FormikForm, + component: GoogleSettingsForm, settings: [ { key: "google-auth-client-id" }, { key: "google-auth-auto-create-accounts-domain" }, -- GitLab