Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight optional form fields as optional #2078

Merged
merged 1 commit into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import DropzoneWithFileInput, {
DragItemFile,
} from "../../form-components/DropzoneWithFileInput";
import Label from "../../form-components/Label";
import Optional from "../../form-components/Optional";
import InfoTooltip from "../../tooltip/InfoTooltip";

const ListItem = styled("div")`
Expand All @@ -37,6 +38,7 @@ interface PropsT<DroppableObject> {
className?: string;
label?: ReactNode;
tooltip?: string;
optional?: boolean;
dropzoneChildren: (args: ChildArgs) => ReactNode;
items: ReactNode[];
acceptedDropTypes: string[];
Expand All @@ -61,7 +63,12 @@ const DropzoneList = <DroppableObject extends PossibleDroppableObject>(
return (
<div className={props.className}>
<Row>
{props.label && <Label>{props.label}</Label>}
{props.label && (
<Label>
{props.optional && <Optional />}
{props.label}
</Label>
)}
{props.tooltip && <InfoTooltip text={props.tooltip} />}
</Row>
{props.items && props.items.length > 0 && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ import {
import FormConceptCopyModal from "./FormConceptCopyModal";
import FormConceptNode, { DragItemFormConceptNode } from "./FormConceptNode";

interface PropsType extends WrappedFieldProps {
interface Props extends WrappedFieldProps {
formType: string;
fieldName: string;
label: string;
tooltip?: string;
onDropFilterFile: Function;
newValue?: Object;
isSingle?: boolean;
optional?: boolean;
disallowMultipleColumns?: boolean;
blocklistedTables?: string[];
allowlistedTables?: string[];
Expand Down Expand Up @@ -416,7 +417,7 @@ const SxDescription = styled(Description)`
font-size: ${({ theme }) => theme.font.xs};
`;

const FormConceptGroup = (props: PropsType) => {
const FormConceptGroup = (props: Props) => {
const newValue = props.newValue;
const defaults = props.defaults || {};

Expand Down Expand Up @@ -503,6 +504,7 @@ const FormConceptGroup = (props: PropsType) => {
<div>
<DropzoneList<DragItemConceptTreeNode | DragItemFormConceptNode>
tooltip={props.tooltip}
optional={props.optional}
label={
<>
{props.label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ interface PropsT extends WrappedFieldProps {
dropzoneChildren: (args: ChildArgs) => ReactNode;
label: string;
tooltip?: string;
optional?: boolean;
}

const FormMultiQueryDropzone: FC<PropsT> = ({
input,
label,
tooltip,
optional,
dropzoneChildren,
}) => {
const addValue = (newItem) => {
Expand All @@ -39,6 +41,7 @@ const FormMultiQueryDropzone: FC<PropsT> = ({
<DropzoneList<DragItemQuery>
acceptedDropTypes={[PREVIOUS_QUERY, PREVIOUS_SECONDARY_ID_QUERY]}
label={label}
optional={optional}
tooltip={tooltip}
dropzoneChildren={dropzoneChildren}
items={input.value.map((query: PreviousQueryT, i: number) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { exists } from "../../common/helpers/exists";
import Dropzone from "../../form-components/Dropzone";
import Label from "../../form-components/Label";
import Optional from "../../form-components/Optional";
import type { DragItemQuery } from "../../standard-query-editor/types";
import InfoTooltip from "../../tooltip/InfoTooltip";

Expand All @@ -21,6 +22,7 @@ const SxDropzone = styled(Dropzone)<{ centered?: boolean }>`
interface PropsT extends WrappedFieldProps {
label: string;
tooltip?: string;
optional?: boolean;
dropzoneText: string;
className?: string;
}
Expand All @@ -33,6 +35,7 @@ const FormQueryDropzone: FC<PropsT> = (props) => {
return (
<div className={props.className}>
<Label>
{props.optional && <Optional />}
{props.label}
{exists(props.tooltip) && <InfoTooltip text={props.tooltip} />}
</Label>
Expand Down
29 changes: 26 additions & 3 deletions frontend/src/js/external-forms/form/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
FormMultiQueryDropzone,
} from "../form-query-dropzone";
import FormTabNavigation from "../form-tab-navigation/FormTabNavigation";
import { isFormField } from "../helper";
import { isFormField, isOptionalField } from "../helper";

const TabsField = styled("div")``;

Expand Down Expand Up @@ -50,10 +50,17 @@ interface PropsT {
getFieldValue: (fieldName: string) => any;
locale: "de" | "en";
availableDatasets: SelectOptionT[];
optional?: boolean;
}

const Field = ({ field, ...commonProps }: PropsT) => {
const { formType, locale, availableDatasets, getFieldValue } = commonProps;
const {
formType,
optional,
locale,
availableDatasets,
getFieldValue,
} = commonProps;
const { t } = useTranslation();

switch (field.type) {
Expand All @@ -76,6 +83,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
placeholder: (field.placeholder && field.placeholder[locale]) || "",
fullWidth: field.style ? field.style.fullWidth : false,
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -95,6 +103,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
max: field.max,
},
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -107,6 +116,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
inline: true,
label: field.label[locale],
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -119,6 +129,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
label: field.label[locale],
dropzoneText: field.dropzoneLabel[locale],
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -131,6 +142,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
label: field.label[locale],
dropzoneChildren: () => field.dropzoneLabel[locale],
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -157,6 +169,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
value: option.value,
})),
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -174,6 +187,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
label: field.label[locale],
options: availableDatasets,
tooltip: field.tooltip ? field.tooltip[locale] : undefined,
optional,
}}
/>
);
Expand All @@ -199,8 +213,16 @@ const Field = ({ field, ...commonProps }: PropsT) => {
<NestedFields>
{tabToShow.fields.map((f, i) => {
const key = isFormField(f) ? f.name : f.type + i;
const nestedFieldOptional = isOptionalField(f);

return <Field key={key} field={f} {...commonProps} />;
return (
<Field
key={key}
field={f}
{...commonProps}
optional={nestedFieldOptional}
/>
);
})}
</NestedFields>
)}
Expand Down Expand Up @@ -228,6 +250,7 @@ const Field = ({ field, ...commonProps }: PropsT) => {
blocklistedTables: field.blocklistedConnectors,
allowlistedTables: field.allowlistedConnectors,
defaults: field.defaults,
optional,
isValidConcept: (item: Object) =>
!nodeIsInvalid(
item,
Expand Down
20 changes: 12 additions & 8 deletions frontend/src/js/external-forms/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
Form as FormType,
FormField as FormFieldType,
} from "../config-types";
import { collectAllFormFields, isFormField } from "../helper";
import { collectAllFormFields, isFormField, isOptionalField } from "../helper";
import { selectReduxFormState } from "../stateSelectors";
import {
validateRequired,
Expand Down Expand Up @@ -71,12 +71,8 @@ function getNotEmptyValidation(fieldType: string) {
}

function getPossibleValidations(fieldType: string) {
const notEmptyValidation = {
NOT_EMPTY: getNotEmptyValidation(fieldType),
};

return {
...notEmptyValidation,
NOT_EMPTY: getNotEmptyValidation(fieldType),
GREATER_THAN_ZERO: validatePositive,
};
}
Expand All @@ -95,8 +91,14 @@ function getErrorForField(t: TFunction, field: FormFieldType, value: any) {
const validateFn = getPossibleValidations(field.type)[validation];

if (validateFn) {
// If not, someone must have configured an unsupported validation
error = error || validateFn(t, value);
} else {
console.error(
"Validation configured that is not supported: ",
validation,
"for field",
field.name,
);
}
}
}
Expand Down Expand Up @@ -131,11 +133,12 @@ const ConfiguredForm = ({ config, ...props }: ConfiguredFormPropsType) => {
return (
<form>
{config.description && config.description[activeLang] && (
<SxFormHeader description={config.description[activeLang]} />
<SxFormHeader description={config.description[activeLang]!} />
)}
<FormConfigSaver />
{config.fields.map((field, i) => {
const key = isFormField(field) ? field.name : field.type + i;
const optional = isOptionalField(field);

return (
<Field
Expand All @@ -145,6 +148,7 @@ const ConfiguredForm = ({ config, ...props }: ConfiguredFormPropsType) => {
field={field}
availableDatasets={availableDatasets}
locale={activeLang}
optional={optional}
/>
);
})}
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/js/external-forms/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import type { FormField, GeneralField } from "./config-types";

const nonFormFieldTypes = new Set(["HEADLINE", "DESCRIPTION"]);

export const isOptionalField = (field: GeneralField) => {
return (
isFormField(field) &&
(!("validations" in field) ||
("validations" in field &&
(!field.validations || !field.validations.includes("NOT_EMPTY"))))
);
};

export const isFormField = (field: GeneralField): field is FormField => {
return !nonFormFieldTypes.has(field.type);
};
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/js/form-components/InputCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { exists } from "../common/helpers/exists";
import InfoTooltip from "../tooltip/InfoTooltip";
import WithTooltip from "../tooltip/WithTooltip";

import Optional from "./Optional";

const Row = styled("div")`
display: flex;
flex-direction: row;
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/js/form-components/InputDateRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import InfoTooltip from "../tooltip/InfoTooltip";
import BaseInput from "./BaseInput";
import Label from "./Label";
import Labeled from "./Labeled";
import Optional from "./Optional";

const Root = styled("div")<{ center?: boolean }>`
text-align: ${({ center }) => (center ? "center" : "left")};
Expand All @@ -39,7 +40,6 @@ const StyledLabel = styled(Label)<{ large?: boolean }>`
const SxLabeled = styled(Labeled)`
&:first-of-type {
margin-right: 10px;
margin-bottom: 10px;
}
`;

Expand All @@ -53,6 +53,7 @@ interface PropsT {
center?: boolean;
autoFocus?: boolean;
tooltip?: string;
optional?: boolean;
input: {
value: DateStringMinMax;
onChange: (value: DateStringMinMax) => void;
Expand Down Expand Up @@ -80,6 +81,7 @@ const InputDateRange: FC<PropsT> = ({
autoFocus,
labelSuffix,
input: { value, onChange },
optional,
tooltip,
}) => {
const { t } = useTranslation();
Expand Down Expand Up @@ -139,6 +141,7 @@ const InputDateRange: FC<PropsT> = ({
{label && (
<StyledLabel large={large}>
{exists(indexPrefix) && <IndexPrefix># {indexPrefix}</IndexPrefix>}
{optional && <Optional />}
{label}
<InfoTooltip
html={
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/js/form-components/InputPlain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const SxBaseInput = styled(BaseInput)<{ fullWidth?: boolean }>`
interface Props<T> extends InputProps<T> {
label: string;
indexPrefix?: number;
optional?: boolean;
inputType?: string;
money?: boolean;
className?: string;
Expand All @@ -43,6 +44,7 @@ const InputPlain = <T extends string | number | null = string | null>(
largeLabel={props.large}
indexPrefix={props.indexPrefix}
tooltip={props.tooltip}
optional={props.optional}
>
<SxBaseInput
large={props.large}
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/js/form-components/InputSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface PropsT {
selectProps?: Object;
tooltip?: string;
defaultValue?: string | null; // Weird to have it here as well => TODO: get rid of redux-form
optional?: boolean;
input: {
clearable?: boolean;
defaultValue?: string | null;
Expand All @@ -37,6 +38,7 @@ const InputSelect = ({
selectProps,
tooltip,
defaultValue,
optional,
...rest
}: PropsT) => {
const { t } = useTranslation();
Expand All @@ -53,6 +55,7 @@ const InputSelect = ({
disabled={disabled}
valueChanged={!isEmpty(input.value) && input.value !== input.defaultValue}
indexPrefix={indexPrefix}
optional={optional}
label={
<>
{!!label && label}
Expand Down
Loading