Skip to content
Snippets Groups Projects
Unverified Commit 552c1013 authored by Ryan Laurie's avatar Ryan Laurie Committed by GitHub
Browse files

Remove defunct form components (#41902)

* remove defunct form components

* fix lil type errros
parent 7fd5d3ff
No related branches found
No related tags found
No related merge requests found
Showing
with 8 additions and 731 deletions
......@@ -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";
......
......@@ -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,
......
......@@ -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,
......
......@@ -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";
......
......@@ -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,
......
......@@ -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";
......
......@@ -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,
......
......@@ -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 = {
......
// eslint-disable-next-line import/no-default-export -- deprecated usage
export { default } from "./FormMessage";
/* 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;
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;
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;
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;
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;
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;
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);
}
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";
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,
};
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;
`;
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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment