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

Action Creator 7: Customize Placeholder text (#25407)

* support field placeholder customization

* update tests
parent 5fc9133f
No related branches found
No related tags found
No related merge requests found
......@@ -10,11 +10,11 @@ export const SettingsPopoverBody = styled.div`
export const SectionLabel = styled.div`
color: ${color("text-medium")};
font-weight: bold;
padding-left: ${space(0)};
margin-bottom: ${space(1)};
`;
export const FieldTypeWrapper = styled.div`
margin-bottom: ${space(2)};
padding-bottom: ${space(2)};
export const Divider = styled.div`
border-bottom: 1px solid ${color("border")};
margin: ${space(2)} 0;
`;
......@@ -4,6 +4,7 @@ import { t } from "ttag";
import TippyPopoverWithTrigger from "metabase/components/PopoverWithTrigger/TippyPopoverWithTrigger";
import type { FieldSettings, FieldType, InputType } from "metabase-types/api";
import Input from "metabase/core/components/Input";
import Radio from "metabase/core/components/Radio";
import Icon from "metabase/components/Icon";
......@@ -11,7 +12,7 @@ import { getFieldTypes, getInputTypes } from "./constants";
import {
SettingsPopoverBody,
SectionLabel,
FieldTypeWrapper,
Divider,
} from "./FieldSettingsPopover.styled";
export function FieldSettingsPopover({
......@@ -58,17 +59,35 @@ export function FormCreatorPopoverBody({
inputType: newInputType,
});
const handleUpdatePlaceholder = (newPlaceholder: string) =>
onChange({
...fieldSettings,
placeholder: newPlaceholder,
});
const hasPlaceholder =
fieldSettings.fieldType !== "date" &&
fieldSettings.inputType !== "inline-select";
return (
<SettingsPopoverBody data-testid="field-settings-popover">
<FieldTypeSelect
value={fieldSettings.fieldType}
onChange={handleUpdateFieldType}
/>
<Divider />
<InputTypeSelect
value={fieldSettings.inputType}
fieldType={fieldSettings.fieldType}
onChange={handleUpdateInputType}
/>
<Divider />
{hasPlaceholder && (
<PlaceholderInput
value={fieldSettings.placeholder ?? ""}
onChange={handleUpdatePlaceholder}
/>
)}
</SettingsPopoverBody>
);
}
......@@ -83,7 +102,7 @@ function FieldTypeSelect({
const fieldTypes = useMemo(getFieldTypes, []);
return (
<FieldTypeWrapper>
<div>
<SectionLabel>{t`Field type`}</SectionLabel>
<Radio
variant="bubble"
......@@ -91,7 +110,7 @@ function FieldTypeSelect({
options={fieldTypes}
onChange={onChange}
/>
</FieldTypeWrapper>
</div>
);
}
......@@ -115,3 +134,25 @@ function InputTypeSelect({
/>
);
}
function PlaceholderInput({
value,
onChange,
}: {
value: string;
onChange: (newPlaceholder: string) => void;
}) {
const inputTypes = useMemo(getInputTypes, []);
return (
<div>
<SectionLabel>{t`Placeholder text`}</SectionLabel>
<Input
fullWidth
value={value}
onChange={e => onChange(e.target.value)}
data-testid="placeholder-input"
/>
</div>
);
}
......@@ -69,4 +69,26 @@ describe("writeback > FormCreator > FieldSettingsPopover", () => {
inputType: "dropdown",
});
});
it("should fire onChange handler editing placeholder", async () => {
const changeSpy = jest.fn();
const settings = getDefaultFieldSettings();
render(
<FieldSettingsPopover fieldSettings={settings} onChange={changeSpy} />,
);
await userEvent.click(screen.getByLabelText("gear icon"));
expect(
await screen.findByTestId("field-settings-popover"),
).toBeInTheDocument();
await userEvent.type(screen.getByTestId("placeholder-input"), "$");
expect(changeSpy).toHaveBeenLastCalledWith({
...settings,
placeholder: "$",
});
});
});
......@@ -5,6 +5,7 @@ import type {
WritebackAction,
FieldSettings,
} from "metabase-types/api";
import type { Parameter } from "metabase-types/types/Parameter";
import type { TemplateTag } from "metabase-types/types/Query";
......@@ -19,6 +20,14 @@ export const getDefaultFormSettings = (
...overrides,
});
type OptionType = {
name: string | number;
value: string | number;
};
const getOptionsFromArray = (options: (number | string)[]): OptionType[] =>
options.map(o => ({ name: o, value: o }));
export const getDefaultFieldSettings = (
overrides: Partial<FieldSettings> = {},
): FieldSettings => ({
......@@ -40,39 +49,48 @@ const getSampleOptions = () => [
{ name: t`Option Three`, value: 3 },
];
const getOptionsFromArray = (options: (number | string)[]) =>
options.map(o => ({ name: o, value: o }));
interface FieldPropTypeMap {
[key: string]: string;
}
const fieldPropsTypeMap: FieldPropTypeMap = {
string: "input",
text: "text",
date: "date",
datetime: "date",
monthyear: "date",
quarteryear: "date",
dropdown: "select",
"inline-select": "radio",
};
const inputTypeHasOptions = (fieldSettings: FieldSettings) =>
["dropdown", "inline-select"].includes(fieldSettings.inputType);
interface FieldProps {
type: string;
placeholder?: string;
options?: OptionType[];
values?: any;
}
const getParameterFieldProps = (fieldSettings: FieldSettings) => {
switch (fieldSettings.inputType) {
case "string":
return { type: "input" };
case "text":
return { type: "text" };
case "number":
return { type: "integer" };
case "date":
case "datetime":
case "monthyear":
case "quarteryear":
return { type: "date", values: {} };
case "dropdown":
return {
type: "select",
options: fieldSettings.valueOptions?.length
? getOptionsFromArray(fieldSettings.valueOptions)
: getSampleOptions(),
};
case "inline-select":
return {
type: "radio",
options: fieldSettings.valueOptions?.length
? getOptionsFromArray(fieldSettings.valueOptions)
: getSampleOptions(),
};
default:
return { type: "input" };
const fieldProps: FieldProps = {
type: fieldPropsTypeMap[fieldSettings?.inputType] ?? "input",
placeholder: fieldSettings.placeholder ?? "",
};
if (inputTypeHasOptions(fieldSettings)) {
fieldProps.options = fieldSettings.valueOptions?.length
? getOptionsFromArray(fieldSettings.valueOptions)
: getSampleOptions();
}
if (fieldProps.type === "date") {
fieldProps.values = {};
}
return fieldProps;
};
export const getFormFieldForParameter = (
......
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