@overmap-ai/forms 1.0.6 → 1.0.9-handle-patchform-errors.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.js","sources":["../src/fields/BaseField/BaseField.ts","../src/fields/BaseField/layouts.tsx","../src/fields/BaseField/hooks.tsx","../src/fields/BooleanField/BooleanInput.tsx","../src/fields/BooleanField/BooleanField.tsx","../src/fields/NumberField/NumberInput.tsx","../src/fields/NumberField/NumberField.tsx","../src/fields/DateField/DateInput.tsx","../src/fields/DateField/DateField.tsx","../src/fields/StringOrTextFields/StringOrTextField.ts","../src/fields/StringOrTextFields/StringField/StringInput.tsx","../src/fields/StringOrTextFields/StringField/StringField.tsx","../src/fields/StringOrTextFields/TextField/TextInput.tsx","../src/fields/StringOrTextFields/TextField/TextField.tsx","../src/fields/SelectField/SelectInput.tsx","../src/builder/utils.ts","../src/fields/MultiStringField/MultiStringInput.tsx","../src/fields/MultiStringField/MultiStringField.tsx","../src/fields/SelectField/BaseSelectField.ts","../src/fields/SelectField/SelectField.tsx","../src/fields/SelectField/MultiSelectInput.tsx","../src/fields/SelectField/MultiSelectField.tsx","../src/fields/CustomField/FieldInputClonerField/FieldInputCloner.tsx","../src/fields/CustomField/CustomField.tsx","../src/fields/CustomField/FieldInputClonerField/FieldInputClonerField.tsx","../src/fields/FieldSection/FieldSectionLayout.tsx","../src/fields/FieldSection/FieldSection.tsx","../src/fields/UploadField/utils.ts","../src/fields/UploadField/UploadInput.tsx","../src/fields/UploadField/UploadField.tsx","../src/fields/constants.ts","../src/fields/utils.ts","../src/fields/hooks.tsx","../src/utils.ts","../src/renderer/FormRenderer/FormRenderer.tsx","../src/renderer/FormSubmissionViewer/FormSubmissionViewer.tsx","../src/renderer/FormBrowser/FormBrowser.tsx","../src/renderer/FormSubmissionBrowser/FormSubmissionBrowser.tsx","../src/renderer/PatchForm/Field.tsx","../src/renderer/PatchForm/Provider.tsx","../src/builder/FieldBuilder.tsx","../src/builder/FieldActions.tsx","../src/builder/constants.ts","../src/builder/FieldWithActions.tsx","../src/builder/FieldSectionWithActions.tsx","../src/builder/DropDispatch.ts","../src/builder/FieldsEditor.tsx","../src/builder/FormBuilder.tsx"],"sourcesContent":["import {\r\n\tBaseSerializedField,\r\n\tBaseSerializedObject,\r\n\tFieldTypeIdentifier,\r\n\tFieldValue,\r\n\tISerializedField,\r\n} from \"@overmap-ai/core\"\r\nimport {\r\n\tAnyField,\r\n\tGetInputProps,\r\n\tISerializedOnlyField,\r\n\tInputFieldLevelValidator,\r\n\tInputFormLevelValidator,\r\n} from \"fields/typings\"\r\nimport { Form } from \"typings\"\r\nimport { ReactNode } from \"react\"\r\nimport { FieldSection } from \"fields/FieldSection\"\r\nimport { FieldOptions } from \"./typings\"\r\n\r\n// TODO: These types redefine ISerializedField and related types.\r\n// Looks like they can be merged.\r\n\r\n// TODO: \"Element\" implies an instantiated component in React.\r\nexport abstract class BaseFormElement<TIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier> {\r\n\tpublic readonly type: TIdentifier\r\n\tprotected readonly identifier: string\r\n\tpublic readonly description: string | null\r\n\r\n\tprotected constructor(options: BaseSerializedObject) {\r\n\t\tconst { description = null, identifier, type } = options\r\n\t\tthis.identifier = identifier\r\n\t\tthis.description = description\r\n\t\tthis.type = type as TIdentifier\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn this.identifier\r\n\t}\r\n\r\n\tabstract getInput(props: GetInputProps<this>): ReactNode\r\n\r\n\tstatic deserialize(_data: ISerializedField): AnyField | FieldSection {\r\n\t\tthrow new Error(`${this.name} must implement deserialize.`)\r\n\t}\r\n\r\n\tprotected _serialize(): BaseSerializedObject<TIdentifier> {\r\n\t\tif (!this.identifier) {\r\n\t\t\tthrow new Error(\"Field identifier must be set before serializing.\")\r\n\t\t}\r\n\t\treturn {\r\n\t\t\ttype: this.type,\r\n\t\t\tidentifier: this.identifier,\r\n\t\t\tdescription: this.description,\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport abstract class BaseField<\r\n\tTValue extends FieldValue,\r\n\tTIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier,\r\n> extends BaseFormElement<TIdentifier> {\r\n\tstatic readonly fieldTypeName: string\r\n\tstatic readonly fieldTypeDescription: string\r\n\r\n\tpublic readonly required: boolean\r\n\tprivate readonly formValidators: InputFormLevelValidator<TValue>[]\r\n\tprivate readonly fieldValidators: InputFieldLevelValidator<TValue>[]\r\n\tpublic readonly label: string\r\n\r\n\t/**\r\n\t * By default, validation doesn't execute on `onChange` events when editing fields\r\n\t * until the field has been `touched`. This can be overridden by setting this to `false`\r\n\t * if you want to validate on every `onChange` event. This is important for fields like booleans\r\n\t * which don't have a `onBlur` event (which is used to set the `touched` state).\r\n\t */\r\n\tpublic readonly onlyValidateAfterTouched: boolean = true\r\n\r\n\tprotected constructor(options: FieldOptions<TValue>) {\r\n\t\tconst { label, required, fieldValidators = [], formValidators = [], ...base } = options\r\n\t\tsuper(base)\r\n\t\tthis.label = label\r\n\t\tthis.required = required\r\n\t\tthis.fieldValidators = fieldValidators\r\n\t\tthis.formValidators = formValidators\r\n\t}\r\n\r\n\tpublic static getFieldCreationSchema(): AnyField[] {\r\n\t\treturn []\r\n\t}\r\n\r\n\tprotected isBlank(value: TValue): boolean {\r\n\t\treturn value === null || value === undefined || value === \"\"\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement>): TValue {\r\n\t\treturn event.target.value as unknown as TValue\r\n\t}\r\n\r\n\tpublic getError(value: TValue, allValues?: Form): string | undefined {\r\n\t\tif (this.required && this.isBlank(value)) {\r\n\t\t\treturn \"This field is required.\"\r\n\t\t}\r\n\t\tfor (const validator of this.getFieldValidators()) {\r\n\t\t\tconst error = validator(value)\r\n\t\t\tif (error) return error\r\n\t\t}\r\n\t\tif (allValues) {\r\n\t\t\tfor (const validator of this.getFormValidators()) {\r\n\t\t\t\tconst error = validator(value, allValues)\r\n\t\t\t\tif (error) return error\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// TODO: We can probably combine _serialize and serialize.\r\n\tprotected _serialize(): BaseSerializedField<TIdentifier> {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tlabel: this.label,\r\n\t\t\trequired: this.required,\r\n\t\t}\r\n\t}\r\n\r\n\tabstract serialize(): ISerializedOnlyField\r\n\r\n\tpublic getFieldValidators(): InputFieldLevelValidator<TValue>[] {\r\n\t\treturn [...this.fieldValidators]\r\n\t}\r\n\r\n\tpublic getFormValidators(): InputFormLevelValidator<TValue>[] {\r\n\t\treturn [...this.formValidators]\r\n\t}\r\n}\r\n","import { Flex, Severity, Text, ThemeOptions } from \"@overmap-ai/blocks\"\r\nimport { ReactElement, ComponentProps, ReactNode } from \"react\"\r\nimport styles from \"styling.module.sass\"\r\n\r\nexport type Color = ThemeOptions[\"accentColor\"]\r\n\r\ninterface InputWithLabelProps {\r\n\tseverity: Severity | undefined\r\n\tinputId: string\r\n\tlabelId: string\r\n\tlabel: string\r\n\tchildren: ReactNode\r\n\tflexProps?: ComponentProps<typeof Flex>\r\n}\r\nexport const InputWithLabel = (props: InputWithLabelProps) => {\r\n\tconst { label, children, severity, inputId, labelId, flexProps } = props\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"1\" asChild {...flexProps}>\r\n\t\t\t<label htmlFor={inputId}>\r\n\t\t\t\t<Text severity={severity} id={labelId}>\r\n\t\t\t\t\t{label}\r\n\t\t\t\t</Text>\r\n\t\t\t\t{children}\r\n\t\t\t</label>\r\n\t\t</Flex>\r\n\t)\r\n}\r\n\r\ninterface InputWithLabelAndHelpTextProps {\r\n\tseverity: Severity | undefined\r\n\thelpText: string | null\r\n\tchildren: ReactElement<InputWithLabelProps>\r\n}\r\n\r\nexport const InputWithLabelAndHelpText = (props: InputWithLabelAndHelpTextProps) => {\r\n\tconst { helpText, children, severity } = props\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t{children}\r\n\t\t\t<Flex direction=\"column\">\r\n\t\t\t\t<Text size=\"1\" severity={severity} className={styles.description}>\r\n\t\t\t\t\t{helpText}\r\n\t\t\t\t</Text>\r\n\t\t\t</Flex>\r\n\t\t</Flex>\r\n\t)\r\n}\r\n","import { AnyField, ComponentProps } from \"fields/typings\"\r\nimport { useField } from \"formik\"\r\nimport { ValueOfField } from \"../../typings.ts\"\r\nimport { Severity } from \"@overmap-ai/blocks\"\r\nimport { useMemo, ChangeEventHandler, FocusEventHandler } from \"react\"\r\n\r\n// Wrapper for Formik's useField hook that returns the field's props, meta, and helpers.\r\nexport const useFormikInput = <TField extends AnyField>(props: ComponentProps<TField>) => {\r\n\tconst { id, field, formId, ...rest } = props\r\n\tconst [fieldProps, meta, helpers] = useField<ValueOfField<TField>>(field.getId())\r\n\tconst { touched } = meta\r\n\tconst helpText = meta.error ?? field.description\r\n\tconst severity: Severity | undefined = meta.error ? \"danger\" : undefined\r\n\tconst inputId = id ?? `${formId}-${field.getId()}-input`\r\n\tconst labelId = `${inputId}-label`\r\n\tconst label = field.required ? `${field.label} *` : field.label\r\n\r\n\t// adds field-level validation to onChange and onBlur events\r\n\t// this is necessary because Formik's useField hook does not support field-level validation\r\n\tconst fieldPropsWithValidation: typeof fieldProps = useMemo(() => {\r\n\t\tconst handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {\r\n\t\t\tconst value = field.getValueFromChangeEvent(e)\r\n\t\t\thelpers.setValue(value as ValueOfField<TField>, false).then()\r\n\t\t\t// only validate onChange if the field has been touched\r\n\t\t\tif (touched || !field.onlyValidateAfterTouched) {\r\n\t\t\t\thelpers.setError(field.getError(value))\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {\r\n\t\t\thelpers.setTouched(true, false).then()\r\n\t\t\thelpers.setError(field.getError(field.getValueFromChangeEvent(e)))\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\t...fieldProps,\r\n\t\t\tonChange: handleChange,\r\n\t\t\tonBlur: handleBlur,\r\n\t\t}\r\n\t}, [field, fieldProps, helpers, touched])\r\n\r\n\treturn [\r\n\t\t{\r\n\t\t\thelpText,\r\n\t\t\tseverity,\r\n\t\t\tinputId,\r\n\t\t\tlabelId,\r\n\t\t\tlabel,\r\n\t\t\tfieldProps: fieldPropsWithValidation,\r\n\t\t\thelpers,\r\n\t\t\tfield,\r\n\t\t},\r\n\t\t{ ...rest, \"aria-labelledby\": labelId },\r\n\t] as const\r\n}\r\n","import { Checkbox, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\r\nimport { useFormikInput } from \"../BaseField\"\r\nimport { BooleanField } from \"./BooleanField\"\r\n\r\nconst truthyValues = [true, \"true\"]\r\n\r\nexport const BooleanInput = memo(function BooleanInput(props: ComponentProps<BooleanField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\tconst value = truthyValues.includes(fieldProps.value)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel\r\n\t\t\t\tseverity={severity}\r\n\t\t\t\tinputId={inputId}\r\n\t\t\t\tlabelId={labelId}\r\n\t\t\t\tlabel={label}\r\n\t\t\t\tflexProps={{ direction: \"row-reverse\", justify: \"end\", align: \"center\", gap: \"2\" }}\r\n\t\t\t>\r\n\t\t\t\t<Checkbox\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tcolor={color}\r\n\t\t\t\t\tvalue={value.toString()}\r\n\t\t\t\t\tchecked={value}\r\n\t\t\t\t\tonCheckedChange={fieldProps.onChange}\r\n\t\t\t\t\t// disabled onChange and onBlur as that is handled by onCheckedChange\r\n\t\t\t\t\tonChange={undefined}\r\n\t\t\t\t\tonBlur={undefined}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedBooleanField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { BooleanInput } from \"./BooleanInput\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { CheckCircledIcon } from \"@overmap-ai/blocks\"\r\n\r\nexport class BooleanField extends BaseField<boolean, \"boolean\"> {\r\n\tstatic readonly fieldTypeName = \"Checkbox\"\r\n\tstatic readonly fieldTypeDescription = \"Perfect for both optional and required yes/no questions.\"\r\n\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof CheckCircledIcon = CheckCircledIcon\r\n\r\n\tpublic constructor(options: ChildFieldOptions<boolean>) {\r\n\t\tsuper({ ...options, type: \"boolean\" })\r\n\t}\r\n\r\n\t// if a BooleanField is required, `false` is considered blank\r\n\tprotected isBlank(value: boolean): boolean {\r\n\t\treturn this.required && !value\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement> | boolean): boolean {\r\n\t\tif (typeof event === \"boolean\") return event\r\n\t\treturn event.target.checked\r\n\t}\r\n\r\n\tserialize(): SerializedBooleanField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): BooleanField {\r\n\t\tif (data.type !== \"boolean\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new BooleanField(data)\r\n\t}\r\n\r\n\tgetInput(props: ComponentProps<BooleanField>): ReactNode {\r\n\t\treturn <BooleanInput {...props} field={this} />\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\nimport { ComponentProps } from \"fields/typings\"\nimport { memo } from \"react\"\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\nimport { useFormikInput } from \"../BaseField\"\nimport { NumberField } from \".\"\n\nexport const NumberInput = memo(function NumberInput(props: ComponentProps<NumberField>) {\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\n\tconst color = useSeverityColor(severity)\n\treturn (\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\n\t\t\t\t<TextField.Input\n\t\t\t\t\t{...rest}\n\t\t\t\t\t{...fieldProps}\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tid={inputId}\n\t\t\t\t\tmin={field.minimum}\n\t\t\t\t\tmax={field.maximum}\n\t\t\t\t\tstep={field.integers ? 1 : 0.1}\n\t\t\t\t\tcolor={color}\n\t\t\t\t/>\n\t\t\t</InputWithLabel>\n\t\t</InputWithLabelAndHelpText>\n\t)\n})\n","import { ISerializedField, SerializedNumberField } from \"@overmap-ai/core\"\r\nimport { BooleanField } from \"../BooleanField\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps, InputFieldLevelValidator, InputValidator } from \"../typings\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { NumberInput } from \"./NumberInput\"\r\nimport { FontFamilyIcon } from \"@overmap-ai/blocks\"\r\n\r\n// empty number fields are represented by an empty string\r\nexport type NumberFieldValue = number | \"\"\r\n\r\nexport interface NumberFieldOptions extends ChildFieldOptions<NumberFieldValue> {\r\n\tmaximum?: number\r\n\tminimum?: number\r\n\tintegers?: boolean\r\n}\r\n\r\nexport class NumberField extends BaseField<NumberFieldValue, \"number\"> {\r\n\tstatic readonly fieldTypeName = \"Number\"\r\n\tstatic readonly fieldTypeDescription = \"Allows specifying a number within a given range.\"\r\n\r\n\tpublic readonly minimum: number | undefined\r\n\tpublic readonly maximum: number | undefined\r\n\tpublic readonly integers: boolean\r\n\r\n\tstatic Icon: typeof FontFamilyIcon = FontFamilyIcon\r\n\r\n\tconstructor(options: NumberFieldOptions) {\r\n\t\tconst {\r\n\t\t\tminimum = Number.MIN_SAFE_INTEGER,\r\n\t\t\tmaximum = Number.MAX_SAFE_INTEGER,\r\n\t\t\tintegers = false,\r\n\t\t\t...base\r\n\t\t} = options\r\n\t\tsuper({ ...base, type: \"number\" })\r\n\t\tthis.minimum = minimum\r\n\t\tthis.maximum = maximum\r\n\t\tthis.integers = integers\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement>): NumberFieldValue {\r\n\t\tconst number = Number.parseFloat(event.target.value)\r\n\r\n\t\tif (Number.isNaN(number)) return \"\"\r\n\t\treturn number\r\n\t}\r\n\r\n\tstatic _validateMin: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof allValues.maximum === \"number\" && typeof value === \"number\" && allValues.maximum < value) {\r\n\t\t\treturn \"Minimum cannot be greater than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic _validateMax: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof allValues.minimum === \"number\" && typeof value === \"number\" && allValues.minimum > value) {\r\n\t\t\treturn \"Maximum cannot be less than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Minimum\",\r\n\t\t\t\tdescription: \"Minimum value\",\r\n\t\t\t\tintegers: true,\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"minimum\",\r\n\t\t\t\tformValidators: [this._validateMin],\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Maximum\",\r\n\t\t\t\tdescription: \"Maximum value\",\r\n\t\t\t\tintegers: true,\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum\",\r\n\t\t\t\tformValidators: [this._validateMax],\r\n\t\t\t}),\r\n\t\t\tnew BooleanField({\r\n\t\t\t\tlabel: \"Integers\",\r\n\t\t\t\tdescription: \"Whole numbers only\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"integers\",\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<NumberFieldValue>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\t\tconst min = this.minimum\r\n\t\tconst max = this.maximum\r\n\r\n\t\tif (typeof min === \"number\") {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && value < min) {\r\n\t\t\t\t\treturn `Must be at least ${this.minimum}.`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (typeof max === \"number\") {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && value > max) {\r\n\t\t\t\t\treturn `Must be at most ${this.maximum}.`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (this.integers) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && !Number.isInteger(value)) {\r\n\t\t\t\t\treturn \"Must be a whole number.\"\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tserialize(): SerializedNumberField {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tminimum: this.minimum,\r\n\t\t\tmaximum: this.maximum,\r\n\t\t\tintegers: this.integers,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): NumberField {\r\n\t\tif (data.type !== \"number\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new NumberField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <NumberInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { DateField } from \"./DateField\"\r\n\r\nexport const DateInput = memo(function DateInput(props: ComponentProps<DateField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\t// TODO: Add timezone info\r\n\t// remove the time from the date\r\n\tconst value: string = fieldProps.value ? fieldProps.value.split(\"T\")[0]! : \"\"\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextField.Input {...rest} {...fieldProps} type=\"date\" id={inputId} color={color} value={value} />\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedDateField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport React from \"react\"\r\nimport { DateInput } from \"./DateInput\"\r\nimport { CalendarIcon } from \"@overmap-ai/blocks\"\r\n\r\nexport class DateField extends BaseField<string, \"date\"> {\r\n\tstatic readonly fieldTypeName = \"Date\"\r\n\tstatic readonly fieldTypeDescription = \"Allows specifying a date.\"\r\n\r\n\tstatic Icon: typeof CalendarIcon = CalendarIcon\r\n\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tpublic constructor(options: ChildFieldOptions<string>) {\r\n\t\tsuper({ ...options, type: \"date\" })\r\n\t}\r\n\r\n\tserialize(): SerializedDateField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement>): string {\r\n\t\treturn new Date(event.target.value).toISOString()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): DateField {\r\n\t\tif (data.type !== \"date\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new DateField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <DateInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { NumberField, NumberFieldValue } from \"../NumberField\"\r\nimport { BaseField, FieldOptions } from \"../BaseField\"\r\nimport { SerializedStringField } from \"@overmap-ai/core\"\r\nimport { InputFieldLevelValidator, InputValidator } from \"fields/typings\"\r\n\r\nexport interface StringOrTextFieldOptions extends FieldOptions<string> {\r\n\tminLength?: NumberFieldValue\r\n\tmaxLength?: NumberFieldValue\r\n}\r\n\r\nexport type SerializedStringOrTextField<TIdentifier extends \"string\" | \"text\"> = Omit<SerializedStringField, \"type\"> & {\r\n\ttype: TIdentifier\r\n}\r\n\r\nexport abstract class StringOrTextField<TIdentifier extends \"string\" | \"text\"> extends BaseField<string, TIdentifier> {\r\n\tpublic readonly minLength?: number\r\n\tpublic readonly maxLength: number\r\n\r\n\tprotected constructor(options: StringOrTextFieldOptions) {\r\n\t\tconst { minLength, maxLength = 5000, ...base } = options\r\n\t\tsuper(base)\r\n\t\t// lengths must be greater than or equal to 0\r\n\t\tthis.minLength = minLength ? Math.max(minLength, 0) : undefined\r\n\t\tthis.maxLength = maxLength ? Math.max(maxLength, 0) : 5000\r\n\t}\r\n\r\n\t/**\r\n\t * This function validates that the value given for \"minimum length\" (when creating a new field) is less than or\r\n\t * equal to the value given for \"maximum length\".\r\n\t */\r\n\tstatic _validateMin: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (\r\n\t\t\ttypeof allValues.maximum_length === \"number\" &&\r\n\t\t\ttypeof value === \"number\" &&\r\n\t\t\tallValues.maximum_length < value\r\n\t\t) {\r\n\t\t\treturn \"Minimum cannot be greater than maximum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\t/**\r\n\t * This function validates that the value given for \"maximum length\" (when creating a new field) is greater than or\r\n\t * equal to the value given for \"minimum length\".\r\n\t */\r\n\tstatic _validateMax: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof value !== \"number\") return null\r\n\r\n\t\tconst { minimum_length: minimumLength } = allValues\r\n\r\n\t\tif (typeof minimumLength !== \"number\") {\r\n\t\t\treturn null\r\n\t\t}\r\n\r\n\t\tif (minimumLength > value) {\r\n\t\t\treturn \"Maximum cannot be less than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\t// min, max\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Minimum length\",\r\n\t\t\t\tdescription: \"Minimum number of characters\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"minimum_length\",\r\n\t\t\t\tminimum: 0,\r\n\t\t\t\tmaximum: 100,\r\n\t\t\t\tformValidators: [this._validateMin],\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Maximum length\",\r\n\t\t\t\tdescription: \"Maximum number of characters\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum_length\",\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: 5000, // TODO: depends on short vs long text\r\n\t\t\t\tformValidators: [this._validateMax],\r\n\t\t\t\t// TODO: default: 500 (see: \"Short text fields can hold up to 500 characters on a single line.\")\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<string>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\r\n\t\tif (this.minLength) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (this.minLength && (!value || value.length < this.minLength)) {\r\n\t\t\t\t\t// One exception to this rule:\r\n\t\t\t\t\tif (!this.required && !value) return null\r\n\t\t\t\t\treturn `Minimum ${this.minLength} character(s).`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (this.maxLength) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"string\" && this.maxLength && value.length > this.maxLength) {\r\n\t\t\t\t\treturn `Maximum ${this.maxLength} character(s).`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tprotected _serialize(): SerializedStringOrTextField<TIdentifier> {\r\n\t\tif (!this.identifier) {\r\n\t\t\tthrow new Error(\"Field identifier must be set before serializing.\")\r\n\t\t}\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tminimum_length: this.minLength,\r\n\t\t\tmaximum_length: this.maxLength,\r\n\t\t}\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { useFormikInput, InputWithLabelAndHelpText, InputWithLabel } from \"fields/BaseField\"\r\nimport { StringField } from \"./StringField\"\r\n\r\nexport const StringInput = memo(function StringInput(props: ComponentProps<StringField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextField.Input {...rest} {...fieldProps} type={field.inputType} id={inputId} color={color} />\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedStringField, StringInputType } from \"@overmap-ai/core\"\r\nimport { StringOrTextField, StringOrTextFieldOptions } from \"../StringOrTextField\"\r\nimport { GetInputProps } from \"../../typings\"\r\nimport React from \"react\"\r\nimport { StringInput } from \"./StringInput\"\r\nimport { InputIcon } from \"@overmap-ai/blocks\"\r\n\r\ninterface StringFieldOptions extends Omit<StringOrTextFieldOptions, \"type\"> {\r\n\tinputType?: StringInputType\r\n}\r\n\r\nexport class StringField extends StringOrTextField<\"string\"> {\r\n\tstatic readonly fieldTypeName = \"Short Text\"\r\n\tstatic readonly fieldTypeDescription = \"Short text fields can hold up to 500 characters on a single line.\"\r\n\tpublic readonly inputType: StringInputType\r\n\r\n\tstatic Icon: typeof InputIcon = InputIcon\r\n\r\n\tconstructor(options: StringFieldOptions) {\r\n\t\tconst { inputType = \"text\", ...rest } = options\r\n\t\t// the field supports a max length no larger than 500\r\n\t\tconst maxLength = options.maxLength ? Math.min(500, options.maxLength) : 500\r\n\t\t// the field supports a min length no larger than the max length\r\n\t\tconst minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined\r\n\t\tsuper({ ...rest, maxLength, minLength, type: \"string\" })\r\n\r\n\t\tthis.inputType = inputType\r\n\t}\r\n\r\n\tserialize(): SerializedStringField {\r\n\t\treturn { ...super._serialize(), input_type: this.inputType }\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): StringField {\r\n\t\tif (data.type !== \"string\") throw new Error(\"Type mismatch.\")\r\n\t\tconst { maximum_length, minimum_length, input_type, ...rest } = data\r\n\t\treturn new StringField({ ...rest, maxLength: maximum_length, minLength: minimum_length, inputType: input_type })\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <StringInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { TextArea } from \"@overmap-ai/blocks\"\nimport { ComponentProps } from \"fields/typings\"\nimport { memo } from \"react\"\nimport { useFormikInput, InputWithLabelAndHelpText, InputWithLabel } from \"fields/BaseField\"\nimport { TextField } from \"./TextField\"\n\nexport const TextInput = memo(function TextInput(props: ComponentProps<TextField>) {\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\n\n\treturn (\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\n\t\t\t\t<TextArea {...rest} {...fieldProps} resize=\"vertical\" id={inputId} severity={severity} />\n\t\t\t</InputWithLabel>\n\t\t</InputWithLabelAndHelpText>\n\t)\n})\n","import { ISerializedField, SerializedTextField } from \"@overmap-ai/core\"\r\nimport { StringOrTextField, StringOrTextFieldOptions } from \"../StringOrTextField\"\r\nimport { GetInputProps } from \"../../typings\"\r\nimport React from \"react\"\r\nimport { RowsIcon } from \"@overmap-ai/blocks\"\r\nimport { TextInput } from \"./TextInput\"\r\n\r\nexport interface TextFieldOptions extends Omit<StringOrTextFieldOptions, \"type\"> {}\r\n\r\nexport class TextField extends StringOrTextField<\"text\"> {\r\n\tstatic readonly fieldTypeName = \"Paragraph\"\r\n\tstatic readonly fieldTypeDescription =\r\n\t\t\"Paragraph fields can hold up to 5000 characters and can have multiple lines.\"\r\n\r\n\tstatic Icon: typeof RowsIcon = RowsIcon\r\n\r\n\tconstructor(options: TextFieldOptions) {\r\n\t\t// the field supports a max length no larger than 5k\r\n\t\tconst maxLength = options.maxLength ? Math.min(5000, options.maxLength) : 5000\r\n\t\t// the field supports a min length no larger than the max length\r\n\t\tconst minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined\r\n\t\tsuper({ ...options, maxLength, minLength, type: \"text\" })\r\n\t}\r\n\r\n\tserialize(): SerializedTextField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField) {\r\n\t\tif (data.type !== \"text\") throw new Error(\"Type mismatch.\")\r\n\t\tconst { maximum_length, minimum_length, ...rest } = data\r\n\t\treturn new TextField({ ...rest, maxLength: maximum_length, minLength: minimum_length })\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <TextInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { Select, SelectItemProps } from \"@overmap-ai/blocks\"\r\nimport { SelectField } from \"./SelectField\"\r\n\r\nexport const SelectInput = memo(function SelectInput(props: ComponentProps<SelectField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange, onBlur } = fieldProps\r\n\r\n\t// Convert SelectFieldOption[] to SelectItemProps[]\r\n\tconst options: SelectItemProps[] = useMemo(\r\n\t\t() => field.options.map((option) => ({ value: option.value, itemContent: option.label })),\r\n\t\t[field.options],\r\n\t)\r\n\r\n\tconst handleChange = useCallback(\r\n\t\t(value: string) => {\r\n\t\t\tonChange(value)\r\n\t\t\tonBlur(value)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<Select\r\n\t\t\t\t\titems={options}\r\n\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\tonValueChange={handleChange}\r\n\t\t\t\t\tplaceholder=\"Select one...\"\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tseverity={severity}\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { UserFormRevision, ISerializedField, SerializedFieldSection, slugify } from \"@overmap-ai/core\"\r\nimport { ISerializedOnlyField } from \"fields\"\r\n\r\nexport const emptySection = (id = \"\", fields = [] as ISerializedOnlyField[]): SerializedFieldSection => ({\r\n\ttype: \"section\",\r\n\tfields,\r\n\tidentifier: id,\r\n\tlabel: null,\r\n\tcondition: null,\r\n\tconditional: false,\r\n})\r\n\r\nexport const wrapRootFieldsWithFieldSection = (\r\n\trevision?: UserFormRevision,\r\n): UserFormRevision<SerializedFieldSection> | undefined => {\r\n\tif (!revision) return undefined\r\n\tconst fields = revision.fields\r\n\tlet pending: ISerializedOnlyField[] = []\r\n\tconst sections: SerializedFieldSection[] = []\r\n\r\n\tfor (const field of fields) {\r\n\t\tif (field.type === \"section\") {\r\n\t\t\tif (pending.length > 0) {\r\n\t\t\t\tsections.push(emptySection(`AUTO_section-${fields.indexOf(field)}`, pending))\r\n\t\t\t\tpending = []\r\n\t\t\t}\r\n\t\t\tsections.push(field)\r\n\t\t} else {\r\n\t\t\tpending.push(field)\r\n\t\t}\r\n\t}\r\n\tif (pending.length > 0) {\r\n\t\tsections.push(emptySection(\"AUTO_section-last\", pending))\r\n\t}\r\n\r\n\t// ensure the description isn't null\r\n\treturn { ...revision, fields: sections, description: revision.description ?? \"\" }\r\n}\r\n\r\nexport function reorder<T>(list: T[], source: number, destination: number): T[] {\r\n\tconst result = Array.from(list)\r\n\tconst [removed] = result.splice(source, 1)\r\n\r\n\tif (!removed) throw new Error(\"Could not find field to reorder.\")\r\n\tresult.splice(destination, 0, removed)\r\n\r\n\treturn result\r\n}\r\n\r\nexport function replace<T>(list: T[], index: number, value: T): T[] {\r\n\tconst result = Array.from(list)\r\n\tresult[index] = value\r\n\treturn result\r\n}\r\n\r\nexport function insert<T>(list: T[] | undefined, index: number, value: T): T[] {\r\n\tconst result = Array.from(list ?? [])\r\n\tresult.splice(index, 0, value)\r\n\treturn result\r\n}\r\n\r\nexport function remove<T>(list: T[], index: number): T[] {\r\n\tconst result = Array.from(list)\r\n\tresult.splice(index, 1)\r\n\treturn result\r\n}\r\n\r\nexport const makeIdentifier = (existing: unknown, label: string): string => {\r\n\tif (typeof existing === \"string\" && existing.length > 0) return existing\r\n\r\n\t// add a timestamp to the end of the slug to make it unique\r\n\tconst now = new Date()\r\n\treturn `${slugify(label)}-${now.getTime()}`\r\n}\r\n\r\nexport const findFieldByIdentifier = (fields: ISerializedField[], identifier?: string): ISerializedField | null => {\r\n\tif (!identifier) return null\r\n\tfor (const field of fields) {\r\n\t\tif (field.type === \"section\") {\r\n\t\t\tconst result = findFieldByIdentifier(field.fields, identifier)\r\n\t\t\tif (result) return result\r\n\t\t} else if (field.identifier === identifier) {\r\n\t\t\treturn field\r\n\t\t}\r\n\t}\r\n\treturn null\r\n}\r\n\r\nexport const makeConditionalSourceFields = (sections: SerializedFieldSection[], index: number) => {\r\n\treturn sections.filter((_, i) => i < index).flatMap((field) => field.fields)\r\n}\r\n\r\nexport const getTakenFieldLabels = (fields: SerializedFieldSection[]): string[] => {\r\n\treturn fields\r\n\t\t.flatMap((field) =>\r\n\t\t\tfield.type === \"section\" ? [...field.fields.map((f) => f.label), field.label] : field.label,\r\n\t\t)\r\n\t\t.filter((id): id is string => id !== null)\r\n}\r\n\r\nexport const incrementFieldLabel = (label: string, takenLabels: string[]): string => {\r\n\t// Append (1), then (2), then (3)... to the end of the label until it is unique\r\n\tlet count = 1\r\n\tlet newLabel = `${label} (${count})`\r\n\twhile (takenLabels.includes(newLabel)) {\r\n\t\tnewLabel = `${label} (${++count})`\r\n\t}\r\n\treturn newLabel\r\n}\r\n","import { Badge, Box, Flex, TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { Cross1Icon, PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"../typings.ts\"\r\nimport React, { ChangeEventHandler, memo, useCallback, useMemo, useState } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { DragDropContext, Draggable, Droppable, DropResult } from \"@hello-pangea/dnd\"\r\nimport { IconButton } from \"@overmap-ai/blocks\"\r\nimport { MultiStringField } from \"./MultiStringField\"\r\nimport { SelectFieldOption } from \"@overmap-ai/core\"\r\nimport { remove, reorder } from \"builder/utils.ts\"\r\n\r\n/**\r\n * Allows the user to create an array of unique strings and customize the order.\r\n * User to generate options for the Select field.\r\n */\r\nexport const MultiStringInput = memo(function MultiStringInput(props: ComponentProps<MultiStringField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput<MultiStringField>(props)\r\n\tconst color = useSeverityColor(severity)\r\n\tconst value = useMemo(() => (Array.isArray(fieldProps.value) ? fieldProps.value : []), [fieldProps.value])\r\n\tconst { onChange, onBlur } = fieldProps\r\n\tconst droppableId = `${inputId}-droppable`\r\n\tconst { disabled } = rest\r\n\r\n\tconst [intermediateValue, setIntermediateValue] = useState(\"\")\r\n\tconst [internalError, setInternalError] = useState(\"\")\r\n\r\n\tconst updatedHelpText = internalError || helpText\r\n\tconst updatedColor = internalError ? \"red\" : color\r\n\r\n\tconst setValueAndTouched = useCallback(\r\n\t\t(newValue: SelectFieldOption[]) => {\r\n\t\t\tonChange(newValue)\r\n\t\t\tonBlur(newValue)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\t// handle change to the input\r\n\tconst handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(\r\n\t\t(e) => {\r\n\t\t\tif (value.findIndex((option: SelectFieldOption): boolean => option.value === e.target.value.trim()) >= 0) {\r\n\t\t\t\t// There is already an option with this value.\r\n\t\t\t\tsetInternalError(\"All options must be unique\")\r\n\t\t\t} else if (!e.target.value) {\r\n\t\t\t\tsetInternalError(\"Option cannot be empty\")\r\n\t\t\t} else {\r\n\t\t\t\tsetInternalError(\"\")\r\n\t\t\t}\r\n\t\t\tsetIntermediateValue(e.target.value)\r\n\t\t},\r\n\t\t[setIntermediateValue, value],\r\n\t)\r\n\r\n\tconst addOption = useCallback(() => {\r\n\t\tif (internalError) return\r\n\r\n\t\tif (!intermediateValue.trim()) {\r\n\t\t\treturn setInternalError(\"Option cannot be empty\")\r\n\t\t}\r\n\r\n\t\tconst trimmedValue = intermediateValue.trim()\r\n\t\t// value and label are the same for user-defined options.\r\n\t\tsetValueAndTouched([...value, { value: trimmedValue, label: trimmedValue }])\r\n\t\tsetIntermediateValue(\"\")\r\n\t}, [intermediateValue, internalError, setValueAndTouched, value])\r\n\r\n\t// moves the intermediate value into the value array\r\n\tconst handleKeyDown = useCallback(\r\n\t\t(e: React.KeyboardEvent<HTMLInputElement>) => {\r\n\t\t\tif (e.key === \"Enter\") {\r\n\t\t\t\t// don't try and submit the form\r\n\t\t\t\te.preventDefault()\r\n\r\n\t\t\t\taddOption()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[addOption],\r\n\t)\r\n\r\n\t// delete an existing option\r\n\tconst handleDeleteOption = useCallback(\r\n\t\t(index: number) => {\r\n\t\t\tsetValueAndTouched(remove(value, index))\r\n\t\t},\r\n\t\t[value, setValueAndTouched],\r\n\t)\r\n\r\n\t// change the order of existing options\r\n\tconst handleDragEnd = useCallback(\r\n\t\t(result: DropResult) => {\r\n\t\t\tif (!result.destination) return\r\n\r\n\t\t\tconst sourceIndex = result.source.index\r\n\t\t\tconst destinationIndex = result.destination.index\r\n\r\n\t\t\tsetValueAndTouched(reorder(value, sourceIndex, destinationIndex))\r\n\t\t},\r\n\t\t[setValueAndTouched, value],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<DragDropContext onDragEnd={handleDragEnd}>\r\n\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t<InputWithLabelAndHelpText helpText={updatedHelpText} severity={severity}>\r\n\t\t\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t\t\t{/* Do not show input if disabled and options are defined */}\r\n\t\t\t\t\t\t{(!disabled || value.length === 0) && (\r\n\t\t\t\t\t\t\t<Flex gap=\"2\">\r\n\t\t\t\t\t\t\t\t<Box grow=\"1\">\r\n\t\t\t\t\t\t\t\t\t<TextField.Input\r\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Press enter to add a new option\"\r\n\t\t\t\t\t\t\t\t\t\t{...rest}\r\n\t\t\t\t\t\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\t\t\t\t\t\tvalue={intermediateValue}\r\n\t\t\t\t\t\t\t\t\t\tonChange={handleChange}\r\n\t\t\t\t\t\t\t\t\t\tonKeyDown={handleKeyDown}\r\n\t\t\t\t\t\t\t\t\t\tid={inputId}\r\n\t\t\t\t\t\t\t\t\t\tcolor={updatedColor}\r\n\t\t\t\t\t\t\t\t\t\t// disable default onBlur behavior due to its error handling\r\n\t\t\t\t\t\t\t\t\t\tonBlur={undefined}\r\n\t\t\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\t\t</Box>\r\n\t\t\t\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\t\t\t\taria-label=\"Add option\"\r\n\t\t\t\t\t\t\t\t\tdisabled={!!internalError || disabled}\r\n\t\t\t\t\t\t\t\t\tonClick={addOption}\r\n\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t<PlusIcon />\r\n\t\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</InputWithLabel>\r\n\t\t\t\t</InputWithLabelAndHelpText>\r\n\t\t\t\t<Droppable droppableId={droppableId}>\r\n\t\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t\t<Flex {...droppableProvided.droppableProps} ref={droppableProvided.innerRef} direction=\"column\">\r\n\t\t\t\t\t\t\t{value.map((option: SelectFieldOption, index) => (\r\n\t\t\t\t\t\t\t\t<Draggable\r\n\t\t\t\t\t\t\t\t\tdraggableId={`${option.value}-draggable`}\r\n\t\t\t\t\t\t\t\t\tindex={index}\r\n\t\t\t\t\t\t\t\t\tkey={option.value}\r\n\t\t\t\t\t\t\t\t\tisDragDisabled={disabled}\r\n\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t{({ draggableProps, dragHandleProps, innerRef }) => (\r\n\t\t\t\t\t\t\t\t\t\t<Flex\r\n\t\t\t\t\t\t\t\t\t\t\t{...dragHandleProps}\r\n\t\t\t\t\t\t\t\t\t\t\t{...draggableProps}\r\n\t\t\t\t\t\t\t\t\t\t\tref={innerRef}\r\n\t\t\t\t\t\t\t\t\t\t\tgap=\"2\"\r\n\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\r\n\t\t\t\t\t\t\t\t\t\t\tjustify=\"between\"\r\n\t\t\t\t\t\t\t\t\t\t\tmb=\"1\"\r\n\t\t\t\t\t\t\t\t\t\t\tasChild\r\n\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t<Badge color=\"gray\" size=\"2\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<span>{option.label}</span>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Delete option\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tseverity=\"info\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tdisabled={disabled}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => handleDeleteOption(index)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Cross1Icon />\r\n\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t\t\t\t\t\t</Badge>\r\n\t\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t</Draggable>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t)}\r\n\t\t\t\t</Droppable>\r\n\t\t\t</Flex>\r\n\t\t</DragDropContext>\r\n\t)\r\n})\r\n","import { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { ISerializedField, SelectFieldOption, SerializedMultiStringField } from \"@overmap-ai/core\"\r\nimport { MultiStringInput } from \"./MultiStringInput\"\r\nimport { GetInputProps, InputFieldLevelValidator } from \"../typings.ts\"\r\nimport { ReactNode } from \"react\"\r\nimport { ListBulletIcon } from \"@overmap-ai/blocks\"\r\n\r\ntype MultiStringFieldOptions = ChildFieldOptions<SelectFieldOption[]> & {\r\n\tminimum_length?: number\r\n\tmaximum_length?: number\r\n}\r\n\r\n/**\r\n * A field that lets the user input multiple strings. Each string must be unique. Useful for things like:\r\n * - Specifying the options of a SelectField (used in `SelectField.getFieldCreationSchema`\r\n * - Listing serial numbers and similar\r\n */\r\nexport class MultiStringField extends BaseField<SelectFieldOption[], \"multi-string\"> {\r\n\tstatic readonly fieldTypeName = \"Multi-string\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to provide multiple unique strings.\"\r\n\tpublic readonly minLength: number\r\n\tpublic readonly maxLength: number\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof ListBulletIcon = ListBulletIcon\r\n\r\n\tconstructor(options: MultiStringFieldOptions) {\r\n\t\tconst { minimum_length, maximum_length, ...rest } = options\r\n\t\tsuper({ ...rest, type: \"multi-string\" })\r\n\t\tthis.minLength = minimum_length ?? 0\r\n\t\tthis.maxLength = maximum_length ?? Infinity\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(\r\n\t\tevent: React.ChangeEvent<HTMLInputElement> | SelectFieldOption[],\r\n\t): SelectFieldOption[] {\r\n\t\tif (Array.isArray(event)) return event\r\n\r\n\t\tthrow new Error(\"Expected an array.\")\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <MultiStringInput field={this} {...props} />\r\n\t}\r\n\r\n\tserialize(): SerializedMultiStringField {\r\n\t\treturn { ...super._serialize(), minimum_length: this.minLength, maximum_length: this.maxLength }\r\n\t}\r\n\r\n\tprotected isBlank(value: SelectFieldOption[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tpublic getFieldValidators(): InputFieldLevelValidator<SelectFieldOption[]>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (Array.isArray(value) && value.length < this.minLength) {\r\n\t\t\t\treturn `Must have at least ${this.minLength} options.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (Array.isArray(value) && value.length > this.maxLength) {\r\n\t\t\t\treturn `Must have at most ${this.maxLength} options.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): MultiStringField {\r\n\t\tif (data.type !== \"multi-string\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new MultiStringField(data)\r\n\t}\r\n}\r\n","import { FieldValue, SelectFieldOption } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { MultiStringField } from \"../MultiStringField\"\r\n\r\n/**\r\n * The options passed to the constructor of SelectField.\r\n */\r\nexport interface BaseSelectFieldOptions<TValue, TIdentifier extends \"select\" | \"multi-select\">\r\n\textends ChildFieldOptions<TValue> {\r\n\t/** When instantiating a SelectField, you can either pass an array of strings or an array of objects. User-created\r\n\t * forms only support arrays of strings. For more complex internal purposes, you can provide an array of objects\r\n\t * where the `label` is the text to display to the user and the `value` is the value handled by Formik.*/\r\n\toptions: string[] | SelectFieldOption[]\r\n\ttype: TIdentifier\r\n}\r\n\r\nexport abstract class BaseSelectField<\r\n\tTValue extends FieldValue,\r\n\tTIdentifier extends \"select\" | \"multi-select\",\r\n> extends BaseField<TValue, TIdentifier> {\r\n\tpublic readonly options: SelectFieldOption[]\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tprotected constructor(options: BaseSelectFieldOptions<TValue, TIdentifier>) {\r\n\t\tsuper(options)\r\n\t\t// SelectField supports two types of options: string[] and { value: string, identifier: string }[]. If\r\n\t\tconst encounteredIds: Set<string> = new Set()\r\n\t\tthis.options = options.options.map((option): SelectFieldOption => {\r\n\t\t\tif (typeof option === \"string\") {\r\n\t\t\t\toption = { label: option, value: option }\r\n\t\t\t}\r\n\t\t\tencounteredIds.add(option.label)\r\n\t\t\treturn option\r\n\t\t})\r\n\t\tif (encounteredIds.size !== options.options.length) {\r\n\t\t\t// TODO: Determine if we need to prevent this.\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.error(\r\n\t\t\t\t`${\r\n\t\t\t\t\toptions.options.length - encounteredIds.size\r\n\t\t\t\t} duplicate identifiers found in options. This may cause unexpected behavior. Options:`,\r\n\t\t\t\toptions.options,\r\n\t\t\t)\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _serialize() {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\toptions: this.options,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew MultiStringField({\r\n\t\t\t\tlabel: \"Options\",\r\n\t\t\t\tdescription: \"List possible options for the user to select from.\",\r\n\t\t\t\trequired: true,\r\n\t\t\t\tidentifier: \"options\",\r\n\t\t\t\tminimum_length: 2,\r\n\t\t\t\tmaximum_length: 20,\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n}\r\n","import { ISerializedField, SelectFieldOptionValue, SerializedSelectField } from \"@overmap-ai/core\"\r\nimport { ReactNode } from \"react\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport { SelectInput } from \"./SelectInput\"\r\nimport { BaseSelectField, BaseSelectFieldOptions } from \"./BaseSelectField\"\r\nimport { DropdownMenuIcon } from \"@overmap-ai/blocks\"\r\n\r\n/**\r\n * The options passed to the constructor of SelectField.\r\n */\r\nexport type SelectFieldOptions = Omit<BaseSelectFieldOptions<SelectFieldOptionValue, \"select\">, \"type\">\r\n\r\nexport class SelectField extends BaseSelectField<SelectFieldOptionValue, \"select\"> {\r\n\tstatic readonly fieldTypeName = \"Dropdown\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to select a single option from a list of options.\"\r\n\r\n\tstatic Icon: typeof DropdownMenuIcon = DropdownMenuIcon\r\n\r\n\tpublic constructor(options: SelectFieldOptions) {\r\n\t\tsuper({ ...options, type: \"select\" })\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement> | string): SelectFieldOptionValue {\r\n\t\tif (typeof event === \"string\") return event\r\n\t\treturn event.target.value\r\n\t}\r\n\r\n\tserialize(): SerializedSelectField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): SelectField {\r\n\t\tif (data.type !== \"select\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new SelectField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <SelectInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { MultiSelect } from \"@overmap-ai/blocks\"\r\nimport { MultiSelectField } from \"./MultiSelectField\"\r\n\r\nconst parseValueToArray = (value: string[] | string): string[] => {\r\n\tif (!value) return []\r\n\tif (Array.isArray(value)) return value\r\n\treturn [value]\r\n}\r\n\r\nexport const MultiSelectInput = memo(function MultiSelectInput(props: ComponentProps<MultiSelectField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange, onBlur } = fieldProps\r\n\tconst value = useMemo(() => parseValueToArray(fieldProps.value), [fieldProps.value])\r\n\r\n\tconst handleChange = useCallback(\r\n\t\t(value: string[]) => {\r\n\t\t\tonChange(value)\r\n\t\t\tonBlur(value)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<MultiSelect\r\n\t\t\t\t\tvalue={value}\r\n\t\t\t\t\tonValueChange={handleChange}\r\n\t\t\t\t\toptions={field.options}\r\n\t\t\t\t\tname={fieldProps.name}\r\n\t\t\t\t\tplaceholder=\"Select one or more...\"\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tseverity={severity}\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SelectFieldOptionValue, SerializedMultiSelectField } from \"@overmap-ai/core\"\r\nimport { ReactNode } from \"react\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport { BaseSelectField, BaseSelectFieldOptions } from \"./BaseSelectField\"\r\nimport { MultiSelectInput } from \"./MultiSelectInput\"\r\nimport { CheckboxIcon } from \"@overmap-ai/blocks\"\r\n\r\n/**\r\n * The options passed to the constructor of MultiSelectField.\r\n */\r\nexport type MultiSelectFieldOptions = Omit<BaseSelectFieldOptions<SelectFieldOptionValue[], \"multi-select\">, \"type\">\r\n\r\nexport class MultiSelectField extends BaseSelectField<SelectFieldOptionValue[], \"multi-select\"> {\r\n\tstatic readonly fieldTypeName = \"Multi-select\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to select a multiple options from a list of options.\"\r\n\r\n\tstatic Icon: typeof CheckboxIcon = CheckboxIcon\r\n\r\n\tpublic constructor(options: MultiSelectFieldOptions) {\r\n\t\tsuper({ ...options, type: \"multi-select\" })\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement> | string[]): string[] {\r\n\t\tif (Array.isArray(event)) return event\r\n\t\tthrow new Error(\"Expected an array.\")\r\n\t}\r\n\r\n\tprotected isBlank(value: SelectFieldOptionValue[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tserialize(): SerializedMultiSelectField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): MultiSelectField {\r\n\t\tif (data.type !== \"multi-select\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new MultiSelectField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <MultiSelectInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { memo, useMemo } from \"react\"\nimport { deserialize, useFieldInput } from \"../../index.ts\"\nimport { useField } from \"formik\"\nimport { FieldInputClonerProps } from \"./typings.ts\"\n\n/**\n * Used to dynamically \"clone\" a field's input for use in conditional sections. When a field is selected for a\n * condition, we need to render the same input in the condition section, so the user can input a value for the\n * condition.\n */\nexport const FieldInputCloner = memo(function FieldInputCloner({ field, ...props }: FieldInputClonerProps) {\n\tconst [{ value: identifier }] = useField(field.options.clonedFieldIdentifier)\n\n\tconst deserializedField = useMemo(() => {\n\t\tconst options = field.options.getFieldToClone(identifier)\n\t\tif (!options) return null\n\t\treturn deserialize(options)\n\t}, [field.options, identifier])\n\n\treturn useFieldInput(deserializedField, props)\n})\n","import { FieldTypeIdentifier, FieldValue } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { FC, ReactNode } from \"react\"\r\nimport { GetInputProps, ISerializedOnlyField } from \"../typings\"\r\n\r\nexport interface CustomFieldOptions<TValue> extends ChildFieldOptions<TValue> {}\r\n\r\nexport class CustomField<\r\n\tTValue extends FieldValue,\r\n\t/** The options passed to constructor */\r\n\tTFieldOptions extends CustomFieldOptions<TValue>,\r\n\t/** The props passed to the custom component */\r\n\tTComponentProps extends GetInputProps<CustomField<TValue, TFieldOptions, TComponentProps>>,\r\n\tTIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier,\r\n> extends BaseField<TValue, TIdentifier> {\r\n\tstatic readonly fieldTypeName = \"Custom\"\r\n\tstatic readonly fieldTypeDescription = \"Allows re-rendering of field already in the form\"\r\n\r\n\tpublic readonly Component: FC<TComponentProps>\r\n\r\n\t// identifier of the field whose value is the label of the field to re-render\r\n\tpublic readonly options: TFieldOptions\r\n\r\n\tconstructor(options: TFieldOptions, Component: FC<TComponentProps>) {\r\n\t\tsuper({ ...options, type: \"custom\" })\r\n\t\tthis.options = options\r\n\t\tthis.Component = Component\r\n\t}\r\n\r\n\tserialize(): ISerializedOnlyField {\r\n\t\tthrow new Error(\"Serializing only supported for public input types.\")\r\n\t}\r\n\r\n\tgetInput(props: TComponentProps): ReactNode {\r\n\t\tconst CustomInput = this.Component\r\n\t\treturn <CustomInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { CustomField, CustomFieldOptions } from \"../CustomField\"\r\nimport { FieldValue, ISerializedField } from \"@overmap-ai/core\"\r\nimport { FieldInputCloner, FieldInputClonerProps } from \"./index\"\r\n\r\nexport interface FieldInputClonerFieldOptions extends CustomFieldOptions<unknown> {\r\n\t/** Given an identifier, should return the options of the field with the\r\n\t * corresponding identifier (the field being cloned) */\r\n\tgetFieldToClone: (identifier: string) => ISerializedField | null\r\n\t/** The identifier of the field to clone */\r\n\tclonedFieldIdentifier: string\r\n}\r\n\r\n/**\r\n * The purpose of this is to display a value input field in the condition of a section. The input field will look like\r\n * the input field of the condition. For example, when specifying the conditional value of a SelectField, a SelectInput\r\n * will be rendered.\r\n */\r\nexport class FieldInputClonerField extends CustomField<\r\n\tFieldValue,\r\n\tFieldInputClonerFieldOptions,\r\n\tFieldInputClonerProps\r\n> {\r\n\tconstructor(options: FieldInputClonerFieldOptions) {\r\n\t\tsuper(options, FieldInputCloner)\r\n\t}\r\n}\r\n","import { ComponentProps, isConditionMet, useFieldInputs } from \"fields\"\nimport { memo, useEffect, useMemo } from \"react\"\nimport { Card, Flex, Heading, Text } from \"@overmap-ai/blocks\"\nimport { useFormikContext } from \"formik\"\nimport { FieldSection } from \".\"\nimport get from \"lodash.get\"\nimport styles from \"styling.module.sass\"\n\n/**\n * Used by FieldSection to render a section of fields.\n */\nexport const FieldSectionLayout = memo(function FieldSectionLayout(props: ComponentProps<FieldSection>) {\n\tconst { field: section, ...rest } = props\n\tconst { label, description, fields, condition } = section\n\tconst { values, setFieldValue } = useFormikContext()\n\n\tconst conditionValue = condition?.identifier ? get(values, condition.identifier) : undefined\n\t// sections without a condition are always met\n\tconst conditionMet = useMemo(() => isConditionMet(condition, conditionValue), [condition, conditionValue])\n\n\tuseEffect(() => {\n\t\t// reset all fields in section if condition is not met\n\t\tif (!conditionMet) {\n\t\t\tfor (const childField of fields) {\n\t\t\t\tsetFieldValue(childField.getId(), \"\").then()\n\t\t\t}\n\t\t}\n\t}, [conditionMet, fields, setFieldValue])\n\n\tconst inputs = useFieldInputs(fields, rest)\n\n\t// if condition is not met, do not render section\n\tif (!conditionMet) {\n\t\treturn null\n\t}\n\n\t// if no label is provided, only render fields without the card wrapper\n\tif (!label) {\n\t\treturn inputs\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<Flex direction=\"column\" gap=\"3\">\n\t\t\t\t<Flex direction=\"column\">\n\t\t\t\t\t<Heading as=\"h3\" size=\"3\">\n\t\t\t\t\t\t{label}\n\t\t\t\t\t</Heading>\n\t\t\t\t\t<Text className={styles.description}>{description}</Text>\n\t\t\t\t</Flex>\n\t\t\t\t{inputs}\n\t\t\t</Flex>\n\t\t</Card>\n\t)\n})\n","import {\r\n\tBaseSerializedObject,\r\n\tISerializedField,\r\n\tSelectFieldOption,\r\n\tSerializedCondition,\r\n\tSerializedFieldSection,\r\n} from \"@overmap-ai/core\"\r\nimport { BooleanField, deserializeField, GetInputProps, SelectField } from \"fields\"\r\nimport { FieldInputClonerField, FieldInputClonerFieldOptions } from \"../CustomField/FieldInputClonerField\"\r\nimport { AnyField } from \"fields/typings\"\r\nimport { BaseFormElement } from \"fields/BaseField\"\r\nimport React from \"react\"\r\nimport { FieldSectionLayout } from \"./FieldSectionLayout\"\r\nimport get from \"lodash.get\"\r\nimport set from \"lodash.set\"\r\nimport { Form } from \"typings\"\r\n\r\ninterface FieldSectionOptions extends Omit<BaseSerializedObject, \"type\"> {\r\n\tlabel?: string | null\r\n\tconditional?: boolean\r\n\tcondition?: SerializedCondition | null\r\n\tfields: AnyField[]\r\n}\r\n\r\nexport class FieldSection extends BaseFormElement<\"section\"> {\r\n\tstatic readonly fieldTypeName = \"Section\"\r\n\tstatic readonly fieldTypeDescription =\r\n\t\t\"Sections can be useful for grouping fields together. They can also be conditionally shown or hidden.\"\r\n\r\n\tpublic readonly label: string | null\r\n\tpublic readonly fields: AnyField[]\r\n\tpublic readonly condition: SerializedCondition | null\r\n\r\n\tpublic constructor(options: FieldSectionOptions) {\r\n\t\tconst { label = null, fields, condition = null, conditional, ...base } = options\r\n\r\n\t\tsuper({ ...base, type: \"section\" })\r\n\t\tthis.fields = fields\r\n\t\tthis.condition = condition\r\n\t\tthis.label = label\r\n\r\n\t\t// handle case when condition is removed\r\n\t\tif (conditional === false) {\r\n\t\t\tthis.condition = null\r\n\t\t}\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema(options: ISerializedField[]): BaseFormElement[] {\r\n\t\t// conditions require at least one field to be present\r\n\t\tif (options.length === 0) return []\r\n\r\n\t\treturn [\r\n\t\t\tnew BooleanField({\r\n\t\t\t\tlabel: \"Conditional\",\r\n\t\t\t\tdescription: \"Conditionally show or hide this section.\",\r\n\t\t\t\tidentifier: \"conditional\",\r\n\t\t\t\trequired: false,\r\n\t\t\t}),\r\n\t\t\t// Declare a section that will hold options for the condition (if any).\r\n\t\t\tnew FieldSection({\r\n\t\t\t\tlabel: \"Conditional settings\",\r\n\t\t\t\tidentifier: \"conditional-settings\",\r\n\t\t\t\t// This section will only be rendered if the above \"Conditional\" field is checked.\r\n\t\t\t\tcondition: {\r\n\t\t\t\t\tidentifier: \"conditional\",\r\n\t\t\t\t\tvalue: true,\r\n\t\t\t\t},\r\n\t\t\t\t// These are the options of the condition.\r\n\t\t\t\tfields: [\r\n\t\t\t\t\t// Declare a select field that will be used to select the field against which we will check the\r\n\t\t\t\t\t// condition. This must be selected before the next field is rendered.\r\n\t\t\t\t\tnew SelectField({\r\n\t\t\t\t\t\tlabel: \"Field\",\r\n\t\t\t\t\t\tdescription: \"The field to use for the condition.\",\r\n\t\t\t\t\t\t// The options (for the field against which we will check the condition) are all the labels of\r\n\t\t\t\t\t\t// the fields in the previous section(s) (or fields declared before with no section) that\r\n\t\t\t\t\t\t// support conditions. We pass in both the label and the identifier of each supported field. The\r\n\t\t\t\t\t\t// identifier becomes the value of the option.\r\n\t\t\t\t\t\toptions: options\r\n\t\t\t\t\t\t\t.map((option): SelectFieldOption | null => {\r\n\t\t\t\t\t\t\t\t// If the field doesn't have a label, it can't be used for a condition.\r\n\t\t\t\t\t\t\t\tif (!option.label) return null\r\n\t\t\t\t\t\t\t\t// Upload fields cannot be used for conditions.\r\n\t\t\t\t\t\t\t\tif (option.type === \"upload\") return null\r\n\r\n\t\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t\tlabel: option.label,\r\n\t\t\t\t\t\t\t\t\tvalue: option.identifier,\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t.filter((option): option is SelectFieldOption => !!option),\r\n\t\t\t\t\t\tidentifier: \"condition.identifier\",\r\n\t\t\t\t\t\trequired: true,\r\n\t\t\t\t\t}),\r\n\t\t\t\t\t// Declare a custom field that will be used to input a value for the condition. The value of the\r\n\t\t\t\t\t// conditional field selected in the previous step must be equal to the value the user inputs into\r\n\t\t\t\t\t// this field for the section to be rendered.\r\n\t\t\t\t\tnew FieldInputClonerField({\r\n\t\t\t\t\t\tlabel: \"Value\",\r\n\t\t\t\t\t\tidentifier: \"condition.value\",\r\n\t\t\t\t\t\trequired: true,\r\n\t\t\t\t\t\tclonedFieldIdentifier: \"condition.identifier\",\r\n\t\t\t\t\t\tgetFieldToClone(identifier: string) {\r\n\t\t\t\t\t\t\tif (!identifier) {\r\n\t\t\t\t\t\t\t\t// No field has been chosen yet.\r\n\t\t\t\t\t\t\t\treturn null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t// Find the field options with a matching identifier.\r\n\t\t\t\t\t\t\tconst option = options.find((option) => option.identifier === identifier)\r\n\t\t\t\t\t\t\tif (!option) {\r\n\t\t\t\t\t\t\t\t// This is unexpected, but not fatal.\r\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\t\t\t\t\tconsole.error(\"Could not find field with identifier\", identifier)\r\n\t\t\t\t\t\t\t\treturn null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t...option,\r\n\t\t\t\t\t\t\t\t// Override some options to make it make sense in the context and to make it work with the framework.\r\n\t\t\t\t\t\t\t\tlabel: \"Value\",\r\n\t\t\t\t\t\t\t\tidentifier: \"condition.value\",\r\n\t\t\t\t\t\t\t\tdescription: \"The value to compare against.\",\r\n\t\t\t\t\t\t\t\trequired: option.type !== \"boolean\",\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t} satisfies FieldInputClonerFieldOptions),\r\n\t\t\t\t],\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): FieldSection {\r\n\t\tif (data.type !== \"section\") throw new Error(\"Invalid type\")\r\n\t\tconst fields = data.fields?.map(deserializeField) ?? []\r\n\t\treturn new FieldSection({ ...data, fields })\r\n\t}\r\n\r\n\tconditional(): this is { condition: SerializedCondition } {\r\n\t\treturn this.condition !== null\r\n\t}\r\n\r\n\tserialize(): SerializedFieldSection {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tlabel: this.label,\r\n\t\t\tcondition: this.condition,\r\n\t\t\tconditional: this.conditional(),\r\n\t\t\tfields: this.fields.map((field) => field.serialize()),\r\n\t\t}\r\n\t}\r\n\r\n\tgetErrors(allValues: Form): Record<string, string> {\r\n\t\tconst errors: Record<string, string> = {}\r\n\t\tfor (const field of this.fields) {\r\n\t\t\tconst id = field.getId()\r\n\t\t\tconst error = field.getError(get(allValues, id), allValues)\r\n\t\t\tif (error) {\r\n\t\t\t\tset(errors, field.getId(), error)\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn errors\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <FieldSectionLayout field={this} {...props} />\r\n\t}\r\n}\r\n","export const convertBytesToLargestUnit = (bytes: number) => {\r\n\t// all files must be less than 50 MB\r\n\tconst units = [\"byte\", \"kilobyte\", \"megabyte\"]\r\n\tlet sizeInUnit = bytes\r\n\tlet unitIndex = 0\r\n\twhile (sizeInUnit > 1024 && unitIndex < units.length - 1) {\r\n\t\tsizeInUnit /= 1024\r\n\t\tunitIndex++\r\n\t}\r\n\tconst formatter = new Intl.NumberFormat([], { maximumFractionDigits: 2, style: \"unit\", unit: units[unitIndex] })\r\n\treturn formatter.format(sizeInUnit)\r\n}\r\n","import { Box, Button, Card, Flex, IconButton, useSeverityColor, Cross1Icon, Text, UploadIcon } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\r\nimport { useFormikInput } from \"../BaseField\"\r\nimport { UploadField } from \"./UploadField\"\r\nimport styles from \"./UploadInput.module.sass\"\r\nimport { convertBytesToLargestUnit } from \"./utils\"\r\n\r\nexport const NumberInput = memo(function NumberInput(props: ComponentProps<UploadField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange } = fieldProps\r\n\tconst color = useSeverityColor(severity)\r\n\tconst input = useRef<HTMLInputElement>(null)\r\n\tconst { value } = fieldProps\r\n\r\n\tconst updatedHelpText = useMemo(() => {\r\n\t\tif (helpText) return helpText\r\n\t\tif (field.maxFileSize) {\r\n\t\t\tconst size = convertBytesToLargestUnit(field.maxFileSize)\r\n\t\t\treturn `Maximum file size: ${size}`\r\n\t\t}\r\n\t\treturn null\r\n\t}, [field.maxFileSize, helpText])\r\n\r\n\tconst handleClick = useCallback(() => {\r\n\t\tinput.current?.click()\r\n\t}, [])\r\n\r\n\tconst handleRemove = useCallback(\r\n\t\t(index: number) => {\r\n\t\t\tconst files = [...value]\r\n\t\t\tfiles.splice(index, 1)\r\n\r\n\t\t\tconst event = { target: { files } }\r\n\t\t\tonChange(event)\r\n\t\t},\r\n\t\t[value, onChange],\r\n\t)\r\n\r\n\tconst multipleButtonText = value ? \"Select new files\" : \"Select files\"\r\n\tconst singleButtonText = value ? \"Select new file\" : \"Select a file\"\r\n\tconst buttonText = field.maxFiles > 1 ? multipleButtonText : singleButtonText\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t<InputWithLabelAndHelpText helpText={updatedHelpText} severity={severity}>\r\n\t\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t\t<Flex direction=\"row\" gap=\"2\">\r\n\t\t\t\t\t\t<Box width=\"max-content\" asChild>\r\n\t\t\t\t\t\t\t<Button {...rest} onClick={handleClick}>\r\n\t\t\t\t\t\t\t\t<UploadIcon /> {buttonText}\r\n\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t</Box>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t\t<input\r\n\t\t\t\t\t\t{...rest}\r\n\t\t\t\t\t\ttype=\"file\"\r\n\t\t\t\t\t\tref={input}\r\n\t\t\t\t\t\tid={inputId}\r\n\t\t\t\t\t\taccept={field.extensions?.join(\",\")}\r\n\t\t\t\t\t\tmultiple={field.maxFiles > 1}\r\n\t\t\t\t\t\tcolor={color}\r\n\t\t\t\t\t\tstyle={{ display: \"none\" }}\r\n\t\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\t\tvalue=\"\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</InputWithLabel>\r\n\t\t\t</InputWithLabelAndHelpText>\r\n\t\t\t{Array.isArray(value) && value.length > 0 && (\r\n\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t{value.map((file, index) => (\r\n\t\t\t\t\t\t<DisplayFile\r\n\t\t\t\t\t\t\tkey={index}\r\n\t\t\t\t\t\t\tfield={field}\r\n\t\t\t\t\t\t\tfile={file}\r\n\t\t\t\t\t\t\tonRemove={() => handleRemove(index)}\r\n\t\t\t\t\t\t\tdisabled={rest.disabled}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t))}\r\n\t\t\t\t</Flex>\r\n\t\t\t)}\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\ninterface DisplayFileProps {\r\n\tfile: File | Promise<File>\r\n\tfield: UploadField\r\n\tdisabled?: boolean\r\n\tonRemove: () => void\r\n}\r\n\r\nconst DisplayFile = memo(function DisplayFile({ file, field, onRemove, disabled }: DisplayFileProps) {\r\n\tconst [resolvedFile, setResolvedFile] = useState<File | null>(null)\r\n\tconst error = useMemo(() => resolvedFile && field.getError([resolvedFile]), [field, resolvedFile])\r\n\tconst { url, name, size } = useMemo(() => {\r\n\t\tlet url: string | null = null\r\n\t\tlet name: string\r\n\t\tlet size: string\r\n\t\t// if the file is an image, create a url for it\r\n\t\tif (resolvedFile?.type.startsWith(\"image/\")) {\r\n\t\t\turl = URL.createObjectURL(resolvedFile)\r\n\t\t}\r\n\t\tif (resolvedFile) {\r\n\t\t\tname = resolvedFile.name\r\n\t\t\tsize = convertBytesToLargestUnit(resolvedFile.size)\r\n\t\t} else {\r\n\t\t\tname = \"Downloading...\"\r\n\t\t\tsize = \"...\"\r\n\t\t}\r\n\t\treturn { url, name, size }\r\n\t}, [resolvedFile])\r\n\r\n\tuseEffect(() => {\r\n\t\tif (file instanceof Promise) {\r\n\t\t\tfile.then(setResolvedFile)\r\n\t\t} else {\r\n\t\t\tsetResolvedFile(file)\r\n\t\t}\r\n\t}, [file])\r\n\r\n\treturn (\r\n\t\t<Card>\r\n\t\t\t<Flex direction={{ initial: \"column\", sm: \"row\" }} gap=\"3\" justify=\"between\">\r\n\t\t\t\t<Flex direction=\"row\" gap=\"3\" align=\"center\" grow=\"1\" shrink=\"0\">\r\n\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\tseverity=\"info\"\r\n\t\t\t\t\t\tvariant=\"outline\"\r\n\t\t\t\t\t\taria-label={`Remove ${name}`}\r\n\t\t\t\t\t\tdisabled={disabled}\r\n\t\t\t\t\t\tonClick={onRemove}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t<Cross1Icon />\r\n\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t\t\t\t<Text>{name}</Text>\r\n\t\t\t\t\t\t<Text size=\"1\">{size}</Text>\r\n\t\t\t\t\t\t{error && (\r\n\t\t\t\t\t\t\t<Text size=\"1\" severity=\"danger\">\r\n\t\t\t\t\t\t\t\t{error}\r\n\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{url && <img className={styles.previewImage} src={url} alt={name} />}\r\n\t\t\t</Flex>\r\n\t\t</Card>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedUploadField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps, InputFieldLevelValidator } from \"../typings\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { NumberInput } from \"./UploadInput\"\r\nimport { UploadIcon } from \"@overmap-ai/blocks\"\r\nimport { NumberField } from \"../NumberField\"\r\nimport { convertBytesToLargestUnit } from \"./utils\"\r\nimport { MultiSelectField } from \"../SelectField\"\r\n\r\nexport interface UploadFieldOptions extends ChildFieldOptions<File[]> {\r\n\textensions?: string[]\r\n\tmaximum_size?: number | string\r\n\tmaximum_files?: number | string\r\n}\r\n\r\nconst largestSupportedSize = 50 * 1024 * 1024 // 50 MB\r\n\r\nexport class UploadField extends BaseField<File[], \"upload\"> {\r\n\tstatic readonly fieldTypeName = \"Upload\"\r\n\tstatic readonly fieldTypeDescription = \"Allows a file to be uploaded.\"\r\n\r\n\tpublic readonly extensions?: string[]\r\n\tpublic readonly maxFileSize: number | undefined\r\n\tpublic readonly maxFiles: number\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof UploadIcon = UploadIcon\r\n\r\n\tconstructor(options: UploadFieldOptions) {\r\n\t\tconst { extensions, maximum_files, maximum_size, ...base } = options\r\n\t\tsuper({ ...base, type: \"upload\" })\r\n\r\n\t\tthis.maxFileSize = typeof maximum_size === \"number\" ? maximum_size : undefined\r\n\t\t// if maximum_files is not a number or less than 1, default and clamp to 1\r\n\t\tthis.maxFiles = Math.max(typeof maximum_files === \"number\" ? maximum_files : 1, 1)\r\n\r\n\t\tthis.extensions = extensions\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement>): File[] {\r\n\t\treturn Array.from(event.target.files || [])\r\n\t}\r\n\r\n\tprotected isBlank(value: File[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"How many files can be uploaded?\",\r\n\t\t\t\tdescription: \"By default, only one file can be uploaded.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: 10,\r\n\t\t\t\tidentifier: \"maximum_files\",\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"What is the maximum size of each file?\",\r\n\t\t\t\tdescription: \"Maximum file size in bytes.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum_size\",\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: largestSupportedSize,\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t\tnew MultiSelectField({\r\n\t\t\t\tlabel: \"Accepted file types\",\r\n\t\t\t\tdescription: \"Types of allowed files to upload. If left blank, all files will be accepted.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"extensions\",\r\n\t\t\t\toptions: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"image/*\",\r\n\t\t\t\t\t\tlabel: \"Images\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"audio/*\",\r\n\t\t\t\t\t\tlabel: \"Audio files\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"video/*\",\r\n\t\t\t\t\t\tlabel: \"Videos\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"text/*\",\r\n\t\t\t\t\t\tlabel: \"Text files\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"application/*\",\r\n\t\t\t\t\t\tlabel: \"Application files (includes PDFs and Word documents)\",\r\n\t\t\t\t\t},\r\n\t\t\t\t],\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<File[]>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\t\tconst maxFileSize = this.maxFileSize ?? largestSupportedSize\r\n\t\tconst maxFiles = this.maxFiles ?? 1\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (value && value.some((file) => file.size > maxFileSize)) {\r\n\t\t\t\treturn `Files must be at most ${convertBytesToLargestUnit(maxFileSize)}.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (value && value.length > maxFiles) {\r\n\t\t\t\treturn `You can only upload ${maxFiles} files.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tserialize(): SerializedUploadField {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\textensions: this.extensions,\r\n\t\t\tmaximum_size: this.maxFileSize,\r\n\t\t\tmaximum_files: this.maxFiles,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): UploadField {\r\n\t\tif (data.type !== \"upload\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new UploadField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <NumberInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { StringField, TextField } from \"./StringOrTextFields\"\r\nimport { BooleanField } from \"./BooleanField\"\r\nimport { DateField } from \"./DateField\"\r\nimport { NumberField } from \"./NumberField\"\r\nimport { MultiSelectField, SelectField } from \"./SelectField\"\r\nimport { CustomField } from \"./CustomField\"\r\nimport { MultiStringField } from \"./MultiStringField\"\r\nimport { UploadField } from \"./UploadField\"\r\n\r\nexport const FieldTypeToClsMapping = {\r\n\tdate: DateField,\r\n\tnumber: NumberField,\r\n\tboolean: BooleanField,\r\n\tselect: SelectField,\r\n\tstring: StringField,\r\n\ttext: TextField,\r\n\tcustom: CustomField,\r\n\tupload: UploadField,\r\n\t// TODO: Underscore\r\n\t\"multi-string\": MultiStringField,\r\n\t\"multi-select\": MultiSelectField,\r\n} as const\r\n","import { AnyField, ISchema, ISerializedOnlyField, SchemaMeta } from \"./typings\"\r\nimport { FieldTypeToClsMapping } from \"./constants\"\r\nimport {\r\n\tFieldTypeIdentifier,\r\n\tFieldValue,\r\n\tISerializedField,\r\n\tSelectFieldOption,\r\n\tSerializedCondition,\r\n\tUserFormRevision,\r\n} from \"@overmap-ai/core\"\r\nimport { FieldSection } from \"./FieldSection\"\r\n\r\n// Note: the deserialization methods are separate to avoid circular dependencies.\r\n\r\n/** Deserializes anything but a FieldSection.\r\n * @see `deserialize` for most use cases\r\n */\r\nexport const deserializeField = (serializedField: ISerializedOnlyField): AnyField => {\r\n\tconst fieldType: FieldTypeIdentifier = serializedField.type\r\n\tconst fieldCls = FieldTypeToClsMapping[fieldType]\r\n\treturn fieldCls.deserialize(serializedField)\r\n}\r\n\r\n/** Deserializes anything */\r\nexport const deserialize = (serialized: ISerializedField): AnyField | FieldSection => {\r\n\tif (serialized.type === \"section\") {\r\n\t\treturn FieldSection.deserialize(serialized)\r\n\t}\r\n\treturn deserializeField(serialized)\r\n}\r\n\r\nexport type PartialFormRevision = Pick<UserFormRevision, \"title\" | \"fields\" | \"description\"> & Partial<UserFormRevision>\r\n\r\nexport function formRevisionToSchema(formRevision: PartialFormRevision, meta: Partial<SchemaMeta> = {}): ISchema {\r\n\t// expanding the meta in order to set default values\r\n\tconst { readonly = false } = meta\r\n\r\n\treturn {\r\n\t\ttitle: formRevision.title,\r\n\t\tdescription: formRevision.description,\r\n\t\tfields: formRevision.fields.map((serializedField: ISerializedField) => deserialize(serializedField)),\r\n\t\tmeta: { readonly },\r\n\t}\r\n}\r\n\r\nexport function valueIsFile(v: FieldValue | Promise<File>[] | undefined): v is File[] | Promise<File>[] {\r\n\tif (Array.isArray(v) && v.some((v) => v instanceof File || v instanceof Promise)) return true\r\n\r\n\treturn false\r\n}\r\n\r\nexport function isConditionMet<TValue extends FieldValue | Promise<File>[]>(\r\n\tcondition: TValue extends FieldValue ? SerializedCondition<TValue> | null : null,\r\n\tvalue: TValue,\r\n) {\r\n\t// if no condition is provided, it is always met\r\n\tif (!condition) return true\r\n\r\n\t// conditions due not support file uploads, so we can assume that the value is not an array of File's\r\n\tif (valueIsFile(value) || valueIsFile(condition.value)) throw new Error(\"Conditions do not support file uploads\")\r\n\r\n\tconst valueAsPrimitive: Exclude<FieldValue, SelectFieldOption[] | File[]> = Array.isArray(value)\r\n\t\t? value.map((v) => (typeof v === \"string\" ? v : v.value))\r\n\t\t: value\r\n\r\n\tconst valueToCompare: Exclude<FieldValue, SelectFieldOption[] | File[]> = Array.isArray(condition.value)\r\n\t\t? condition.value.map((v) => (typeof v === \"string\" ? v : v.value))\r\n\t\t: condition.value\r\n\r\n\t// if comparing arrays, check if any of the values match\r\n\tif (Array.isArray(valueToCompare) && Array.isArray(valueAsPrimitive)) {\r\n\t\t// ensure that every value in valueToCompare is in valueAsPrimitive\r\n\t\t// though not necessarily the other way around\r\n\t\tfor (const v of valueToCompare) {\r\n\t\t\tif (!valueAsPrimitive.includes(v)) return false\r\n\t\t}\r\n\t\treturn true\r\n\t}\r\n\r\n\treturn valueToCompare === value\r\n}\r\n","import { GetInputProps } from \"./typings\"\r\nimport { ReactNode, useMemo } from \"react\"\r\nimport { BaseField, BaseFormElement } from \"./BaseField\"\r\nimport { Flex } from \"@overmap-ai/blocks\"\r\nimport { FieldValue } from \"@overmap-ai/core\"\r\n\r\nexport const useFieldInput = <TField extends BaseFormElement | null>(\r\n\tfield: TField,\r\n\tprops: TField extends BaseFormElement ? GetInputProps<TField> : null,\r\n): ReactNode => {\r\n\t// TODO: Consider deep equality check on props\r\n\treturn useMemo(() => {\r\n\t\tif (!props || !field) return null\r\n\t\treturn field.getInput(props)\r\n\t}, [field, props])\r\n}\r\n\r\nexport const useFieldInputs = (fields: BaseFormElement[], props: GetInputProps<BaseField<FieldValue>>): ReactNode => {\r\n\tconst inputs = useMemo(() => {\r\n\t\treturn fields.map((field) => {\r\n\t\t\treturn <div key={field.getId()}>{field.getInput(props)}</div>\r\n\t\t})\r\n\t}, [fields, props])\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t{inputs}\r\n\t\t</Flex>\r\n\t)\r\n}\r\n","import { FieldSection, ISchema, isConditionMet } from \"fields\"\r\nimport { BaseField, BaseFormElement } from \"fields/BaseField\"\r\nimport { FormikErrors } from \"formik\"\r\nimport cloneDeep from \"lodash.clonedeep\"\r\nimport get from \"lodash.get\"\r\nimport set from \"lodash.set\"\r\nimport { Form } from \"typings\"\r\n\r\nexport const hasKeys = (errors: object): boolean => {\r\n\treturn Object.keys(errors).length > 0\r\n}\r\n\r\nexport const validateForm = async (schema: ISchema, form: Form) => {\r\n\t// TODO: Comments\r\n\tconst errors: FormikErrors<Form> = {}\r\n\tfor (const field of schema.fields) {\r\n\t\tif (field instanceof FieldSection) {\r\n\t\t\t// if condition is not met, do not validate section\r\n\t\t\tif (field.condition) {\r\n\t\t\t\tconst { identifier } = field.condition\r\n\r\n\t\t\t\tif (!isConditionMet(field.condition, get(form, identifier))) {\r\n\t\t\t\t\tcontinue\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tObject.assign(errors, field.getErrors(form))\r\n\t\t} else {\r\n\t\t\t// REASON: WebStorm is wrong, TypeScript is right. `field` is a BaseFormElement, which may be a BaseField.\r\n\t\t\t// noinspection SuspiciousTypeOfGuard\r\n\t\t\tif (!(field instanceof BaseField)) {\r\n\t\t\t\tthrow new Error(\"Invalid field type\")\r\n\t\t\t}\r\n\t\t\tconst id = field.getId()\r\n\t\t\tconst error = field.getError(get(form, id), form)\r\n\t\t\tif (error) set(errors, id, error)\r\n\t\t}\r\n\t}\r\n\r\n\t// only return errors if there are any\r\n\tif (hasKeys(errors)) return errors\r\n}\r\n\r\nconst uncontrolledValues: unknown[] = [null, undefined]\r\n\r\n// If a value is not provided, adds empty values for all fields in the\r\n// schema so that the form is fully controlled\r\nexport const initialFormValues = (fields: BaseFormElement[], values: Form): Form => {\r\n\treturn fields.reduce<Form>(\r\n\t\t(acc, field) => {\r\n\t\t\t// check for field section\r\n\t\t\tif (field instanceof FieldSection) {\r\n\t\t\t\treturn { ...acc, ...initialFormValues(field.fields, values) }\r\n\t\t\t}\r\n\t\t\t// values must not be undefined or React will error as\r\n\t\t\t// the input changes from uncontrolled to controlled\r\n\t\t\tif (uncontrolledValues.includes(get(acc, field.getId()))) {\r\n\t\t\t\tset(acc, field.getId(), \"\")\r\n\t\t\t}\r\n\t\t\treturn acc\r\n\t\t},\r\n\t\t// TODO: Had to do this because of this error:\r\n\t\t// > Uncaught TypeError: can't define property \"description\":\r\n\t\t// > Object is not extensible\"\r\n\t\t// This means that we can't mutate `acc` because it's frozen for some\r\n\t\t// unknown reason.\r\n\t\tcloneDeep(values),\r\n\t)\r\n}\r\n","import { Button, Card, Flex, Heading, Text } from \"@overmap-ai/blocks\"\r\nimport { ISchema } from \"fields/typings\"\r\nimport { FormikProvider, useFormik } from \"formik\"\r\nimport { useMemo, memo, forwardRef, useEffect } from \"react\"\r\nimport { initialFormValues, validateForm } from \"utils\"\r\nimport styles from \"styling.module.sass\"\r\nimport { Form } from \"typings\"\r\nimport { useFieldInputs } from \"../../fields\"\r\n\r\ninterface FormRendererProps {\r\n\t/** The schema of the form the render */\r\n\tschema: ISchema\r\n\t/** Initial values of the form */\r\n\tvalues?: Form\r\n\tonSubmit?: (values: Form) => Promise<void> | void\r\n\t/** @default \"Submit\" */\r\n\tsubmitText?: string\r\n\t/** The text of the cancel button (hidden by default)\r\n\t * @default null\r\n\t */\r\n\tcancelText?: string\r\n\tonCancel?: () => void\r\n\tonDirty?: () => void\r\n\t/** Hide the form description\r\n\t * @default false */\r\n\thideDescription?: boolean\r\n\t/** Hide the title (and description)\r\n\t * @default false\r\n\t */\r\n\thideTitle?: boolean\r\n\tclassName?: string\r\n}\r\n\r\nconst defaultHandleSubmit = () => {\r\n\tthrow new Error(\"onSubmit must be provided if form is not readonly.\")\r\n}\r\n\r\nexport const FormRenderer = memo(\r\n\tforwardRef<HTMLDivElement, FormRendererProps>((props, ref) => {\r\n\t\tconst {\r\n\t\t\tschema,\r\n\t\t\tvalues = {},\r\n\t\t\tonSubmit = defaultHandleSubmit,\r\n\t\t\tsubmitText = \"Submit\",\r\n\t\t\tcancelText,\r\n\t\t\tonCancel,\r\n\t\t\tonDirty,\r\n\t\t\t// if the title isn't provided, hide it by default\r\n\t\t\thideTitle = !schema.title,\r\n\t\t\thideDescription,\r\n\t\t\tclassName,\r\n\t\t} = props\r\n\t\tconst { readonly } = schema.meta\r\n\r\n\t\t// randomly generate a form id to ensure field ids are unique\r\n\t\tconst formId = useMemo(() => crypto.randomUUID(), [])\r\n\r\n\t\tconst formik = useFormik<Form>({\r\n\t\t\tinitialValues: initialFormValues(schema.fields, values),\r\n\t\t\tonSubmit,\r\n\t\t\tvalidate: (form) => validateForm(schema, form),\r\n\t\t\t// only validate the entire form on submit\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t\tvalidateOnChange: false,\r\n\t\t})\r\n\t\tconst { dirty } = formik\r\n\r\n\t\tconst Title = useMemo(\r\n\t\t\t() => (typeof schema.title === \"string\" ? <Heading>{schema.title}</Heading> : schema.title),\r\n\t\t\t[schema.title],\r\n\t\t)\r\n\r\n\t\tconst Description = useMemo(\r\n\t\t\t() =>\r\n\t\t\t\ttypeof schema.description === \"string\" ? (\r\n\t\t\t\t\t<Text className={styles.description}>{schema.description}</Text>\r\n\t\t\t\t) : (\r\n\t\t\t\t\tschema.description\r\n\t\t\t\t),\r\n\t\t\t[schema.description],\r\n\t\t)\r\n\r\n\t\tconst inputs = useFieldInputs(schema.fields, { formId, disabled: readonly })\r\n\r\n\t\tuseEffect(() => {\r\n\t\t\tif (dirty && onDirty) onDirty()\r\n\t\t}, [dirty, onDirty])\r\n\r\n\t\treturn (\r\n\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t<Flex ref={ref} direction=\"column\" gap=\"2\" className={className} asChild>\r\n\t\t\t\t\t<form id={formId} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t\t{!hideTitle && (\r\n\t\t\t\t\t\t\t<Card>\r\n\t\t\t\t\t\t\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t\t\t\t\t\t\t{Title}\r\n\t\t\t\t\t\t\t\t\t{!hideDescription && Description}\r\n\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t</Card>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t{inputs}\r\n\t\t\t\t\t\t{!readonly && (\r\n\t\t\t\t\t\t\t<Flex justify=\"end\" gap=\"2\">\r\n\t\t\t\t\t\t\t\t{cancelText && (\r\n\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"soft\" onClick={onCancel}>\r\n\t\t\t\t\t\t\t\t\t\t{cancelText}\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t<Button type=\"submit\" disabled={!formik.isValid}>\r\n\t\t\t\t\t\t\t\t\t{submitText}\r\n\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</form>\r\n\t\t\t\t</Flex>\r\n\t\t\t</FormikProvider>\r\n\t\t)\r\n\t}),\r\n)\r\n","import { useMemo, memo, forwardRef } from \"react\"\r\nimport {\r\n\tOffline,\r\n\tselectFormRevision,\r\n\tuseAppSelector,\r\n\tUserFormSubmissionPayload,\r\n\tselectSubmissionAttachments,\r\n\tuseSDK,\r\n} from \"@overmap-ai/core\"\r\nimport { FormRenderer } from \"../FormRenderer/FormRenderer\"\r\nimport { formRevisionToSchema } from \"fields/utils\"\r\nimport { ISchema } from \"fields/typings\"\r\n\r\ninterface FormSubmissionViewerProps {\r\n\t/** The submission to render for viewing */\r\n\tsubmission: Offline<UserFormSubmissionPayload>\r\n\t/** @default false */\r\n\tshowFormDescription?: boolean\r\n\t/** @default true */\r\n\tshowFormTitle?: boolean\r\n}\r\n\r\n/**\r\n * Wrapper for `FormRenderer` that takes a `UserFormSubmissionPayload` instead of an `ISchema`.\r\n * Also, unlike `FormRenderer`, this component depends on the redux store.\r\n * @see FormRenderer\r\n */\r\nexport const FormSubmissionViewer = memo(\r\n\tforwardRef<HTMLDivElement, FormSubmissionViewerProps>((props, ref) => {\r\n\t\tconst { submission, showFormDescription = false, showFormTitle = true } = props\r\n\t\tconst revision = useAppSelector(selectFormRevision(submission.form_revision))\r\n\t\tconst { sdk } = useSDK()\r\n\r\n\t\tif (!revision) {\r\n\t\t\tthrow new Error(\r\n\t\t\t\t`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`,\r\n\t\t\t)\r\n\t\t}\r\n\t\tconst schema: ISchema = useMemo(() => {\r\n\t\t\treturn formRevisionToSchema(revision, { readonly: true })\r\n\t\t}, [revision])\r\n\r\n\t\tconst submissionValuesWithAttachments = useMemo(() => {\r\n\t\t\tconst attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? []\r\n\t\t\tconst downloadedAttachments: Record<string, Promise<File>[]> = {}\r\n\r\n\t\t\tfor (const attachment of attachments) {\r\n\t\t\t\tconst promise = sdk.files\r\n\t\t\t\t\t.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name)\r\n\t\t\t\t\t.then((response) => {\r\n\t\t\t\t\t\tif (!response.success) throw new Error(`Failed to download attachment ${attachment.file_name}.`)\r\n\t\t\t\t\t\treturn response.body\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\tconst fieldAttachments = downloadedAttachments[attachment.field_identifier]\r\n\t\t\t\tif (fieldAttachments) {\r\n\t\t\t\t\tfieldAttachments.push(promise)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdownloadedAttachments[attachment.field_identifier] = [promise]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn { ...submission.values, ...downloadedAttachments }\r\n\t\t}, [sdk.files, sdk.store, submission.offline_id, submission.values])\r\n\r\n\t\treturn (\r\n\t\t\t<FormRenderer\r\n\t\t\t\tref={ref}\r\n\t\t\t\tschema={schema}\r\n\t\t\t\tvalues={submissionValuesWithAttachments}\r\n\t\t\t\thideDescription={!showFormDescription}\r\n\t\t\t\thideTitle={!showFormTitle}\r\n\t\t\t/>\r\n\t\t)\r\n\t}),\r\n)\r\n","import {\r\n\tFlex,\r\n\tButtonList,\r\n\tText,\r\n\tIconButton,\r\n\tStarFilledIcon,\r\n\tStarIcon,\r\n\tTextField,\r\n\tdivButtonProps,\r\n\tTooltip,\r\n\tQuestionMarkCircledIcon,\r\n\tPersonIcon,\r\n\tSelect,\r\n\tBox,\r\n} from \"@overmap-ai/blocks\"\r\nimport {\r\n\tselectNumberOfUserForms,\r\n\tuseAppSelector,\r\n\tCachedUserForm,\r\n\tuseSDK,\r\n\tselectOrganization,\r\n\tselectUser,\r\n\tselectCurrentUser,\r\n\tselectUserFormMapping,\r\n\tselectFilteredUserForms,\r\n\ttype UserFormSearchArgs,\r\n\tclassNames,\r\n} from \"@overmap-ai/core\"\r\nimport { ChangeEventHandler, MouseEventHandler, forwardRef, memo, useCallback, useMemo, useState } from \"react\"\r\nimport styles from \"./FormBrowser.module.sass\"\r\n\r\ninterface FormBrowserProps {\r\n\t/** If `true`, the user can toggle the favorite state of the forms they have access to */\r\n\tisFavoriteEditable?: boolean\r\n\tonSelectForm: (form: CachedUserForm) => void\r\n\t/** @default 20 */\r\n\tmaxResults?: number\r\n}\r\n\r\n// there is one dropdown with both organizations and users as options\r\n// the value is prefixed with either \"organization:\" or \"user:\" to indicate which it is\r\n// this is done to avoid collisions between the two, as they are both integers\r\nconst orgOptionPrefix = \"organization:\"\r\nconst userOptionPrefix = \"user:\"\r\n\r\nexport const FormBrowser = memo(\r\n\tforwardRef<HTMLDivElement, FormBrowserProps>((props, ref) => {\r\n\t\tconst { maxResults = 20, ...entryProps } = props\r\n\t\tconst [filter, setFilter] = useState(\"\")\r\n\t\tconst [ownerFilter, setOwnerFilter] = useState(\"\")\r\n\t\tconst { sdk } = useSDK()\r\n\r\n\t\tconst ownerFilterOptions = useMemo(() => {\r\n\t\t\tconst ret: UserFormSearchArgs = { maxResults, searchTerm: filter }\r\n\r\n\t\t\tif (ownerFilter) {\r\n\t\t\t\tif (ownerFilter.startsWith(orgOptionPrefix)) {\r\n\t\t\t\t\tret.owner_organization = parseInt(ownerFilter.slice(orgOptionPrefix.length))\r\n\t\t\t\t} else if (ownerFilter.startsWith(userOptionPrefix)) {\r\n\t\t\t\t\tret.owner_user = parseInt(ownerFilter.slice(userOptionPrefix.length))\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn ret\r\n\t\t}, [filter, maxResults, ownerFilter])\r\n\t\tconst userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? []\r\n\r\n\t\tconst userFormMapping = useAppSelector(selectUserFormMapping)\r\n\r\n\t\tconst handleToggleFavorite = useCallback(\r\n\t\t\t(form: CachedUserForm) => {\r\n\t\t\t\tif (form.favorite) {\r\n\t\t\t\t\tsdk.userForms.unfavorite(form.offline_id).then()\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsdk.userForms.favorite(form.offline_id).then()\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[sdk],\r\n\t\t)\r\n\r\n\t\tconst options = useMemo(() => {\r\n\t\t\tconst state = sdk.store.getState()\r\n\r\n\t\t\t// value to label mapping\r\n\t\t\tconst accumulator: Record<string, string> = {}\r\n\r\n\t\t\tfor (const form of Object.values(userFormMapping)) {\r\n\t\t\t\tconst organization = selectOrganization(form.owner_organization || -1)(state)\r\n\t\t\t\tif (organization) {\r\n\t\t\t\t\taccumulator[`${orgOptionPrefix}${organization.id}`] = organization.name\r\n\t\t\t\t}\r\n\t\t\t\tconst user = selectUser(form.owner_user || -1)(state)\r\n\r\n\t\t\t\tif (user) {\r\n\t\t\t\t\taccumulator[`${userOptionPrefix}${user.id}`] = user.username\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn Object.entries(accumulator).map(([value, label]) => ({ itemContent: label, value }))\r\n\t\t}, [userFormMapping, sdk.store])\r\n\r\n\t\tconst handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>((e) => {\r\n\t\t\tsetFilter(e.currentTarget.value)\r\n\t\t}, [])\r\n\r\n\t\tconst numberOfForms = useAppSelector(selectNumberOfUserForms) || 0\r\n\t\tconst numberOfHiddenForms = numberOfForms - userForms.length\r\n\t\tconst overflowMessage =\r\n\t\t\tuserForms.length == maxResults && numberOfHiddenForms > 0\r\n\t\t\t\t? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)`\r\n\t\t\t\t: numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`\r\n\r\n\t\treturn (\r\n\t\t\t<Flex ref={ref} direction=\"column\" gap=\"2\">\r\n\t\t\t\t<Flex gap=\"2\" grow=\"1\">\r\n\t\t\t\t\t<Box grow=\"1\" asChild>\r\n\t\t\t\t\t\t<TextField.Root size=\"3\">\r\n\t\t\t\t\t\t\t<TextField.Input placeholder=\"Filter\" value={filter} onChange={handleChange} />\r\n\t\t\t\t\t\t</TextField.Root>\r\n\t\t\t\t\t</Box>\r\n\t\t\t\t\t<Select\r\n\t\t\t\t\t\titems={options}\r\n\t\t\t\t\t\tvalue={ownerFilter}\r\n\t\t\t\t\t\tonValueChange={setOwnerFilter}\r\n\t\t\t\t\t\tplaceholder=\"Owner\"\r\n\t\t\t\t\t\tsize=\"large\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{userForms.length > 0 && (\r\n\t\t\t\t\t<ButtonList.Root>\r\n\t\t\t\t\t\t{userForms.map((form) => (\r\n\t\t\t\t\t\t\t<FormBrowserEntry\r\n\t\t\t\t\t\t\t\tkey={form.offline_id}\r\n\t\t\t\t\t\t\t\t{...entryProps}\r\n\t\t\t\t\t\t\t\tform={form}\r\n\t\t\t\t\t\t\t\thandleToggleFavorite={() => handleToggleFavorite(form)}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t</ButtonList.Root>\r\n\t\t\t\t)}\r\n\t\t\t\t<Box px=\"3\">\r\n\t\t\t\t\t<Text size=\"2\" severity=\"info\">\r\n\t\t\t\t\t\t{overflowMessage}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Box>\r\n\t\t\t</Flex>\r\n\t\t)\r\n\t}),\r\n)\r\n\r\ninterface FormBrowserEntryProps extends Omit<FormBrowserProps, \"maxResults\"> {\r\n\tform: CachedUserForm\r\n\thandleToggleFavorite: () => void\r\n}\r\n\r\nconst FormBrowserEntry = (props: FormBrowserEntryProps) => {\r\n\tconst { form, onSelectForm, isFavoriteEditable, handleToggleFavorite } = props\r\n\tconst ownerOrganization = useAppSelector(selectOrganization(form.owner_organization || -1))?.name\r\n\tconst ownerUser = useAppSelector(selectUser(form.owner_user || -1))\r\n\tconst currentUserId = useAppSelector(selectCurrentUser).id\r\n\tconst ownedByCurrentUser = !!ownerUser && ownerUser.id === currentUserId\r\n\tconst owner = ownerOrganization ?? (ownedByCurrentUser ? \"You\" : ownerUser?.username) ?? \"Unknown\"\r\n\r\n\tconst handleFavoriteClick = useCallback<MouseEventHandler<HTMLButtonElement>>(\r\n\t\t(e) => {\r\n\t\t\te.stopPropagation()\r\n\t\t\thandleToggleFavorite()\r\n\t\t},\r\n\t\t[handleToggleFavorite],\r\n\t)\r\n\r\n\tconst ret = (\r\n\t\t<ButtonList.Item onClick={() => onSelectForm(form)} asChild>\r\n\t\t\t<Flex justify=\"between\" gap=\"2\" py=\"2\" px=\"3\" {...divButtonProps}>\r\n\t\t\t\t<Flex grow=\"1\" align=\"center\" gap=\"2\">\r\n\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\tclassName={classNames(form.favorite ? styles.favoriteIcon : styles.regularIcon)}\r\n\t\t\t\t\t\tvariant=\"ghost\"\r\n\t\t\t\t\t\tonClick={handleFavoriteClick}\r\n\t\t\t\t\t\taria-label={form.favorite ? \"Favorite form\" : \"Standard form\"}\r\n\t\t\t\t\t\tdisabled={!isFavoriteEditable}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{form.favorite ? <StarFilledIcon /> : <StarIcon />}\r\n\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t<Text noWrap>{form.latestRevision.title}</Text>\r\n\t\t\t\t\t{form.latestRevision.description && <QuestionMarkCircledIcon />}\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{owner && (\r\n\t\t\t\t\t<Flex align=\"center\" gap=\"2\">\r\n\t\t\t\t\t\t<PersonIcon /> {owner}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t)}\r\n\t\t\t</Flex>\r\n\t\t</ButtonList.Item>\r\n\t)\r\n\r\n\t// wrap the button in a tooltip if there is a description\r\n\tif (form.latestRevision.description) {\r\n\t\treturn (\r\n\t\t\t<Tooltip key={form.offline_id} content={form.latestRevision.description}>\r\n\t\t\t\t{ret}\r\n\t\t\t</Tooltip>\r\n\t\t)\r\n\t}\r\n\r\n\treturn ret\r\n}\r\n","import React, { ReactNode, memo, useMemo } from \"react\"\r\nimport styles from \"./FormSubmissionBrowser.module.sass\"\r\nimport {\r\n\tOffline,\r\n\tselectCurrentUser,\r\n\tselectFormRevision,\r\n\tselectLatestFormRevision,\r\n\tselectSubmissionsForForm,\r\n\tselectUser,\r\n\tuseAppSelector,\r\n\tUserFormSubmission,\r\n\tUserFormSubmissionPayload,\r\n\tgetLocalDateString,\r\n\tisToday,\r\n\tuseFileSrc,\r\n\tclassNames,\r\n} from \"@overmap-ai/core\"\r\nimport { Badge, Flex, Text, ButtonList, Avatar } from \"@overmap-ai/blocks\"\r\n\r\nexport type FormSubmissionClickEvent = {\r\n\tsubmission: Offline<UserFormSubmissionPayload>\r\n}\r\n\r\ninterface UserFormSubmissionBrowserEntryProps {\r\n\tsubmission: Offline<UserFormSubmissionPayload> | UserFormSubmission\r\n\tonSubmissionClick?: (e: FormSubmissionClickEvent) => void\r\n\trowDecorator?: (submission: Offline<UserFormSubmissionPayload> | UserFormSubmission, Row: ReactNode) => ReactNode\r\n\tcompact: boolean\r\n\tlabelType: \"creator\" | \"formName\"\r\n}\r\n\r\nconst FormSubmissionBrowserEntry = memo(function FormSubmissionBrowserEntry(\r\n\tprops: UserFormSubmissionBrowserEntryProps,\r\n) {\r\n\tconst { submission, onSubmissionClick, compact, labelType, rowDecorator } = props\r\n\tconst currentUser = useAppSelector(selectCurrentUser)\r\n\tconst createdBy = useAppSelector(selectUser(\"created_by\" in submission ? submission.created_by : currentUser.id))\r\n\tconst dateToUse = getCreatedAtOrSubmittedAtDate(submission)\r\n\tconst formattedDateTime = isToday(dateToUse)\r\n\t\t? dateToUse.toLocaleTimeString([], {\r\n\t\t\t\thour: \"2-digit\",\r\n\t\t\t\tminute: \"2-digit\",\r\n\t\t })\r\n\t\t: getLocalDateString(dateToUse)\r\n\tconst revision = useAppSelector(selectFormRevision(submission.form_revision))\r\n\tif (!revision) {\r\n\t\tthrow new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`)\r\n\t}\r\n\tconst latestRevisionNumber = useAppSelector(selectLatestFormRevision(revision.form))?.revision\r\n\tconst creatorProfileSrc = useFileSrc({\r\n\t\tfile: createdBy?.profile.file ?? null,\r\n\t\tfileSha1: createdBy?.profile.file_sha1 ?? null,\r\n\t})\r\n\tconst creatorProfileFallback = createdBy?.username.charAt(0).toUpperCase() ?? \"?\"\r\n\r\n\tconst isLatestRevision = revision.revision === latestRevisionNumber\r\n\r\n\tconst handleClick = React.useCallback(() => {\r\n\t\tif (onSubmissionClick) {\r\n\t\t\tonSubmissionClick({ submission })\r\n\t\t}\r\n\t}, [submission, onSubmissionClick])\r\n\r\n\tconst row = (\r\n\t\t<ButtonList.Item onClick={handleClick} asChild>\r\n\t\t\t<Flex grow=\"1\" width=\"100%\" p=\"2\" gap=\"2\" justify=\"between\">\r\n\t\t\t\t<Flex gap=\"2\" align=\"center\" className={styles.stopHorizontalOverflow}>\r\n\t\t\t\t\t<Avatar src={creatorProfileSrc} size=\"1\" fallback={creatorProfileFallback} />\r\n\t\t\t\t\t<Text size=\"2\" noWrap>\r\n\t\t\t\t\t\t{labelType === \"creator\" ? (createdBy || currentUser).username : revision.title}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t<Flex gap=\"2\" align=\"center\">\r\n\t\t\t\t\t{!compact &&\r\n\t\t\t\t\t\t(revision.revision ? (\r\n\t\t\t\t\t\t\t<Badge variant=\"soft\" severity={isLatestRevision ? \"primary\" : \"info\"}>\r\n\t\t\t\t\t\t\t\t{compact ? revision.revision.toString() : `Revision #${revision.revision}`}\r\n\t\t\t\t\t\t\t</Badge>\r\n\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t!!latestRevisionNumber && <Badge>Original</Badge>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t<Text size=\"2\" noWrap>\r\n\t\t\t\t\t\t{formattedDateTime}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Flex>\r\n\t\t\t</Flex>\r\n\t\t</ButtonList.Item>\r\n\t)\r\n\r\n\tif (rowDecorator) {\r\n\t\treturn rowDecorator(submission, row)\r\n\t}\r\n\r\n\treturn row\r\n})\r\n\r\ninterface FormSubmissionBrowserProps {\r\n\t// If not set, `submissions` must be provided.\r\n\tformId?: string\r\n\t// If not provided, `formId` is expected, and all submissions of that form will be displayed.\r\n\tsubmissions?: (Offline<UserFormSubmissionPayload> | UserFormSubmission)[]\r\n\tonSubmissionClick?: (e: FormSubmissionClickEvent) => void\r\n\trowDecorator?: UserFormSubmissionBrowserEntryProps[\"rowDecorator\"]\r\n\t/** @default false */\r\n\tcompact?: boolean\r\n\tlabelType: \"creator\" | \"formName\"\r\n\tclassName?: string\r\n\t/** @default outline */\r\n\tvariant?: \"ghost\" | \"outline\"\r\n\t/** Content displayed within the container but after the list */\r\n\tafter?: ReactNode\r\n}\r\n\r\n// UserFOrmSubmission objects have a \"created_at\" field, but UserFormSubmissionPayload objects have a \"submitted_at\"\r\n// field. We use the \"created_at\" field if it exists, otherwise we use the \"submitted_at\" field. Unless someone\r\n// decides to hack the payload to bring their own submissions to the top by spoofing the `submitted_at` field, this\r\n// should be fine and allows a real life timeline instead of one that's based on internet access.\r\nconst getCreatedAtOrSubmittedAtDate = (submission: UserFormSubmissionPayload | UserFormSubmission) => {\r\n\tconst date = \"created_at\" in submission ? submission.created_at : submission.submitted_at\r\n\treturn new Date(date)\r\n}\r\n\r\nexport const FormSubmissionBrowser = memo(function FormSubmissionBrowser(props: FormSubmissionBrowserProps) {\r\n\tconst {\r\n\t\tformId,\r\n\t\tsubmissions: propSubmissions,\r\n\t\tcompact = false,\r\n\t\tclassName,\r\n\t\tafter,\r\n\t\tvariant = \"outline\",\r\n\t\t...submissionEntryProps\r\n\t} = props\r\n\tif (!!formId === !!propSubmissions) {\r\n\t\tthrow new Error(\"Either formId or submissions must be provided, but not both.\")\r\n\t}\r\n\tconst submissions = useAppSelector(\r\n\t\tpropSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId as string),\r\n\t)\r\n\tconst sortedSubmissions = useMemo(\r\n\t\t() =>\r\n\t\t\tsubmissions?.sort((a, b) => {\r\n\t\t\t\treturn getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime()\r\n\t\t\t}),\r\n\t\t[submissions],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<ButtonList.Root\r\n\t\t\tclassName={classNames(styles.submissionsContainer, className)}\r\n\t\t\tsize=\"small\"\r\n\t\t\tvariant={variant}\r\n\t\t\tbefore={\r\n\t\t\t\t!compact && (\r\n\t\t\t\t\t<Text severity=\"info\">\r\n\t\t\t\t\t\tThere are {(submissions?.length || 0).toString()} submissions of this form.\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t)\r\n\t\t\t}\r\n\t\t\tafter={after}\r\n\t\t>\r\n\t\t\t{sortedSubmissions?.map((submission, index) => {\r\n\t\t\t\treturn (\r\n\t\t\t\t\t<FormSubmissionBrowserEntry\r\n\t\t\t\t\t\tkey={index}\r\n\t\t\t\t\t\tsubmission={submission}\r\n\t\t\t\t\t\tcompact={compact}\r\n\t\t\t\t\t\t{...submissionEntryProps}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)\r\n\t\t\t})}\r\n\t\t</ButtonList.Root>\r\n\t)\r\n})\r\n","import { ReactNode, memo, useMemo } from \"react\"\r\nimport { FieldValue } from \"@overmap-ai/core\"\r\nimport { useField, useFormikContext } from \"formik\"\r\n\r\ninterface RenderArgs {\r\n\tvalue: FieldValue\r\n\t/** Intermediate changes to the field value */\r\n\tsetValue: (value: FieldValue) => void\r\n\t/** EX: when the onBlur event is fired */\r\n\tpatchValue: () => void\r\n}\r\n\r\ninterface PatchFieldProps {\r\n\tname: string\r\n\trender: (args: RenderArgs) => ReactNode\r\n}\r\n\r\nexport const PatchField = memo(function PatchField(props: PatchFieldProps) {\r\n\tconst { name, render } = props\r\n\tconst { submitForm } = useFormikContext()\r\n\tconst [fieldProps, _meta, helpers] = useField(name)\r\n\r\n\treturn useMemo(() => {\r\n\t\tconst setValue = (value: FieldValue) => helpers.setValue(value, false)\r\n\t\treturn render({\r\n\t\t\tvalue: fieldProps.value,\r\n\t\t\tsetValue,\r\n\t\t\tpatchValue: submitForm,\r\n\t\t})\r\n\t}, [submitForm, helpers, fieldProps.value, render])\r\n})\r\n","import { ISchema } from \"fields\"\r\nimport { FormikErrors, FormikProvider, useFormik } from \"formik\"\r\nimport { forwardRef, memo, useCallback, useEffect, useMemo } from \"react\"\r\nimport { Form } from \"typings\"\r\nimport { hasKeys, initialFormValues, validateForm } from \"utils\"\r\n\r\ninterface PatchFormProviderProps {\r\n\tchildren: React.ReactNode\r\n\tschema: ISchema\r\n\tvalues: Form\r\n\t/** Called when `patchValue` is called on a child `PatchField` and the form is valid.\r\n\t * @example ```js\r\n\t * {\"field name\": \"field value\"}\r\n\t * ``` */\r\n\tonPatch: (values: Form) => void\r\n\t/** Called when `patchValue` is called on a child `PatchField` and the form is not valid.\r\n\t * After this event is fired, the form is reset to the initial values.\r\n\t * @example ```js\r\n\t * {\"field name\": \"error message\"}\r\n\t * ``` */\r\n\tonError: (error: FormikErrors<Form>) => void\r\n\tclassName?: string\r\n}\r\n\r\n/** Use PatchForms to create patch edits to existing forms rather than editing the entire form. */\r\nexport const PatchFormProvider = memo(\r\n\tforwardRef<HTMLFormElement, PatchFormProviderProps>((props, ref) => {\r\n\t\tconst { children, schema, values, onPatch, onError, ...rest } = props\r\n\r\n\t\tconst initialValues = useMemo(() => initialFormValues(schema.fields, values), [schema.fields, values])\r\n\r\n\t\tconst handlePatch = useCallback(\r\n\t\t\t(values: Form) => {\r\n\t\t\t\tconst diff: Form = {}\r\n\r\n\t\t\t\tfor (const key in values) {\r\n\t\t\t\t\tconst value = values[key]\r\n\t\t\t\t\tif (value !== initialValues[key] && value !== undefined) {\r\n\t\t\t\t\t\tdiff[key] = value\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// skip if no changes\r\n\t\t\t\tif (!hasKeys(diff)) return\r\n\r\n\t\t\t\tonPatch(diff)\r\n\t\t\t},\r\n\t\t\t[initialValues, onPatch],\r\n\t\t)\r\n\r\n\t\tconst validate = useCallback(\r\n\t\t\tasync (form: Form) => {\r\n\t\t\t\tconst error = await validateForm(schema, form)\r\n\r\n\t\t\t\tif (error) {\r\n\t\t\t\t\t// report the error\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn error\r\n\t\t\t},\r\n\t\t\t[schema, onError],\r\n\t\t)\r\n\r\n\t\tconst formik = useFormik<Form>({\r\n\t\t\tinitialValues,\r\n\t\t\tonSubmit: handlePatch,\r\n\t\t\tvalidate,\r\n\t\t\t// only validate the entire form on submit\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t\tvalidateOnChange: false,\r\n\t\t})\r\n\r\n\t\tconst { errors, resetForm } = formik\r\n\r\n\t\tuseEffect(() => {\r\n\t\t\t// on errors, reset the form the the initial values\r\n\t\t\tif (hasKeys(errors)) {\r\n\t\t\t\tresetForm({ values: initialValues, errors: {} })\r\n\t\t\t}\r\n\t\t}, [errors, initialValues, resetForm])\r\n\r\n\t\treturn (\r\n\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t{/* the `form` captures any submit events that are generated */}\r\n\t\t\t\t<form {...rest} ref={ref} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t{children}\r\n\t\t\t\t</form>\r\n\t\t\t</FormikProvider>\r\n\t\t)\r\n\t}),\r\n)\r\n","import { FormikUserFormRevision, NestedFieldPath } from \"./typings\"\r\nimport { FC, ReactNode, memo, useCallback, useMemo, useState } from \"react\"\r\nimport { FieldTypeToClsMapping } from \"fields/constants\"\r\nimport { AnyField, ISchema } from \"fields/typings\"\r\nimport { FieldTypeIdentifier, ISerializedField, SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { Button, Dialog, Flex, Separator, Text } from \"@overmap-ai/blocks\"\r\nimport { FormRenderer } from \"renderer\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { BooleanField, deserialize, StringField, TextField } from \"fields\"\r\nimport { Form } from \"typings\"\r\nimport { insert, makeIdentifier, replace, getTakenFieldLabels } from \"./utils\"\r\nimport { BaseField, BaseFormElement } from \"../fields/BaseField\"\r\nimport { FieldSection } from \"../fields\"\r\nimport get from \"lodash.get\"\r\n\r\ninterface ChooseFieldToAddProps {\r\n\tsetFieldType: (id: FieldTypeIdentifier) => void\r\n}\r\n\r\ninterface FieldToChooseProps extends ChooseFieldToAddProps {\r\n\tfield: (typeof CompleteFieldTypeToClsMapping)[(typeof fieldsToChoose)[number][number]]\r\n\tsetFieldType: () => void\r\n}\r\n\r\nconst CompleteFieldTypeToClsMapping = {\r\n\t...FieldTypeToClsMapping,\r\n\tsection: FieldSection,\r\n}\r\n\r\nconst FieldToChoose = memo(function FieldToChoose(props: FieldToChooseProps) {\r\n\tconst { field, setFieldType } = props\r\n\r\n\tconst typeName = field.fieldTypeName\r\n\tconst description = field.fieldTypeDescription\r\n\tconst Icon = field.Icon\r\n\treturn (\r\n\t\t<Flex gap=\"4\" align=\"center\">\r\n\t\t\t<Button type=\"button\" variant=\"surface\" onClick={setFieldType} style={{ width: \"135px\" }}>\r\n\t\t\t\t<Flex gap=\"3\" align=\"center\" grow=\"1\">\r\n\t\t\t\t\t<Icon />\r\n\t\t\t\t\t{typeName}\r\n\t\t\t\t</Flex>\r\n\t\t\t</Button>\r\n\t\t\t<Text>{description}</Text>\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\nconst fieldsToChoose = [\r\n\t[\"string\", \"text\"],\r\n\t[\"select\", \"multi-select\", \"upload\"],\r\n\t[\"boolean\", \"date\", \"number\", \"multi-string\"],\r\n] satisfies FieldTypeIdentifier[][]\r\nconst indexOfLastFieldGroup = fieldsToChoose.length - 1\r\n\r\nconst ChooseFieldToAdd = memo(function ChooseFieldToAdd(props: ChooseFieldToAddProps) {\r\n\tconst { setFieldType } = props\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"3\">\r\n\t\t\t{fieldsToChoose.map((fieldGroup, index) => (\r\n\t\t\t\t<Flex key={index} direction=\"column\" gap=\"3\">\r\n\t\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t\t{fieldGroup.map((identifier) => (\r\n\t\t\t\t\t\t\t<FieldToChoose\r\n\t\t\t\t\t\t\t\tkey={identifier}\r\n\t\t\t\t\t\t\t\tfield={FieldTypeToClsMapping[identifier]}\r\n\t\t\t\t\t\t\t\tsetFieldType={() => setFieldType(identifier)}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t\t{index < indexOfLastFieldGroup && <Separator size=\"4\" />}\r\n\t\t\t\t</Flex>\r\n\t\t\t))}\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\ninterface FieldOptionsFormProps {\r\n\tdefaultField?: ISerializedField\r\n\tfieldType: FieldTypeIdentifier\r\n\t/** fields that can be used as a condition */\r\n\tconditionalSourceFields?: ISerializedField[]\r\n\thandleCancel: () => void\r\n\thandleCreateField: (form: Form) => void\r\n}\r\n\r\nconst validateNewFieldName = (takenLabels: string[]) => {\r\n\treturn (value: unknown) => {\r\n\t\tif (!value || typeof value !== \"string\") return\r\n\r\n\t\tif (takenLabels.includes(value.trim())) {\r\n\t\t\treturn \"This name is already taken.\"\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/** Creates the common field at the beginning of each field creation schema.\r\n *\r\n * Note: this is not in the BaseField class due to circular dependencies.\r\n */\r\nconst commonFields = (takenLabels: string[], type: FieldTypeIdentifier): AnyField[] => {\r\n\tconst base = [\r\n\t\tnew StringField({\r\n\t\t\tlabel: \"Label\",\r\n\t\t\trequired: true,\r\n\t\t\tmaxLength: 200,\r\n\t\t\tidentifier: \"label\",\r\n\t\t\tfieldValidators: [validateNewFieldName(takenLabels)],\r\n\t\t}),\r\n\t\tnew TextField({\r\n\t\t\tlabel: \"Description\",\r\n\t\t\trequired: false,\r\n\t\t\tmaxLength: 1000,\r\n\t\t\tidentifier: \"description\",\r\n\t\t}),\r\n\t]\r\n\r\n\t// sections do not have a required field\r\n\tif (type === \"section\") return base\r\n\r\n\treturn [\r\n\t\t...base,\r\n\t\tnew BooleanField({ label: \"Required\", description: null, required: false, identifier: \"required\" }),\r\n\t]\r\n}\r\n\r\nconst FieldOptionsForm = memo(function FieldOptionsForm(props: FieldOptionsFormProps) {\r\n\tconst { fieldType, handleCancel, handleCreateField, defaultField, conditionalSourceFields } = props\r\n\tconst fieldCls = CompleteFieldTypeToClsMapping[fieldType]\r\n\tconst formik = useFormikContext<FormikUserFormRevision>()\r\n\r\n\tconst schema: ISchema = useMemo(() => {\r\n\t\tconst takenFieldLabels = getTakenFieldLabels(formik.values.fields)\r\n\t\t\t// when editing a field, we want to allow the user to keep the same label\r\n\t\t\t.filter((id) => id !== defaultField?.label)\r\n\r\n\t\tlet fields: BaseFormElement[] = commonFields(takenFieldLabels, fieldType)\r\n\t\tif (fieldCls === FieldSection) {\r\n\t\t\tif (conditionalSourceFields === undefined) {\r\n\t\t\t\tthrow new Error(\"Conditional source fields must be provided when changing sections.\")\r\n\t\t\t}\r\n\t\t\tfields = fields.concat(fieldCls.getFieldCreationSchema(conditionalSourceFields))\r\n\t\t} else {\r\n\t\t\tif (!(fieldCls.prototype instanceof BaseField)) {\r\n\t\t\t\tthrow new Error(`Field must be an instance of BaseField. Got ${fieldCls}.`)\r\n\t\t\t}\r\n\r\n\t\t\t// We now know that this is not a FieldSection. We need to tell TypeScript that.\r\n\t\t\ttype FieldClass = Exclude<typeof fieldCls, typeof FieldSection>\r\n\t\t\tfields = [...fields, ...(fieldCls as FieldClass).getFieldCreationSchema()]\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tfields,\r\n\t\t\tmeta: { readonly: false },\r\n\t\t\t// using the dialog title as the form title\r\n\t\t\ttitle: null,\r\n\t\t}\r\n\t}, [formik.values.fields, fieldType, fieldCls, defaultField?.label, conditionalSourceFields])\r\n\r\n\treturn (\r\n\t\t<FormRenderer\r\n\t\t\tschema={schema}\r\n\t\t\tvalues={defaultField as Form | undefined}\r\n\t\t\tonSubmit={handleCreateField}\r\n\t\t\t// only show cancel button if we are creating a new field, not editing an existing one\r\n\t\t\tcancelText={defaultField ? undefined : \"Back\"}\r\n\t\t\tonCancel={handleCancel}\r\n\t\t/>\r\n\t)\r\n})\r\n\r\ninterface FieldBuilderProps extends Pick<FieldOptionsFormProps, \"conditionalSourceFields\"> {\r\n\tindex: number\r\n\tparentPath: NestedFieldPath\r\n\tinitial?: ISerializedField\r\n\tediting?: boolean\r\n\tchildren: ReactNode\r\n}\r\n\r\nexport type FieldBuilderArgs = Omit<FieldBuilderProps, \"children\">\r\n\r\nexport const FieldBuilder: FC<FieldBuilderProps> = memo(function FieldBuilder(props: FieldBuilderProps) {\r\n\tconst { parentPath, index, children, initial, editing, conditionalSourceFields } = props\r\n\tconst [fieldType, setFieldType] = useState<FieldTypeIdentifier>()\r\n\tconst type = initial?.type ?? fieldType\r\n\tconst typeName = type ? CompleteFieldTypeToClsMapping[type].fieldTypeName : undefined\r\n\tconst { setFieldValue, values } = useFormikContext<FormikUserFormRevision>()\r\n\r\n\tif (editing && !initial) throw new Error(\"Initial field must be provided if editing is true.\")\r\n\r\n\tconst showChooseField = !type && !editing && !initial\r\n\tconst title = showChooseField ? \"Choose a field type\" : `${typeName} settings`\r\n\r\n\tconst description = showChooseField\r\n\t\t? \"Select a field type to add to this section.\"\r\n\t\t: typeName?.toLowerCase() === \"section\"\r\n\t\t? \"Customize your section\"\r\n\t\t: `Customize your ${typeName?.toLowerCase()} field.`\r\n\r\n\tconst handleCancel = useCallback(() => setFieldType(undefined), [])\r\n\r\n\tconst handleCloseInterrupt = useCallback((confirmClose: () => void) => {\r\n\t\t// reset field type\r\n\t\tsetFieldType(undefined)\r\n\t\tconfirmClose()\r\n\t}, [])\r\n\r\n\tconst handleCreateField = useCallback(\r\n\t\t(form: Form, closeDialog: () => void) => {\r\n\t\t\tconst { label } = form\r\n\t\t\tif (!type) throw new Error(\"Field type must be selected before creating a field.\")\r\n\t\t\tif (!label || typeof label !== \"string\") throw new Error(\"Label must be provided before creating a field.\")\r\n\r\n\t\t\t// maintain the same identifier if we are editing an existing field\r\n\t\t\t// so that conditional pointers are not broken\r\n\t\t\tconst field = deserialize({\r\n\t\t\t\ttype,\r\n\t\t\t\t...form,\r\n\t\t\t\tidentifier: makeIdentifier(form.identifier, label),\r\n\t\t\t} as ISerializedField).serialize()\r\n\r\n\t\t\tconst parent: SerializedFieldSection[] | undefined = get(values, parentPath)\r\n\r\n\t\t\tif (parent === undefined) {\r\n\t\t\t\tthrow new Error(\"Parent path must point to an existing field.\")\r\n\t\t\t}\r\n\r\n\t\t\tlet newFields\r\n\r\n\t\t\tif (!Array.isArray(parent)) throw new Error(\"Parent path must point to an array.\")\r\n\r\n\t\t\tif (editing) {\r\n\t\t\t\t// replace existing field\r\n\t\t\t\tnewFields = replace(parent, index, field)\r\n\t\t\t} else {\r\n\t\t\t\t// insert new field\r\n\t\t\t\tnewFields = insert(parent, index, field)\r\n\t\t\t}\r\n\r\n\t\t\tsetFieldValue(parentPath, newFields).then()\r\n\t\t\tcloseDialog()\r\n\t\t},\r\n\t\t[editing, type, values, parentPath, setFieldValue, index],\r\n\t)\r\n\r\n\tconst dialogContent = useCallback(\r\n\t\t(closeDialog: () => void) => {\r\n\t\t\tif (showChooseField) {\r\n\t\t\t\treturn <ChooseFieldToAdd setFieldType={setFieldType} />\r\n\t\t\t}\r\n\t\t\treturn (\r\n\t\t\t\t<FieldOptionsForm\r\n\t\t\t\t\tconditionalSourceFields={conditionalSourceFields}\r\n\t\t\t\t\thandleCancel={handleCancel}\r\n\t\t\t\t\thandleCreateField={(form) => handleCreateField(form, closeDialog)}\r\n\t\t\t\t\tfieldType={type as FieldTypeIdentifier}\r\n\t\t\t\t\tdefaultField={initial}\r\n\t\t\t\t/>\r\n\t\t\t)\r\n\t\t},\r\n\t\t[conditionalSourceFields, handleCancel, handleCreateField, initial, showChooseField, type],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<Dialog onCloseInterrupt={handleCloseInterrupt} title={title} description={description} content={dialogContent}>\r\n\t\t\t{children}\r\n\t\t</Dialog>\r\n\t)\r\n})\r\n","import { DropdownMenuItemProps, IconButton } from \"@overmap-ai/blocks\"\r\nimport { Pencil1Icon, TrashIcon, PlusIcon, DragHandleDots2Icon, DotsVerticalIcon, CopyIcon } from \"@overmap-ai/blocks\"\r\nimport { Flex, DropdownMenu, Box, Responsive } from \"@overmap-ai/blocks\"\r\nimport { FC, PropsWithChildren, ReactNode, memo, useMemo } from \"react\"\r\nimport { DraggableProvidedDragHandleProps } from \"@hello-pangea/dnd\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\n\r\ninterface FieldActionsProps {\r\n\tremove: () => void\r\n\tdragHandleProps: DraggableProvidedDragHandleProps | null | undefined\r\n\teditProps: FieldBuilderArgs\r\n\tinsertAfterProps: FieldBuilderArgs\r\n\tduplicateProps: FieldBuilderArgs\r\n}\r\n\r\nconst DefaultWrapper: FC<{ children: ReactNode }> = ({ children }) => <>{children}</>\r\n\r\nconst forMobile = <D extends \"block\" | \"flex\">(mobile: boolean, display: D): Responsive<D | \"none\"> => ({\r\n\tinitial: mobile ? display : \"none\",\r\n\tsm: mobile ? \"none\" : display,\r\n})\r\n\r\nexport const FieldActions = memo(function FieldActions(props: FieldActionsProps) {\r\n\tconst { remove, dragHandleProps, editProps, insertAfterProps, duplicateProps } = props\r\n\r\n\tconst actions = useMemo(\r\n\t\t() => [\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: editProps,\r\n\t\t\t\tIcon: Pencil1Icon,\r\n\t\t\t\ttext: \"Edit\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tIcon: TrashIcon,\r\n\t\t\t\tbuttonProps: {\r\n\t\t\t\t\tonClick: remove,\r\n\t\t\t\t},\r\n\t\t\t\ttext: \"Delete\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: duplicateProps,\r\n\t\t\t\tIcon: CopyIcon,\r\n\t\t\t\ttext: \"Duplicate\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: insertAfterProps,\r\n\t\t\t\tIcon: PlusIcon,\r\n\t\t\t\ttext: \"Add after\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\t// Wrapping icon in a div so that the asChild turns the button into a div\r\n\t\t\t\t// so that the drag handle props are not applied to the icon\r\n\t\t\t\t// Note: b/c the <button> does not handle the space-press event correctly\r\n\t\t\t\tIcon: (props: PropsWithChildren) => (\r\n\t\t\t\t\t<div {...props}>\r\n\t\t\t\t\t\t<DragHandleDots2Icon />\r\n\t\t\t\t\t</div>\r\n\t\t\t\t),\r\n\t\t\t\ttext: \"Reorder\",\r\n\t\t\t\tdisableOnMobile: true,\r\n\t\t\t\tbuttonProps: { ...dragHandleProps, asChild: true },\r\n\t\t\t},\r\n\t\t],\r\n\t\t[dragHandleProps, duplicateProps, editProps, insertAfterProps, remove],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t{/* For tablet and up */}\r\n\t\t\t<Flex gap=\"4\" display={forMobile(false, \"flex\")}>\r\n\t\t\t\t{actions.map((Action) => {\r\n\t\t\t\t\tconst Wrapper = Action.Wrapper ?? DefaultWrapper\r\n\t\t\t\t\treturn (\r\n\t\t\t\t\t\t<Wrapper key={Action.text} {...(Action.wrapperProps as FieldBuilderArgs)}>\r\n\t\t\t\t\t\t\t<IconButton type=\"button\" variant=\"ghost\" aria-label={Action.text} {...Action.buttonProps}>\r\n\t\t\t\t\t\t\t\t<Action.Icon />\r\n\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t</Wrapper>\r\n\t\t\t\t\t)\r\n\t\t\t\t})}\r\n\t\t\t</Flex>\r\n\t\t\t{/* For mobile devices */}\r\n\t\t\t<Box display={forMobile(true, \"block\")}>\r\n\t\t\t\t<DropdownMenu\r\n\t\t\t\t\ttrigger={\r\n\t\t\t\t\t\t<IconButton variant=\"ghost\" aria-label=\"Actions menu\">\r\n\t\t\t\t\t\t\t<DotsVerticalIcon />\r\n\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// TODO: close on select when we can wrap the menu item in a FieldBuilder (via Wrapper)\r\n\t\t\t\t\tcloseOnSelect={false}\r\n\t\t\t\t\titems={actions\r\n\t\t\t\t\t\t.map((Action): DropdownMenuItemProps | null => {\r\n\t\t\t\t\t\t\tif (Action.disableOnMobile) return null\r\n\r\n\t\t\t\t\t\t\tconst Wrapper = Action.Wrapper ?? DefaultWrapper\r\n\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t...Action.buttonProps,\r\n\t\t\t\t\t\t\t\tonSelect: Action.buttonProps?.onClick,\r\n\t\t\t\t\t\t\t\tcontent: (\r\n\t\t\t\t\t\t\t\t\t<Wrapper {...(Action.wrapperProps as FieldBuilderArgs)}>\r\n\t\t\t\t\t\t\t\t\t\t<Flex gap=\"2\" align=\"center\">\r\n\t\t\t\t\t\t\t\t\t\t\t<Action.Icon />\r\n\t\t\t\t\t\t\t\t\t\t\t{Action.text}\r\n\t\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t\t</Wrapper>\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\t.filter((x): x is DropdownMenuItemProps => x !== null)}\r\n\t\t\t\t/>\r\n\t\t\t</Box>\r\n\t\t</>\r\n\t)\r\n})\r\n","export const formId = \"form-builder\"\n","import { ISerializedField } from \"@overmap-ai/core\"\r\nimport { Card, Flex } from \"@overmap-ai/blocks\"\r\nimport { deserialize, useFieldInput } from \"fields\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { Draggable } from \"@hello-pangea/dnd\"\r\nimport { FieldActions } from \"./FieldActions\"\r\nimport { formId } from \"./constants\"\r\nimport { FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { incrementFieldLabel } from \"./utils\"\r\n\r\ninterface FieldWithActionsProps {\r\n\tfield: ISerializedField\r\n\tindex: number\r\n\tsectionIndex: number\r\n\ttakenLabels: string[]\r\n\tremove: () => void\r\n}\r\n\r\nexport const FieldWithActions = memo(function FieldWithActions(props: FieldWithActionsProps) {\r\n\tconst { field, index, sectionIndex, takenLabels, remove } = props\r\n\tconst deserializedField = useMemo(() => deserialize(field), [field])\r\n\tconst input = useFieldInput(deserializedField, { formId, disabled: true })\r\n\r\n\tconst duplicateField = useCallback(\r\n\t\t(field: ISerializedField) => {\r\n\t\t\t// only already created sections can be duplicated so labels should exist\r\n\t\t\tif (field.label === null) {\r\n\t\t\t\tthrow new Error(`Expected a label for field ${field.identifier}`)\r\n\t\t\t}\r\n\t\t\treturn { ...field, label: incrementFieldLabel(field.label, takenLabels), identifier: \"\" }\r\n\t\t},\r\n\t\t[takenLabels],\r\n\t)\r\n\r\n\tconst editFieldProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex,\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tinitial: field,\r\n\t\t\tediting: true,\r\n\t\t}),\r\n\t\t[field, index, sectionIndex],\r\n\t)\r\n\r\n\tconst duplicateFieldProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: index + 1,\r\n\t\t\tinitial: duplicateField(field),\r\n\t\t}),\r\n\t\t[duplicateField, field, index, sectionIndex],\r\n\t)\r\n\r\n\tconst insertAfterProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: index + 1,\r\n\t\t\tinitial: undefined,\r\n\t\t}),\r\n\t\t[index, sectionIndex],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<Draggable draggableId={field.identifier} index={index}>\r\n\t\t\t{(draggableProvided) => (\r\n\t\t\t\t<Card\r\n\t\t\t\t\tref={draggableProvided.innerRef}\r\n\t\t\t\t\t{...draggableProvided.draggableProps}\r\n\t\t\t\t\t{...draggableProvided.dragHandleProps}\r\n\t\t\t\t\t// using margin bottom instead of flex gap to avoid a bug where the\r\n\t\t\t\t\t// gap is not applied to dragged elements\r\n\t\t\t\t\tmb=\"4\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Flex gap=\"4\" justify=\"between\" align=\"center\">\r\n\t\t\t\t\t\t{input}\r\n\t\t\t\t\t\t<FieldActions\r\n\t\t\t\t\t\t\tremove={remove}\r\n\t\t\t\t\t\t\teditProps={editFieldProps}\r\n\t\t\t\t\t\t\tduplicateProps={duplicateFieldProps}\r\n\t\t\t\t\t\t\tinsertAfterProps={insertAfterProps}\r\n\t\t\t\t\t\t\tdragHandleProps={draggableProvided.dragHandleProps}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Card>\r\n\t\t\t)}\r\n\t\t</Draggable>\r\n\t)\r\n})\r\n","import { PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { Button, Card, Em, Flex, Heading, Strong, Text } from \"@overmap-ai/blocks\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { Draggable, Droppable } from \"@hello-pangea/dnd\"\r\nimport { FieldActions } from \"./FieldActions\"\r\nimport { FormikUserFormRevision } from \"./typings\"\r\nimport {\r\n\temptySection,\r\n\tfindFieldByIdentifier,\r\n\tmakeConditionalSourceFields,\r\n\tremove,\r\n\tincrementFieldLabel,\r\n\tgetTakenFieldLabels,\r\n\tmakeIdentifier,\r\n} from \"./utils\"\r\nimport { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { DropState } from \"./DropDispatch\"\r\nimport { useAlertDialog } from \"@overmap-ai/blocks\"\r\nimport { FieldWithActions } from \"./FieldWithActions\"\r\nimport styles from \"styling.module.sass\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { valueIsFile } from \"fields\"\r\n\r\ninterface FieldSectionWithActionsProps {\r\n\tfield: SerializedFieldSection\r\n\tindex: number\r\n\tdropState: DropState\r\n}\r\n\r\nexport const FieldSectionWithActions = memo(function FieldSectionWithActions(props: FieldSectionWithActionsProps) {\r\n\tconst { field, index: sectionIndex, dropState } = props\r\n\tconst isDropDisabled = dropState[field.identifier]?.disabled\r\n\tconst { setFieldValue, values } = useFormikContext<FormikUserFormRevision>()\r\n\tconst alertDialog = useAlertDialog()\r\n\tconst takenFieldLabels = getTakenFieldLabels(values.fields)\r\n\r\n\tconst removeSectionConditions = useCallback(\r\n\t\t(sectionsToUpdate: SerializedFieldSection[], allSections: SerializedFieldSection[]) => {\r\n\t\t\tfor (const section of sectionsToUpdate) {\r\n\t\t\t\tconst sectionIndex = allSections.indexOf(section)\r\n\t\t\t\tsetFieldValue(`fields.${sectionIndex}.condition`, null).then()\r\n\t\t\t\tsetFieldValue(`fields.${sectionIndex}.conditional`, false).then()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[setFieldValue],\r\n\t)\r\n\r\n\tconst makeRemoveFieldAction = useCallback(\r\n\t\t(fieldIndex: number) => {\r\n\t\t\tconst removing = field.fields[fieldIndex]\r\n\t\t\tif (!removing) throw new Error(\"Could not find field to remove.\")\r\n\r\n\t\t\t// check if field is being used as a condition\r\n\t\t\tconst sectionsWithMatchingCondition: SerializedFieldSection[] = []\r\n\t\t\tfor (const section of values.fields) {\r\n\t\t\t\tif (section.condition?.identifier === removing.identifier) {\r\n\t\t\t\t\tsectionsWithMatchingCondition.push(section)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\tremoving,\r\n\t\t\t\taffectedSections: sectionsWithMatchingCondition,\r\n\t\t\t\taction: () => setFieldValue(`fields.${sectionIndex}.fields`, remove(field.fields, fieldIndex)),\r\n\t\t\t}\r\n\t\t},\r\n\t\t[field.fields, values.fields, setFieldValue, sectionIndex],\r\n\t)\r\n\r\n\tconst removeField = useCallback(\r\n\t\t(i: number) => {\r\n\t\t\tconst { affectedSections, action, removing } = makeRemoveFieldAction(i)\r\n\r\n\t\t\tconst cmd = () => {\r\n\t\t\t\taction().then()\r\n\t\t\t\tremoveSectionConditions(affectedSections, values.fields)\r\n\t\t\t}\r\n\r\n\t\t\tif (affectedSections.length > 0) {\r\n\t\t\t\tconst labels = affectedSections.map((section) => section.label).join(\", \")\r\n\t\t\t\treturn alertDialog({\r\n\t\t\t\t\ttitle: \"Remove condition?\",\r\n\t\t\t\t\tdescription: `${removing.label} is being used as a condition, deleting it will remove the condition from the ${labels} section(s).`,\r\n\t\t\t\t\tseverity: \"danger\",\r\n\t\t\t\t\tactionText: \"Remove\",\r\n\t\t\t\t\tonAction: cmd,\r\n\t\t\t\t})\r\n\t\t\t}\r\n\r\n\t\t\t// not a condition, remove field\r\n\t\t\tcmd()\r\n\t\t},\r\n\t\t[makeRemoveFieldAction, removeSectionConditions, values.fields, alertDialog],\r\n\t)\r\n\r\n\tconst removeSection = useCallback(() => {\r\n\t\tconst fieldSideEffects = field.fields.map((_, i) => makeRemoveFieldAction(i))\r\n\t\tconst affectedSections = fieldSideEffects.flatMap((sideEffect) => sideEffect.affectedSections)\r\n\r\n\t\tconst title = affectedSections.length ? \"Remove fields and conditions?\" : \"Remove fields?\"\r\n\t\tconst numFields = field.fields.length\r\n\t\tconst sectionLabels = affectedSections.map((section) => section.label).join(\", \")\r\n\t\tconst description = affectedSections.length\r\n\t\t\t? `Deleting this section will remove the ${numFields} field(s) it contains and will remove the conditions from following sections: ${sectionLabels}`\r\n\t\t\t: `Deleting this section will remove the ${numFields} field(s) it contains.`\r\n\r\n\t\tconst updatedSections = remove(values.fields, sectionIndex)\r\n\t\tconst cmd = () => setFieldValue(\"fields\", updatedSections)\r\n\r\n\t\tif (affectedSections.length > 0) {\r\n\t\t\treturn alertDialog({\r\n\t\t\t\ttitle,\r\n\t\t\t\tdescription,\r\n\t\t\t\tseverity: \"danger\",\r\n\t\t\t\tactionText: \"Remove\",\r\n\t\t\t\tonAction: () => {\r\n\t\t\t\t\t// remove the section (and fields)\r\n\t\t\t\t\tcmd().then(() => {\r\n\t\t\t\t\t\t// remove conditions from affected sections\r\n\t\t\t\t\t\tremoveSectionConditions(affectedSections, updatedSections)\r\n\t\t\t\t\t})\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\t// if no side effects for other sections, just remove the section\r\n\t\tcmd().then()\r\n\t}, [\r\n\t\tfield.fields,\r\n\t\tvalues.fields,\r\n\t\tsectionIndex,\r\n\t\tmakeRemoveFieldAction,\r\n\t\tsetFieldValue,\r\n\t\talertDialog,\r\n\t\tremoveSectionConditions,\r\n\t])\r\n\r\n\tconst duplicateSection = useCallback(\r\n\t\t(field: SerializedFieldSection) => {\r\n\t\t\t// only already created sections can be duplicated so labels should exist\r\n\t\t\tif (field.label === null) {\r\n\t\t\t\tthrow new Error(`Expected a label for field ${field.identifier}`)\r\n\t\t\t}\r\n\t\t\tconst newSectionLabel = incrementFieldLabel(field.label, takenFieldLabels)\r\n\t\t\tconst newFields = field.fields.map((f) => {\r\n\t\t\t\tconst newLabel = incrementFieldLabel(f.label, takenFieldLabels)\r\n\t\t\t\t// Make new identifiers now as they will not be made by FieldBuilder\r\n\t\t\t\treturn {\r\n\t\t\t\t\t...f,\r\n\t\t\t\t\tlabel: newLabel,\r\n\t\t\t\t\tidentifier: makeIdentifier(undefined, newLabel),\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\treturn { ...field, label: newSectionLabel, fields: newFields, identifier: \"\" }\r\n\t\t},\r\n\t\t[takenFieldLabels],\r\n\t)\r\n\r\n\tconst editSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: field,\r\n\t\t\tediting: true,\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex),\r\n\t\t}),\r\n\t\t[field, sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst insertSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex + 1,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: emptySection(),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1),\r\n\t\t}),\r\n\t\t[sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst insertFieldAtEndOfSection: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: field.fields.length,\r\n\t\t\tinitial: undefined,\r\n\t\t}),\r\n\t\t[field.fields.length, sectionIndex],\r\n\t)\r\n\r\n\tconst duplicateSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex + 1,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: duplicateSection(field),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1),\r\n\t\t}),\r\n\t\t[duplicateSection, field, sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst conditionLabel = useMemo(\r\n\t\t() => findFieldByIdentifier(values.fields, field.condition?.identifier)?.label,\r\n\t\t[field.condition?.identifier, values.fields],\r\n\t)\r\n\r\n\tconst conditionComparison = Array.isArray(field.condition?.value) ? \"contains all of\" : \"equals\"\r\n\tif (valueIsFile(field.condition?.value)) throw new Error(\"File values are not supported for conditions.\")\r\n\tconst conditionValue = Array.isArray(field.condition?.value)\r\n\t\t? field.condition?.value.map((v) => (typeof v === \"string\" ? v : v.label)).join(\", \")\r\n\t\t: field.condition?.value.toString()\r\n\r\n\treturn (\r\n\t\t<Draggable draggableId={field.identifier} index={sectionIndex}>\r\n\t\t\t{(draggableProvided) => (\r\n\t\t\t\t<Card\r\n\t\t\t\t\tref={draggableProvided.innerRef}\r\n\t\t\t\t\t{...draggableProvided.draggableProps}\r\n\t\t\t\t\t{...draggableProvided.dragHandleProps}\r\n\t\t\t\t\t// using margin bottom instead of flex gap to avoid a bug where the\r\n\t\t\t\t\t// gap is not applied to dragged elements\r\n\t\t\t\t\tmb=\"4\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Flex gap=\"3\" justify=\"between\" align=\"center\">\r\n\t\t\t\t\t\t<Flex direction=\"column\" gap=\"2\" grow=\"1\">\r\n\t\t\t\t\t\t\t<Flex direction=\"column\">\r\n\t\t\t\t\t\t\t\t<Heading as=\"h3\" size=\"3\">\r\n\t\t\t\t\t\t\t\t\t{field.label}\r\n\t\t\t\t\t\t\t\t</Heading>\r\n\t\t\t\t\t\t\t\t<Text className={styles.description}>{field.description}</Text>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t{field.condition && (\r\n\t\t\t\t\t\t\t\t<Text size=\"1\">\r\n\t\t\t\t\t\t\t\t\t<Em>\r\n\t\t\t\t\t\t\t\t\t\tDisplay only if <Strong>{conditionLabel}</Strong> {conditionComparison}{\" \"}\r\n\t\t\t\t\t\t\t\t\t\t<Strong>{conditionValue}</Strong>\r\n\t\t\t\t\t\t\t\t\t</Em>\r\n\t\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t<Droppable droppableId={field.identifier} type=\"SECTION\" isDropDisabled={isDropDisabled}>\r\n\t\t\t\t\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t\t\t\t\t<Flex\r\n\t\t\t\t\t\t\t\t\t\tref={droppableProvided.innerRef}\r\n\t\t\t\t\t\t\t\t\t\t{...droppableProvided.droppableProps}\r\n\t\t\t\t\t\t\t\t\t\tdirection=\"column\"\r\n\t\t\t\t\t\t\t\t\t\tgap=\"0\"\r\n\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t{field.fields.map((child, i) => (\r\n\t\t\t\t\t\t\t\t\t\t\t<FieldWithActions\r\n\t\t\t\t\t\t\t\t\t\t\t\tkey={child.identifier}\r\n\t\t\t\t\t\t\t\t\t\t\t\tfield={child}\r\n\t\t\t\t\t\t\t\t\t\t\t\tindex={i}\r\n\t\t\t\t\t\t\t\t\t\t\t\tsectionIndex={sectionIndex}\r\n\t\t\t\t\t\t\t\t\t\t\t\tremove={() => removeField(i)}\r\n\t\t\t\t\t\t\t\t\t\t\t\ttakenLabels={takenFieldLabels}\r\n\t\t\t\t\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\r\n\t\t\t\t\t\t\t\t\t\t<FieldBuilder {...insertFieldAtEndOfSection}>\r\n\t\t\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"outline\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<PlusIcon /> Add a field\r\n\t\t\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t\t\t</FieldBuilder>\r\n\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t</Droppable>\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t<FieldActions\r\n\t\t\t\t\t\t\tremove={removeSection}\r\n\t\t\t\t\t\t\tinsertAfterProps={insertSectionProps}\r\n\t\t\t\t\t\t\tdragHandleProps={draggableProvided.dragHandleProps}\r\n\t\t\t\t\t\t\teditProps={editSectionProps}\r\n\t\t\t\t\t\t\tduplicateProps={duplicateSectionProps}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Card>\r\n\t\t\t)}\r\n\t\t</Draggable>\r\n\t)\r\n})\r\n","import { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { Reducer } from \"react\"\r\n\r\nexport interface SmallFieldSection {\r\n\t/** is dropping disabled in this section? */\r\n\tdisabled: boolean\r\n\t/** id's of field that may not be dropped on this section */\r\n\tconditionFields: Set<string>\r\n\t/** the index of the section the condition is in */\r\n\tconditionIndex?: number\r\n\t/** the index of the section */\r\n\tindex: number\r\n\t/** label of the section */\r\n\tlabel: string | null\r\n}\r\n\r\n// section id -> section state\r\nexport type DropState = Record<string, SmallFieldSection>\r\n\r\nexport type DropAction = { type: \"release\" } | { type: \"hold\"; fieldId: string } | { type: \"update\"; state: DropState }\r\n\r\nexport const reducer: Reducer<DropState, DropAction> = (state, action) => {\r\n\tconst next = { ...state }\r\n\r\n\tswitch (action.type) {\r\n\t\tcase \"release\":\r\n\t\t\tfor (const sectionId in next) {\r\n\t\t\t\tnext[sectionId]!.disabled = false\r\n\t\t\t}\r\n\t\t\treturn next\r\n\t\tcase \"hold\":\r\n\t\t\tfor (const sectionId in next) {\r\n\t\t\t\tif (next[sectionId]?.conditionFields.has(action.fieldId)) {\r\n\t\t\t\t\tnext[sectionId]!.disabled = true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn next\r\n\t\tcase \"update\":\r\n\t\t\treturn action.state\r\n\t}\r\n}\r\n\r\n/** @returns the index of the section containing the field */\r\nconst getConditionIndex = (fields: SerializedFieldSection[], identifier?: string): number | undefined => {\r\n\tif (!identifier) return undefined\r\n\r\n\tfor (let i = 0; i < fields.length; i++) {\r\n\t\tconst section = fields[i]\r\n\r\n\t\tif (!section) continue\r\n\r\n\t\tfor (const field of section.fields) {\r\n\t\t\tif (field.identifier === identifier) return i\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/** creates a `DropState` from a list of `SerializedFieldSection` objects */\r\nexport const initializer = (fields: SerializedFieldSection[]): DropState => {\r\n\tconst acc: DropState = {}\r\n\r\n\tfor (let index = 0; index < fields.length; index++) {\r\n\t\tconst field = fields[index]\r\n\t\tif (!field) throw new Error(\"Field is undefined.\")\r\n\r\n\t\t// include any fields that are disabled by the condition of the previous field\r\n\t\tconst previousConditionFields = index > 0 ? acc[fields[index - 1]!.identifier]?.conditionFields : undefined\r\n\t\tconst disabledFields = new Set<string>(previousConditionFields)\r\n\t\tif (field.condition?.identifier) {\r\n\t\t\tdisabledFields.add(field.condition.identifier)\r\n\t\t}\r\n\r\n\t\tacc[field.identifier] = {\r\n\t\t\tdisabled: false,\r\n\t\t\tconditionFields: disabledFields,\r\n\t\t\tconditionIndex: getConditionIndex(fields, field.condition?.identifier),\r\n\t\t\tindex,\r\n\t\t\tlabel: field.label,\r\n\t\t}\r\n\t}\r\n\r\n\treturn acc\r\n}\r\n","import { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { memo, useCallback, useEffect, useMemo, useReducer } from \"react\"\r\nimport { DragDropContext, Droppable, OnDragEndResponder, OnDragStartResponder } from \"@hello-pangea/dnd\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { FormikUserFormRevision } from \"./typings\"\r\nimport { Flex, Button, useToast } from \"@overmap-ai/blocks\"\r\nimport { PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { emptySection, insert, makeConditionalSourceFields, remove, reorder } from \"./utils\"\r\nimport { FieldSectionWithActions } from \"./FieldSectionWithActions\"\r\nimport { initializer, reducer } from \"./DropDispatch\"\r\n\r\n/** \r\n * NOTE: Because this returns a new array instance on every call, it will cause re-renders if not destructured.\r\n * \r\n * BAD:\r\n * ```\r\nconst section: [SerializedFieldSection, string] | undefined = findSection(values.fields, source.droppableId)\r\nconst myEffect = useEffect(() => { doSomethingWith(section) }, [section])\r\n```\r\n * GOOD:\r\n```\r\nconst [section, i]: [SerializedFieldSection, string] | undefined = findSection(values.fields, source.droppableId)\r\nconst myEffect = useEffect(() => { doSomethingWith(section, index) }, [section, i])\r\n```\r\n*/\r\nconst findSection = (\r\n\tfields: SerializedFieldSection[],\r\n\tsectionId: string,\r\n): [SerializedFieldSection, string] | undefined => {\r\n\tfor (const [i, section] of Object.entries(fields)) {\r\n\t\tif (section.identifier === sectionId) return [section, i]\r\n\t}\r\n}\r\n\r\nexport const FieldsEditor = memo(function FieldsEditor() {\r\n\tconst { values, setFieldValue } = useFormikContext<FormikUserFormRevision>()\r\n\t// used to conditionally disable dropping on field sections so that a field\r\n\t// using a condition cannot be dropped after the section referencing it\r\n\tconst [dropState, dispatch] = useReducer(reducer, values.fields, initializer)\r\n\tconst { showInfo } = useToast()\r\n\r\n\tuseEffect(() => {\r\n\t\tdispatch({ type: \"update\", state: initializer(values.fields) })\r\n\t}, [dispatch, values.fields])\r\n\r\n\tconst handleDragStart = useCallback<OnDragStartResponder>((start) => {\r\n\t\t// validation for ensuring a condition is before the section\r\n\t\t// when dragging a section occurs in `handleDragEnd`\r\n\r\n\t\t// if dragging a field between sections\r\n\t\tif (start.type === \"SECTION\") {\r\n\t\t\tdispatch({ type: \"hold\", fieldId: start.draggableId })\r\n\t\t}\r\n\t}, [])\r\n\r\n\tconst handleDragEnd = useCallback<OnDragEndResponder>(\r\n\t\t(result) => {\r\n\t\t\tconst { source, destination, type, reason, draggableId } = result\r\n\t\t\tdispatch({ type: \"release\" })\r\n\r\n\t\t\tif (!destination || reason === \"CANCEL\") return\r\n\r\n\t\t\tif (type === \"ROOT\") {\r\n\t\t\t\tconst state = dropState[draggableId]\r\n\t\t\t\tif (!state) throw new Error(\"Could not find section context.\")\r\n\r\n\t\t\t\tlet dest =\r\n\t\t\t\t\ttypeof state.conditionIndex !== \"undefined\"\r\n\t\t\t\t\t\t? // cannot move a section with a condition before the condition's field\r\n\t\t\t\t\t\t Math.max(state.conditionIndex + 1, destination.index)\r\n\t\t\t\t\t\t: destination.index\r\n\r\n\t\t\t\t// check if this section contains another section's condition\r\n\t\t\t\tfor (const section of Object.values(dropState)) {\r\n\t\t\t\t\tif (section.conditionIndex === source.index) {\r\n\t\t\t\t\t\t// ensure condition field is above the section referencing it\r\n\t\t\t\t\t\tdest = Math.min(dest, section.index - 1)\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (dest != destination.index) {\r\n\t\t\t\t\t// TODO: change to a warning toast\r\n\t\t\t\t\tshowInfo({\r\n\t\t\t\t\t\ttitle: \"Reordered sections\",\r\n\t\t\t\t\t\tdescription: \"Sections with conditions must be below the fields they reference.\",\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn setFieldValue(\"fields\", reorder(values.fields, source.index, dest))\r\n\t\t\t}\r\n\r\n\t\t\tif (type !== \"SECTION\") throw new Error(\"Unexpected droppable type.\")\r\n\r\n\t\t\tconst [sourceSection, srcIndex] = findSection(values.fields, source.droppableId) ?? []\r\n\t\t\tconst [destinationSection, destIndex] = findSection(values.fields, destination.droppableId) ?? []\r\n\r\n\t\t\tif (!sourceSection?.fields || !destinationSection) throw new Error(\"Could not find section with fields.\")\r\n\r\n\t\t\tif (sourceSection.identifier === destinationSection.identifier) {\r\n\t\t\t\tsetFieldValue(\r\n\t\t\t\t\t`fields.${srcIndex}.fields`,\r\n\t\t\t\t\treorder(sourceSection.fields, source.index, destination.index),\r\n\t\t\t\t).then()\r\n\t\t\t} else {\r\n\t\t\t\tconst removed = sourceSection.fields[source.index]\r\n\t\t\t\tif (!removed) throw new Error(\"Could not find field to reorder.\")\r\n\r\n\t\t\t\tsetFieldValue(`fields.${srcIndex}.fields`, remove(sourceSection.fields, source.index)).then()\r\n\t\t\t\tsetFieldValue(\r\n\t\t\t\t\t`fields.${destIndex}.fields`,\r\n\t\t\t\t\tinsert(destinationSection.fields, destination.index, removed),\r\n\t\t\t\t).then()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[values.fields, setFieldValue, dropState, showInfo],\r\n\t)\r\n\r\n\tconst makeFieldSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: values.fields.length,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: emptySection(),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, values.fields.length),\r\n\t\t}),\r\n\t\t[values.fields],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\r\n\t\t\t<Droppable droppableId=\"droppable\" type=\"ROOT\">\r\n\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t<Flex\r\n\t\t\t\t\t\tref={droppableProvided.innerRef}\r\n\t\t\t\t\t\t{...droppableProvided.droppableProps}\r\n\t\t\t\t\t\tdirection=\"column\"\r\n\t\t\t\t\t\tgap=\"0\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{values.fields.map((field, index) => (\r\n\t\t\t\t\t\t\t<FieldSectionWithActions\r\n\t\t\t\t\t\t\t\tkey={field.label}\r\n\t\t\t\t\t\t\t\tfield={field}\r\n\t\t\t\t\t\t\t\tindex={index}\r\n\t\t\t\t\t\t\t\tdropState={dropState}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\r\n\t\t\t\t\t\t<FieldBuilder {...makeFieldSectionProps}>\r\n\t\t\t\t\t\t\t<Button type=\"button\" variant=\"outline\">\r\n\t\t\t\t\t\t\t\t<PlusIcon /> Add a section\r\n\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t</FieldBuilder>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t)}\r\n\t\t\t</Droppable>\r\n\t\t</DragDropContext>\r\n\t)\r\n})\r\n","import { formRevisionToSchema, StringField, TextField, useFieldInput } from \"../fields\"\r\nimport { FormikErrors, FormikProvider, useFormik } from \"formik\"\r\nimport { FormRenderer } from \"../renderer\"\r\nimport { Button, Flex, Heading, Tabs, Text } from \"@overmap-ai/blocks\"\r\nimport { FormBuilderSaveHandler, FormikUserFormRevision, NewForm } from \"./typings\"\r\nimport { FieldsEditor } from \"./FieldsEditor\"\r\nimport { hasKeys } from \"utils\"\r\nimport { forwardRef, memo, ReactNode, useCallback, useMemo } from \"react\"\r\nimport { ISchema } from \"fields/typings\"\r\nimport { wrapRootFieldsWithFieldSection } from \"./utils\"\r\nimport { formId } from \"./constants\"\r\nimport { UserFormRevision } from \"@overmap-ai/core\"\r\n\r\nconst initialValues: NewForm = {\r\n\ttitle: \"\",\r\n\tdescription: \"\",\r\n\tfields: [],\r\n}\r\n\r\nconst title = new StringField({\r\n\tlabel: \"Title\",\r\n\tminLength: 0,\r\n\tmaxLength: 100,\r\n\trequired: true,\r\n\tidentifier: \"title\",\r\n})\r\n\r\nconst titleProps = { formId, placeholder: \"Give your form a title.\" }\r\n\r\nconst description = new TextField({\r\n\tlabel: \"Description\",\r\n\tminLength: 0,\r\n\tmaxLength: 1000,\r\n\trequired: false,\r\n\tidentifier: \"description\",\r\n})\r\n\r\nconst descriptionProps = { formId, placeholder: \"Explain the purpose of this form.\" }\r\n\r\nconst previewSubmit = () => {\r\n\talert(\"This is a form preview, your data will not be saved.\")\r\n}\r\n\r\ninterface FormBuilderProps {\r\n\tonCancel?: () => void\r\n\tonSave: FormBuilderSaveHandler\r\n\t/** A revision of an existing form to edit. To create a new form, pass `undefined`. */\r\n\trevision?: UserFormRevision\r\n\t/** A heading for the `FormBuilder`\r\n\t * @default \"Create a new form\" or \"Edit form\" if `revision` is passed\r\n\t */\r\n\theading?: ReactNode\r\n}\r\n\r\nexport const FormBuilder = memo(\r\n\tforwardRef<HTMLDivElement, FormBuilderProps>((props, ref) => {\r\n\t\tconst { onCancel, onSave, revision } = props\r\n\t\tconst defaultHeading = revision ? \"Edit form\" : \"Create a new form\"\r\n\t\tconst { heading = defaultHeading } = props\r\n\r\n\t\tconst validate = useCallback((form: FormikUserFormRevision) => {\r\n\t\t\tconst errors: FormikErrors<FormikUserFormRevision> = {}\r\n\t\t\tif (!form.title) {\r\n\t\t\t\terrors.title = \"Title is required.\"\r\n\t\t\t}\r\n\t\t\tif (!form.fields || form.fields.length === 0) {\r\n\t\t\t\terrors.fields = \"At least one field is required.\"\r\n\t\t\t}\r\n\t\t\tif (hasKeys(errors)) {\r\n\t\t\t\treturn errors\r\n\t\t\t}\r\n\t\t}, [])\r\n\r\n\t\tconst formik = useFormik<FormikUserFormRevision>({\r\n\t\t\tinitialValues: wrapRootFieldsWithFieldSection(revision) ?? initialValues,\r\n\t\t\tvalidate,\r\n\t\t\tonSubmit: (form) => onSave(form),\r\n\t\t\t// only validate the entire for on submit\r\n\t\t\tvalidateOnChange: false,\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t})\r\n\r\n\t\tconst previewSchema: ISchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values])\r\n\r\n\t\tconst titleInput = useFieldInput(title, titleProps)\r\n\t\tconst descriptionInput = useFieldInput(description, descriptionProps)\r\n\t\tconst FormBuilderHeading = useMemo(\r\n\t\t\t() => (typeof heading === \"object\" ? heading : <Heading>{heading}</Heading>),\r\n\t\t\t[heading],\r\n\t\t)\r\n\r\n\t\treturn (\r\n\t\t\t<Tabs.Root ref={ref} defaultValue=\"edit\">\r\n\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t<Tabs.List>\r\n\t\t\t\t\t\t<Tabs.Trigger value=\"edit\">Edit</Tabs.Trigger>\r\n\t\t\t\t\t\t<Tabs.Trigger value=\"preview\">Preview</Tabs.Trigger>\r\n\t\t\t\t\t</Tabs.List>\r\n\r\n\t\t\t\t\t<Tabs.Content value=\"edit\">\r\n\t\t\t\t\t\t{FormBuilderHeading}\r\n\t\t\t\t\t\t<Text>\r\n\t\t\t\t\t\t\tAdd a new form field by clicking a + button. Specify options for each field, then drag and\r\n\t\t\t\t\t\t\tdrop to rearrange them. You can see what a submitted form might look like in the{\" \"}\r\n\t\t\t\t\t\t\t<em>Preview</em> tab, but{\" \"}\r\n\t\t\t\t\t\t\t<strong>field values entered on this page will not be saved.</strong>\r\n\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t<Flex asChild direction=\"column\" gap=\"2\" mt=\"3\">\r\n\t\t\t\t\t\t\t<form id={formId} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t\t\t\t\t\t{titleInput}\r\n\t\t\t\t\t\t\t\t\t{descriptionInput}\r\n\t\t\t\t\t\t\t\t\t<FieldsEditor />\r\n\t\t\t\t\t\t\t\t\t<Text severity=\"danger\" size=\"1\">\r\n\t\t\t\t\t\t\t\t\t\t{typeof formik.errors.fields === \"string\" && formik.errors.fields}\r\n\t\t\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t\t\t</FormikProvider>\r\n\t\t\t\t\t\t\t\t<Flex justify=\"end\" gap=\"2\">\r\n\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"soft\" onClick={onCancel}>\r\n\t\t\t\t\t\t\t\t\t\tCancel\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t\t<Button type=\"submit\" disabled={!formik.isValid}>\r\n\t\t\t\t\t\t\t\t\t\tSave\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t</form>\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t</Tabs.Content>\r\n\r\n\t\t\t\t\t<Tabs.Content value=\"preview\">\r\n\t\t\t\t\t\t<FormRenderer schema={previewSchema} onSubmit={previewSubmit} />\r\n\t\t\t\t\t</Tabs.Content>\r\n\t\t\t\t</Flex>\r\n\t\t\t</Tabs.Root>\r\n\t\t)\r\n\t}),\r\n)\r\n"],"names":["description","styles","formId","BooleanInput","NumberInput","TextField","DateInput","StringInput","TextInput","SelectInput","MultiStringInput","MultiSelectInput","value","FieldInputCloner","FieldSectionLayout","option","_a","DisplayFile","url","name","size","v","FormSubmissionBrowserEntry","FormSubmissionBrowser","PatchField","initialValues","values","FieldToChoose","ChooseFieldToAdd","FieldOptionsForm","FieldBuilder","title","FieldActions","remove","props","FieldWithActions","field","FieldSectionWithActions","sectionIndex","_b","FieldsEditor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forms.js","sources":["../src/fields/BaseField/BaseField.ts","../src/fields/BaseField/layouts.tsx","../src/fields/BaseField/hooks.tsx","../src/fields/BooleanField/BooleanInput.tsx","../src/fields/BooleanField/BooleanField.tsx","../src/fields/NumberField/NumberInput.tsx","../src/fields/NumberField/NumberField.tsx","../src/fields/DateField/DateInput.tsx","../src/fields/DateField/DateField.tsx","../src/fields/StringOrTextFields/StringOrTextField.ts","../src/fields/StringOrTextFields/StringField/StringInput.tsx","../src/fields/StringOrTextFields/StringField/StringField.tsx","../src/fields/StringOrTextFields/TextField/TextInput.tsx","../src/fields/StringOrTextFields/TextField/TextField.tsx","../src/fields/SelectField/SelectInput.tsx","../src/builder/utils.ts","../src/fields/MultiStringField/MultiStringInput.tsx","../src/fields/MultiStringField/MultiStringField.tsx","../src/fields/SelectField/BaseSelectField.ts","../src/fields/SelectField/SelectField.tsx","../src/fields/SelectField/MultiSelectInput.tsx","../src/fields/SelectField/MultiSelectField.tsx","../src/fields/CustomField/FieldInputClonerField/FieldInputCloner.tsx","../src/fields/CustomField/CustomField.tsx","../src/fields/CustomField/FieldInputClonerField/FieldInputClonerField.tsx","../src/fields/FieldSection/FieldSectionLayout.tsx","../src/fields/FieldSection/FieldSection.tsx","../src/fields/UploadField/utils.ts","../src/fields/UploadField/UploadInput.tsx","../src/fields/UploadField/UploadField.tsx","../src/fields/constants.ts","../src/fields/utils.ts","../src/fields/hooks.tsx","../src/utils.ts","../src/renderer/FormRenderer/FormRenderer.tsx","../src/renderer/FormSubmissionViewer/FormSubmissionViewer.tsx","../src/renderer/FormBrowser/FormBrowser.tsx","../src/renderer/FormSubmissionBrowser/FormSubmissionBrowser.tsx","../src/renderer/PatchForm/Field.tsx","../src/renderer/PatchForm/Provider.tsx","../src/builder/FieldBuilder.tsx","../src/builder/FieldActions.tsx","../src/builder/constants.ts","../src/builder/FieldWithActions.tsx","../src/builder/FieldSectionWithActions.tsx","../src/builder/DropDispatch.ts","../src/builder/FieldsEditor.tsx","../src/builder/FormBuilder.tsx"],"sourcesContent":["import {\r\n\tBaseSerializedField,\r\n\tBaseSerializedObject,\r\n\tFieldTypeIdentifier,\r\n\tFieldValue,\r\n\tISerializedField,\r\n} from \"@overmap-ai/core\"\r\nimport {\r\n\tAnyField,\r\n\tGetInputProps,\r\n\tISerializedOnlyField,\r\n\tInputFieldLevelValidator,\r\n\tInputFormLevelValidator,\r\n} from \"fields/typings\"\r\nimport { Form } from \"typings\"\r\nimport { ReactNode } from \"react\"\r\nimport { FieldSection } from \"fields/FieldSection\"\r\nimport { FieldOptions } from \"./typings\"\r\n\r\n// TODO: These types redefine ISerializedField and related types.\r\n// Looks like they can be merged.\r\n\r\n// TODO: \"Element\" implies an instantiated component in React.\r\nexport abstract class BaseFormElement<TIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier> {\r\n\tpublic readonly type: TIdentifier\r\n\tprotected readonly identifier: string\r\n\tpublic readonly description: string | null\r\n\r\n\tprotected constructor(options: BaseSerializedObject) {\r\n\t\tconst { description = null, identifier, type } = options\r\n\t\tthis.identifier = identifier\r\n\t\tthis.description = description\r\n\t\tthis.type = type as TIdentifier\r\n\t}\r\n\r\n\tgetId(): string {\r\n\t\treturn this.identifier\r\n\t}\r\n\r\n\tabstract getInput(props: GetInputProps<this>): ReactNode\r\n\r\n\tstatic deserialize(_data: ISerializedField): AnyField | FieldSection {\r\n\t\tthrow new Error(`${this.name} must implement deserialize.`)\r\n\t}\r\n\r\n\tprotected _serialize(): BaseSerializedObject<TIdentifier> {\r\n\t\tif (!this.identifier) {\r\n\t\t\tthrow new Error(\"Field identifier must be set before serializing.\")\r\n\t\t}\r\n\t\treturn {\r\n\t\t\ttype: this.type,\r\n\t\t\tidentifier: this.identifier,\r\n\t\t\tdescription: this.description,\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport abstract class BaseField<\r\n\tTValue extends FieldValue,\r\n\tTIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier,\r\n> extends BaseFormElement<TIdentifier> {\r\n\tstatic readonly fieldTypeName: string\r\n\tstatic readonly fieldTypeDescription: string\r\n\r\n\tpublic readonly required: boolean\r\n\tprivate readonly formValidators: InputFormLevelValidator<TValue>[]\r\n\tprivate readonly fieldValidators: InputFieldLevelValidator<TValue>[]\r\n\tpublic readonly label: string\r\n\r\n\t/**\r\n\t * By default, validation doesn't execute on `onChange` events when editing fields\r\n\t * until the field has been `touched`. This can be overridden by setting this to `false`\r\n\t * if you want to validate on every `onChange` event. This is important for fields like booleans\r\n\t * which don't have a `onBlur` event (which is used to set the `touched` state).\r\n\t */\r\n\tpublic readonly onlyValidateAfterTouched: boolean = true\r\n\r\n\tprotected constructor(options: FieldOptions<TValue>) {\r\n\t\tconst { label, required, fieldValidators = [], formValidators = [], ...base } = options\r\n\t\tsuper(base)\r\n\t\tthis.label = label\r\n\t\tthis.required = required\r\n\t\tthis.fieldValidators = fieldValidators\r\n\t\tthis.formValidators = formValidators\r\n\t}\r\n\r\n\tpublic static getFieldCreationSchema(): AnyField[] {\r\n\t\treturn []\r\n\t}\r\n\r\n\tprotected isBlank(value: TValue): boolean {\r\n\t\treturn value === null || value === undefined || value === \"\"\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement>): TValue {\r\n\t\treturn event.target.value as unknown as TValue\r\n\t}\r\n\r\n\tpublic getError(value: TValue, allValues?: Form): string | undefined {\r\n\t\tif (this.required && this.isBlank(value)) {\r\n\t\t\treturn \"This field is required.\"\r\n\t\t}\r\n\t\tfor (const validator of this.getFieldValidators()) {\r\n\t\t\tconst error = validator(value)\r\n\t\t\tif (error) return error\r\n\t\t}\r\n\t\tif (allValues) {\r\n\t\t\tfor (const validator of this.getFormValidators()) {\r\n\t\t\t\tconst error = validator(value, allValues)\r\n\t\t\t\tif (error) return error\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// TODO: We can probably combine _serialize and serialize.\r\n\tprotected _serialize(): BaseSerializedField<TIdentifier> {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tlabel: this.label,\r\n\t\t\trequired: this.required,\r\n\t\t}\r\n\t}\r\n\r\n\tabstract serialize(): ISerializedOnlyField\r\n\r\n\tpublic getFieldValidators(): InputFieldLevelValidator<TValue>[] {\r\n\t\treturn [...this.fieldValidators]\r\n\t}\r\n\r\n\tpublic getFormValidators(): InputFormLevelValidator<TValue>[] {\r\n\t\treturn [...this.formValidators]\r\n\t}\r\n}\r\n","import { Flex, Severity, Text, ThemeOptions } from \"@overmap-ai/blocks\"\r\nimport { ReactElement, ComponentProps, ReactNode } from \"react\"\r\nimport styles from \"styling.module.sass\"\r\n\r\nexport type Color = ThemeOptions[\"accentColor\"]\r\n\r\ninterface InputWithLabelProps {\r\n\tseverity: Severity | undefined\r\n\tinputId: string\r\n\tlabelId: string\r\n\tlabel: string\r\n\tchildren: ReactNode\r\n\tflexProps?: ComponentProps<typeof Flex>\r\n}\r\nexport const InputWithLabel = (props: InputWithLabelProps) => {\r\n\tconst { label, children, severity, inputId, labelId, flexProps } = props\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"1\" asChild {...flexProps}>\r\n\t\t\t<label htmlFor={inputId}>\r\n\t\t\t\t<Text severity={severity} id={labelId}>\r\n\t\t\t\t\t{label}\r\n\t\t\t\t</Text>\r\n\t\t\t\t{children}\r\n\t\t\t</label>\r\n\t\t</Flex>\r\n\t)\r\n}\r\n\r\ninterface InputWithLabelAndHelpTextProps {\r\n\tseverity: Severity | undefined\r\n\thelpText: string | null\r\n\tchildren: ReactElement<InputWithLabelProps>\r\n}\r\n\r\nexport const InputWithLabelAndHelpText = (props: InputWithLabelAndHelpTextProps) => {\r\n\tconst { helpText, children, severity } = props\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t{children}\r\n\t\t\t<Flex direction=\"column\">\r\n\t\t\t\t<Text size=\"1\" severity={severity} className={styles.description}>\r\n\t\t\t\t\t{helpText}\r\n\t\t\t\t</Text>\r\n\t\t\t</Flex>\r\n\t\t</Flex>\r\n\t)\r\n}\r\n","import { AnyField, ComponentProps } from \"fields/typings\"\r\nimport { useField } from \"formik\"\r\nimport { ValueOfField } from \"../../typings.ts\"\r\nimport { Severity } from \"@overmap-ai/blocks\"\r\nimport { useMemo, ChangeEventHandler, FocusEventHandler } from \"react\"\r\n\r\n// Wrapper for Formik's useField hook that returns the field's props, meta, and helpers.\r\nexport const useFormikInput = <TField extends AnyField>(props: ComponentProps<TField>) => {\r\n\tconst { id, field, formId, ...rest } = props\r\n\tconst [fieldProps, meta, helpers] = useField<ValueOfField<TField>>(field.getId())\r\n\tconst { touched } = meta\r\n\tconst helpText = meta.error ?? field.description\r\n\tconst severity: Severity | undefined = meta.error ? \"danger\" : undefined\r\n\tconst inputId = id ?? `${formId}-${field.getId()}-input`\r\n\tconst labelId = `${inputId}-label`\r\n\tconst label = field.required ? `${field.label} *` : field.label\r\n\r\n\t// adds field-level validation to onChange and onBlur events\r\n\t// this is necessary because Formik's useField hook does not support field-level validation\r\n\tconst fieldPropsWithValidation: typeof fieldProps = useMemo(() => {\r\n\t\tconst handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {\r\n\t\t\tconst value = field.getValueFromChangeEvent(e)\r\n\t\t\thelpers.setValue(value as ValueOfField<TField>, false).then()\r\n\t\t\t// only validate onChange if the field has been touched\r\n\t\t\tif (touched || !field.onlyValidateAfterTouched) {\r\n\t\t\t\thelpers.setError(field.getError(value))\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {\r\n\t\t\thelpers.setTouched(true, false).then()\r\n\t\t\thelpers.setError(field.getError(field.getValueFromChangeEvent(e)))\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\t...fieldProps,\r\n\t\t\tonChange: handleChange,\r\n\t\t\tonBlur: handleBlur,\r\n\t\t}\r\n\t}, [field, fieldProps, helpers, touched])\r\n\r\n\treturn [\r\n\t\t{\r\n\t\t\thelpText,\r\n\t\t\tseverity,\r\n\t\t\tinputId,\r\n\t\t\tlabelId,\r\n\t\t\tlabel,\r\n\t\t\tfieldProps: fieldPropsWithValidation,\r\n\t\t\thelpers,\r\n\t\t\tfield,\r\n\t\t},\r\n\t\t{ ...rest, \"aria-labelledby\": labelId },\r\n\t] as const\r\n}\r\n","import { Checkbox, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\r\nimport { useFormikInput } from \"../BaseField\"\r\nimport { BooleanField } from \"./BooleanField\"\r\n\r\nconst truthyValues = [true, \"true\"]\r\n\r\nexport const BooleanInput = memo(function BooleanInput(props: ComponentProps<BooleanField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\tconst value = truthyValues.includes(fieldProps.value)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel\r\n\t\t\t\tseverity={severity}\r\n\t\t\t\tinputId={inputId}\r\n\t\t\t\tlabelId={labelId}\r\n\t\t\t\tlabel={label}\r\n\t\t\t\tflexProps={{ direction: \"row-reverse\", justify: \"end\", align: \"center\", gap: \"2\" }}\r\n\t\t\t>\r\n\t\t\t\t<Checkbox\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tcolor={color}\r\n\t\t\t\t\tvalue={value.toString()}\r\n\t\t\t\t\tchecked={value}\r\n\t\t\t\t\tonCheckedChange={fieldProps.onChange}\r\n\t\t\t\t\t// disabled onChange and onBlur as that is handled by onCheckedChange\r\n\t\t\t\t\tonChange={undefined}\r\n\t\t\t\t\tonBlur={undefined}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedBooleanField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { BooleanInput } from \"./BooleanInput\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { CheckCircledIcon } from \"@overmap-ai/blocks\"\r\n\r\nexport class BooleanField extends BaseField<boolean, \"boolean\"> {\r\n\tstatic readonly fieldTypeName = \"Checkbox\"\r\n\tstatic readonly fieldTypeDescription = \"Perfect for both optional and required yes/no questions.\"\r\n\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof CheckCircledIcon = CheckCircledIcon\r\n\r\n\tpublic constructor(options: ChildFieldOptions<boolean>) {\r\n\t\tsuper({ ...options, type: \"boolean\" })\r\n\t}\r\n\r\n\t// if a BooleanField is required, `false` is considered blank\r\n\tprotected isBlank(value: boolean): boolean {\r\n\t\treturn this.required && !value\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement> | boolean): boolean {\r\n\t\tif (typeof event === \"boolean\") return event\r\n\t\treturn event.target.checked\r\n\t}\r\n\r\n\tserialize(): SerializedBooleanField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): BooleanField {\r\n\t\tif (data.type !== \"boolean\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new BooleanField(data)\r\n\t}\r\n\r\n\tgetInput(props: ComponentProps<BooleanField>): ReactNode {\r\n\t\treturn <BooleanInput {...props} field={this} />\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\r\nimport { useFormikInput } from \"../BaseField\"\r\nimport { NumberField } from \".\"\r\n\r\nexport const NumberInput = memo(function NumberInput(props: ComponentProps<NumberField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextField.Input\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\ttype=\"number\"\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tmin={field.minimum}\r\n\t\t\t\t\tmax={field.maximum}\r\n\t\t\t\t\tstep={field.integers ? 1 : 0.1}\r\n\t\t\t\t\tcolor={color}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedNumberField } from \"@overmap-ai/core\"\r\nimport { BooleanField } from \"../BooleanField\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps, InputFieldLevelValidator, InputValidator } from \"../typings\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { NumberInput } from \"./NumberInput\"\r\nimport { FontFamilyIcon } from \"@overmap-ai/blocks\"\r\n\r\n// empty number fields are represented by an empty string\r\nexport type NumberFieldValue = number | \"\"\r\n\r\nexport interface NumberFieldOptions extends ChildFieldOptions<NumberFieldValue> {\r\n\tmaximum?: number\r\n\tminimum?: number\r\n\tintegers?: boolean\r\n}\r\n\r\nexport class NumberField extends BaseField<NumberFieldValue, \"number\"> {\r\n\tstatic readonly fieldTypeName = \"Number\"\r\n\tstatic readonly fieldTypeDescription = \"Allows specifying a number within a given range.\"\r\n\r\n\tpublic readonly minimum: number | undefined\r\n\tpublic readonly maximum: number | undefined\r\n\tpublic readonly integers: boolean\r\n\r\n\tstatic Icon: typeof FontFamilyIcon = FontFamilyIcon\r\n\r\n\tconstructor(options: NumberFieldOptions) {\r\n\t\tconst {\r\n\t\t\tminimum = Number.MIN_SAFE_INTEGER,\r\n\t\t\tmaximum = Number.MAX_SAFE_INTEGER,\r\n\t\t\tintegers = false,\r\n\t\t\t...base\r\n\t\t} = options\r\n\t\tsuper({ ...base, type: \"number\" })\r\n\t\tthis.minimum = minimum\r\n\t\tthis.maximum = maximum\r\n\t\tthis.integers = integers\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement>): NumberFieldValue {\r\n\t\tconst number = Number.parseFloat(event.target.value)\r\n\r\n\t\tif (Number.isNaN(number)) return \"\"\r\n\t\treturn number\r\n\t}\r\n\r\n\tstatic _validateMin: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof allValues.maximum === \"number\" && typeof value === \"number\" && allValues.maximum < value) {\r\n\t\t\treturn \"Minimum cannot be greater than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic _validateMax: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof allValues.minimum === \"number\" && typeof value === \"number\" && allValues.minimum > value) {\r\n\t\t\treturn \"Maximum cannot be less than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Minimum\",\r\n\t\t\t\tdescription: \"Minimum value\",\r\n\t\t\t\tintegers: true,\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"minimum\",\r\n\t\t\t\tformValidators: [this._validateMin],\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Maximum\",\r\n\t\t\t\tdescription: \"Maximum value\",\r\n\t\t\t\tintegers: true,\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum\",\r\n\t\t\t\tformValidators: [this._validateMax],\r\n\t\t\t}),\r\n\t\t\tnew BooleanField({\r\n\t\t\t\tlabel: \"Integers\",\r\n\t\t\t\tdescription: \"Whole numbers only\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"integers\",\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<NumberFieldValue>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\t\tconst min = this.minimum\r\n\t\tconst max = this.maximum\r\n\r\n\t\tif (typeof min === \"number\") {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && value < min) {\r\n\t\t\t\t\treturn `Must be at least ${this.minimum}.`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (typeof max === \"number\") {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && value > max) {\r\n\t\t\t\t\treturn `Must be at most ${this.maximum}.`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (this.integers) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"number\" && !Number.isInteger(value)) {\r\n\t\t\t\t\treturn \"Must be a whole number.\"\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tserialize(): SerializedNumberField {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tminimum: this.minimum,\r\n\t\t\tmaximum: this.maximum,\r\n\t\t\tintegers: this.integers,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): NumberField {\r\n\t\tif (data.type !== \"number\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new NumberField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <NumberInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { DateField } from \"./DateField\"\r\n\r\nexport const DateInput = memo(function DateInput(props: ComponentProps<DateField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\t// TODO: Add timezone info\r\n\t// remove the time from the date\r\n\tconst value: string = fieldProps.value ? fieldProps.value.split(\"T\")[0]! : \"\"\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextField.Input {...rest} {...fieldProps} type=\"date\" id={inputId} color={color} value={value} />\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedDateField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport React from \"react\"\r\nimport { DateInput } from \"./DateInput\"\r\nimport { CalendarIcon } from \"@overmap-ai/blocks\"\r\n\r\nexport class DateField extends BaseField<string, \"date\"> {\r\n\tstatic readonly fieldTypeName = \"Date\"\r\n\tstatic readonly fieldTypeDescription = \"Allows specifying a date.\"\r\n\r\n\tstatic Icon: typeof CalendarIcon = CalendarIcon\r\n\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tpublic constructor(options: ChildFieldOptions<string>) {\r\n\t\tsuper({ ...options, type: \"date\" })\r\n\t}\r\n\r\n\tserialize(): SerializedDateField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement>): string {\r\n\t\treturn new Date(event.target.value).toISOString()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): DateField {\r\n\t\tif (data.type !== \"date\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new DateField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <DateInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { NumberField, NumberFieldValue } from \"../NumberField\"\r\nimport { BaseField, FieldOptions } from \"../BaseField\"\r\nimport { SerializedStringField } from \"@overmap-ai/core\"\r\nimport { InputFieldLevelValidator, InputValidator } from \"fields/typings\"\r\n\r\nexport interface StringOrTextFieldOptions extends FieldOptions<string> {\r\n\tminLength?: NumberFieldValue\r\n\tmaxLength?: NumberFieldValue\r\n}\r\n\r\nexport type SerializedStringOrTextField<TIdentifier extends \"string\" | \"text\"> = Omit<SerializedStringField, \"type\"> & {\r\n\ttype: TIdentifier\r\n}\r\n\r\nexport abstract class StringOrTextField<TIdentifier extends \"string\" | \"text\"> extends BaseField<string, TIdentifier> {\r\n\tpublic readonly minLength?: number\r\n\tpublic readonly maxLength: number\r\n\r\n\tprotected constructor(options: StringOrTextFieldOptions) {\r\n\t\tconst { minLength, maxLength = 5000, ...base } = options\r\n\t\tsuper(base)\r\n\t\t// lengths must be greater than or equal to 0\r\n\t\tthis.minLength = minLength ? Math.max(minLength, 0) : undefined\r\n\t\tthis.maxLength = maxLength ? Math.max(maxLength, 0) : 5000\r\n\t}\r\n\r\n\t/**\r\n\t * This function validates that the value given for \"minimum length\" (when creating a new field) is less than or\r\n\t * equal to the value given for \"maximum length\".\r\n\t */\r\n\tstatic _validateMin: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (\r\n\t\t\ttypeof allValues.maximum_length === \"number\" &&\r\n\t\t\ttypeof value === \"number\" &&\r\n\t\t\tallValues.maximum_length < value\r\n\t\t) {\r\n\t\t\treturn \"Minimum cannot be greater than maximum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\t/**\r\n\t * This function validates that the value given for \"maximum length\" (when creating a new field) is greater than or\r\n\t * equal to the value given for \"minimum length\".\r\n\t */\r\n\tstatic _validateMax: InputValidator<NumberFieldValue> = (value, allValues) => {\r\n\t\tif (typeof value !== \"number\") return null\r\n\r\n\t\tconst { minimum_length: minimumLength } = allValues\r\n\r\n\t\tif (typeof minimumLength !== \"number\") {\r\n\t\t\treturn null\r\n\t\t}\r\n\r\n\t\tif (minimumLength > value) {\r\n\t\t\treturn \"Maximum cannot be less than minimum.\"\r\n\t\t}\r\n\t\treturn null\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\t// min, max\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Minimum length\",\r\n\t\t\t\tdescription: \"Minimum number of characters\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"minimum_length\",\r\n\t\t\t\tminimum: 0,\r\n\t\t\t\tmaximum: 100,\r\n\t\t\t\tformValidators: [this._validateMin],\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"Maximum length\",\r\n\t\t\t\tdescription: \"Maximum number of characters\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum_length\",\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: 5000, // TODO: depends on short vs long text\r\n\t\t\t\tformValidators: [this._validateMax],\r\n\t\t\t\t// TODO: default: 500 (see: \"Short text fields can hold up to 500 characters on a single line.\")\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<string>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\r\n\t\tif (this.minLength) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (this.minLength && (!value || value.length < this.minLength)) {\r\n\t\t\t\t\t// One exception to this rule:\r\n\t\t\t\t\tif (!this.required && !value) return null\r\n\t\t\t\t\treturn `Minimum ${this.minLength} character(s).`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (this.maxLength) {\r\n\t\t\tvalidators.push((value) => {\r\n\t\t\t\tif (typeof value === \"string\" && this.maxLength && value.length > this.maxLength) {\r\n\t\t\t\t\treturn `Maximum ${this.maxLength} character(s).`\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tprotected _serialize(): SerializedStringOrTextField<TIdentifier> {\r\n\t\tif (!this.identifier) {\r\n\t\t\tthrow new Error(\"Field identifier must be set before serializing.\")\r\n\t\t}\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tminimum_length: this.minLength,\r\n\t\t\tmaximum_length: this.maxLength,\r\n\t\t}\r\n\t}\r\n}\r\n","import { TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { useFormikInput, InputWithLabelAndHelpText, InputWithLabel } from \"fields/BaseField\"\r\nimport { StringField } from \"./StringField\"\r\n\r\nexport const StringInput = memo(function StringInput(props: ComponentProps<StringField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst color = useSeverityColor(severity)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextField.Input {...rest} {...fieldProps} type={field.inputType} id={inputId} color={color} />\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedStringField, StringInputType } from \"@overmap-ai/core\"\r\nimport { StringOrTextField, StringOrTextFieldOptions } from \"../StringOrTextField\"\r\nimport { GetInputProps } from \"../../typings\"\r\nimport React from \"react\"\r\nimport { StringInput } from \"./StringInput\"\r\nimport { InputIcon } from \"@overmap-ai/blocks\"\r\n\r\ninterface StringFieldOptions extends Omit<StringOrTextFieldOptions, \"type\"> {\r\n\tinputType?: StringInputType\r\n}\r\n\r\nexport class StringField extends StringOrTextField<\"string\"> {\r\n\tstatic readonly fieldTypeName = \"Short Text\"\r\n\tstatic readonly fieldTypeDescription = \"Short text fields can hold up to 500 characters on a single line.\"\r\n\tpublic readonly inputType: StringInputType\r\n\r\n\tstatic Icon: typeof InputIcon = InputIcon\r\n\r\n\tconstructor(options: StringFieldOptions) {\r\n\t\tconst { inputType = \"text\", ...rest } = options\r\n\t\t// the field supports a max length no larger than 500\r\n\t\tconst maxLength = options.maxLength ? Math.min(500, options.maxLength) : 500\r\n\t\t// the field supports a min length no larger than the max length\r\n\t\tconst minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined\r\n\t\tsuper({ ...rest, maxLength, minLength, type: \"string\" })\r\n\r\n\t\tthis.inputType = inputType\r\n\t}\r\n\r\n\tserialize(): SerializedStringField {\r\n\t\treturn { ...super._serialize(), input_type: this.inputType }\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): StringField {\r\n\t\tif (data.type !== \"string\") throw new Error(\"Type mismatch.\")\r\n\t\tconst { maximum_length, minimum_length, input_type, ...rest } = data\r\n\t\treturn new StringField({ ...rest, maxLength: maximum_length, minLength: minimum_length, inputType: input_type })\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <StringInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { TextArea } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo } from \"react\"\r\nimport { useFormikInput, InputWithLabelAndHelpText, InputWithLabel } from \"fields/BaseField\"\r\nimport { TextField } from \"./TextField\"\r\n\r\nexport const TextInput = memo(function TextInput(props: ComponentProps<TextField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<TextArea {...rest} {...fieldProps} resize=\"vertical\" id={inputId} severity={severity} />\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedTextField } from \"@overmap-ai/core\"\r\nimport { StringOrTextField, StringOrTextFieldOptions } from \"../StringOrTextField\"\r\nimport { GetInputProps } from \"../../typings\"\r\nimport React from \"react\"\r\nimport { RowsIcon } from \"@overmap-ai/blocks\"\r\nimport { TextInput } from \"./TextInput\"\r\n\r\nexport interface TextFieldOptions extends Omit<StringOrTextFieldOptions, \"type\"> {}\r\n\r\nexport class TextField extends StringOrTextField<\"text\"> {\r\n\tstatic readonly fieldTypeName = \"Paragraph\"\r\n\tstatic readonly fieldTypeDescription =\r\n\t\t\"Paragraph fields can hold up to 5000 characters and can have multiple lines.\"\r\n\r\n\tstatic Icon: typeof RowsIcon = RowsIcon\r\n\r\n\tconstructor(options: TextFieldOptions) {\r\n\t\t// the field supports a max length no larger than 5k\r\n\t\tconst maxLength = options.maxLength ? Math.min(5000, options.maxLength) : 5000\r\n\t\t// the field supports a min length no larger than the max length\r\n\t\tconst minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined\r\n\t\tsuper({ ...options, maxLength, minLength, type: \"text\" })\r\n\t}\r\n\r\n\tserialize(): SerializedTextField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField) {\r\n\t\tif (data.type !== \"text\") throw new Error(\"Type mismatch.\")\r\n\t\tconst { maximum_length, minimum_length, ...rest } = data\r\n\t\treturn new TextField({ ...rest, maxLength: maximum_length, minLength: minimum_length })\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <TextInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { Select, SelectItemProps } from \"@overmap-ai/blocks\"\r\nimport { SelectField } from \"./SelectField\"\r\n\r\nexport const SelectInput = memo(function SelectInput(props: ComponentProps<SelectField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange, onBlur } = fieldProps\r\n\r\n\t// Convert SelectFieldOption[] to SelectItemProps[]\r\n\tconst options: SelectItemProps[] = useMemo(\r\n\t\t() => field.options.map((option) => ({ value: option.value, itemContent: option.label })),\r\n\t\t[field.options],\r\n\t)\r\n\r\n\tconst handleChange = useCallback(\r\n\t\t(value: string) => {\r\n\t\t\tonChange(value)\r\n\t\t\tonBlur(value)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<Select\r\n\t\t\t\t\titems={options}\r\n\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\tonValueChange={handleChange}\r\n\t\t\t\t\tplaceholder=\"Select one...\"\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tseverity={severity}\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { UserFormRevision, ISerializedField, SerializedFieldSection, slugify } from \"@overmap-ai/core\"\r\nimport { ISerializedOnlyField } from \"fields\"\r\n\r\nexport const emptySection = (id = \"\", fields = [] as ISerializedOnlyField[]): SerializedFieldSection => ({\r\n\ttype: \"section\",\r\n\tfields,\r\n\tidentifier: id,\r\n\tlabel: null,\r\n\tcondition: null,\r\n\tconditional: false,\r\n})\r\n\r\nexport const wrapRootFieldsWithFieldSection = (\r\n\trevision?: UserFormRevision,\r\n): UserFormRevision<SerializedFieldSection> | undefined => {\r\n\tif (!revision) return undefined\r\n\tconst fields = revision.fields\r\n\tlet pending: ISerializedOnlyField[] = []\r\n\tconst sections: SerializedFieldSection[] = []\r\n\r\n\tfor (const field of fields) {\r\n\t\tif (field.type === \"section\") {\r\n\t\t\tif (pending.length > 0) {\r\n\t\t\t\tsections.push(emptySection(`AUTO_section-${fields.indexOf(field)}`, pending))\r\n\t\t\t\tpending = []\r\n\t\t\t}\r\n\t\t\tsections.push(field)\r\n\t\t} else {\r\n\t\t\tpending.push(field)\r\n\t\t}\r\n\t}\r\n\tif (pending.length > 0) {\r\n\t\tsections.push(emptySection(\"AUTO_section-last\", pending))\r\n\t}\r\n\r\n\t// ensure the description isn't null\r\n\treturn { ...revision, fields: sections, description: revision.description ?? \"\" }\r\n}\r\n\r\nexport function reorder<T>(list: T[], source: number, destination: number): T[] {\r\n\tconst result = Array.from(list)\r\n\tconst [removed] = result.splice(source, 1)\r\n\r\n\tif (!removed) throw new Error(\"Could not find field to reorder.\")\r\n\tresult.splice(destination, 0, removed)\r\n\r\n\treturn result\r\n}\r\n\r\nexport function replace<T>(list: T[], index: number, value: T): T[] {\r\n\tconst result = Array.from(list)\r\n\tresult[index] = value\r\n\treturn result\r\n}\r\n\r\nexport function insert<T>(list: T[] | undefined, index: number, value: T): T[] {\r\n\tconst result = Array.from(list ?? [])\r\n\tresult.splice(index, 0, value)\r\n\treturn result\r\n}\r\n\r\nexport function remove<T>(list: T[], index: number): T[] {\r\n\tconst result = Array.from(list)\r\n\tresult.splice(index, 1)\r\n\treturn result\r\n}\r\n\r\nexport const makeIdentifier = (existing: unknown, label: string): string => {\r\n\tif (typeof existing === \"string\" && existing.length > 0) return existing\r\n\r\n\t// add a timestamp to the end of the slug to make it unique\r\n\tconst now = new Date()\r\n\treturn `${slugify(label)}-${now.getTime()}`\r\n}\r\n\r\nexport const findFieldByIdentifier = (fields: ISerializedField[], identifier?: string): ISerializedField | null => {\r\n\tif (!identifier) return null\r\n\tfor (const field of fields) {\r\n\t\tif (field.type === \"section\") {\r\n\t\t\tconst result = findFieldByIdentifier(field.fields, identifier)\r\n\t\t\tif (result) return result\r\n\t\t} else if (field.identifier === identifier) {\r\n\t\t\treturn field\r\n\t\t}\r\n\t}\r\n\treturn null\r\n}\r\n\r\nexport const makeConditionalSourceFields = (sections: SerializedFieldSection[], index: number) => {\r\n\treturn sections.filter((_, i) => i < index).flatMap((field) => field.fields)\r\n}\r\n\r\nexport const getTakenFieldLabels = (fields: SerializedFieldSection[]): string[] => {\r\n\treturn fields\r\n\t\t.flatMap((field) =>\r\n\t\t\tfield.type === \"section\" ? [...field.fields.map((f) => f.label), field.label] : field.label,\r\n\t\t)\r\n\t\t.filter((id): id is string => id !== null)\r\n}\r\n\r\nexport const incrementFieldLabel = (label: string, takenLabels: string[]): string => {\r\n\t// Append (1), then (2), then (3)... to the end of the label until it is unique\r\n\tlet count = 1\r\n\tlet newLabel = `${label} (${count})`\r\n\twhile (takenLabels.includes(newLabel)) {\r\n\t\tnewLabel = `${label} (${++count})`\r\n\t}\r\n\treturn newLabel\r\n}\r\n","import { Badge, Box, Flex, TextField, useSeverityColor } from \"@overmap-ai/blocks\"\r\nimport { Cross1Icon, PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"../typings.ts\"\r\nimport React, { ChangeEventHandler, memo, useCallback, useMemo, useState } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { DragDropContext, Draggable, Droppable, DropResult } from \"@hello-pangea/dnd\"\r\nimport { IconButton } from \"@overmap-ai/blocks\"\r\nimport { MultiStringField } from \"./MultiStringField\"\r\nimport { SelectFieldOption } from \"@overmap-ai/core\"\r\nimport { remove, reorder } from \"builder/utils.ts\"\r\n\r\n/**\r\n * Allows the user to create an array of unique strings and customize the order.\r\n * User to generate options for the Select field.\r\n */\r\nexport const MultiStringInput = memo(function MultiStringInput(props: ComponentProps<MultiStringField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput<MultiStringField>(props)\r\n\tconst color = useSeverityColor(severity)\r\n\tconst value = useMemo(() => (Array.isArray(fieldProps.value) ? fieldProps.value : []), [fieldProps.value])\r\n\tconst { onChange, onBlur } = fieldProps\r\n\tconst droppableId = `${inputId}-droppable`\r\n\tconst { disabled } = rest\r\n\r\n\tconst [intermediateValue, setIntermediateValue] = useState(\"\")\r\n\tconst [internalError, setInternalError] = useState(\"\")\r\n\r\n\tconst updatedHelpText = internalError || helpText\r\n\tconst updatedColor = internalError ? \"red\" : color\r\n\r\n\tconst setValueAndTouched = useCallback(\r\n\t\t(newValue: SelectFieldOption[]) => {\r\n\t\t\tonChange(newValue)\r\n\t\t\tonBlur(newValue)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\t// handle change to the input\r\n\tconst handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(\r\n\t\t(e) => {\r\n\t\t\tif (value.findIndex((option: SelectFieldOption): boolean => option.value === e.target.value.trim()) >= 0) {\r\n\t\t\t\t// There is already an option with this value.\r\n\t\t\t\tsetInternalError(\"All options must be unique\")\r\n\t\t\t} else if (!e.target.value) {\r\n\t\t\t\tsetInternalError(\"Option cannot be empty\")\r\n\t\t\t} else {\r\n\t\t\t\tsetInternalError(\"\")\r\n\t\t\t}\r\n\t\t\tsetIntermediateValue(e.target.value)\r\n\t\t},\r\n\t\t[setIntermediateValue, value],\r\n\t)\r\n\r\n\tconst addOption = useCallback(() => {\r\n\t\tif (internalError) return\r\n\r\n\t\tif (!intermediateValue.trim()) {\r\n\t\t\treturn setInternalError(\"Option cannot be empty\")\r\n\t\t}\r\n\r\n\t\tconst trimmedValue = intermediateValue.trim()\r\n\t\t// value and label are the same for user-defined options.\r\n\t\tsetValueAndTouched([...value, { value: trimmedValue, label: trimmedValue }])\r\n\t\tsetIntermediateValue(\"\")\r\n\t}, [intermediateValue, internalError, setValueAndTouched, value])\r\n\r\n\t// moves the intermediate value into the value array\r\n\tconst handleKeyDown = useCallback(\r\n\t\t(e: React.KeyboardEvent<HTMLInputElement>) => {\r\n\t\t\tif (e.key === \"Enter\") {\r\n\t\t\t\t// don't try and submit the form\r\n\t\t\t\te.preventDefault()\r\n\r\n\t\t\t\taddOption()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[addOption],\r\n\t)\r\n\r\n\t// delete an existing option\r\n\tconst handleDeleteOption = useCallback(\r\n\t\t(index: number) => {\r\n\t\t\tsetValueAndTouched(remove(value, index))\r\n\t\t},\r\n\t\t[value, setValueAndTouched],\r\n\t)\r\n\r\n\t// change the order of existing options\r\n\tconst handleDragEnd = useCallback(\r\n\t\t(result: DropResult) => {\r\n\t\t\tif (!result.destination) return\r\n\r\n\t\t\tconst sourceIndex = result.source.index\r\n\t\t\tconst destinationIndex = result.destination.index\r\n\r\n\t\t\tsetValueAndTouched(reorder(value, sourceIndex, destinationIndex))\r\n\t\t},\r\n\t\t[setValueAndTouched, value],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<DragDropContext onDragEnd={handleDragEnd}>\r\n\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t<InputWithLabelAndHelpText helpText={updatedHelpText} severity={severity}>\r\n\t\t\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t\t\t{/* Do not show input if disabled and options are defined */}\r\n\t\t\t\t\t\t{(!disabled || value.length === 0) && (\r\n\t\t\t\t\t\t\t<Flex gap=\"2\">\r\n\t\t\t\t\t\t\t\t<Box grow=\"1\">\r\n\t\t\t\t\t\t\t\t\t<TextField.Input\r\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Press enter to add a new option\"\r\n\t\t\t\t\t\t\t\t\t\t{...rest}\r\n\t\t\t\t\t\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\t\t\t\t\t\tvalue={intermediateValue}\r\n\t\t\t\t\t\t\t\t\t\tonChange={handleChange}\r\n\t\t\t\t\t\t\t\t\t\tonKeyDown={handleKeyDown}\r\n\t\t\t\t\t\t\t\t\t\tid={inputId}\r\n\t\t\t\t\t\t\t\t\t\tcolor={updatedColor}\r\n\t\t\t\t\t\t\t\t\t\t// disable default onBlur behavior due to its error handling\r\n\t\t\t\t\t\t\t\t\t\tonBlur={undefined}\r\n\t\t\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\t\t</Box>\r\n\t\t\t\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\t\t\t\taria-label=\"Add option\"\r\n\t\t\t\t\t\t\t\t\tdisabled={!!internalError || disabled}\r\n\t\t\t\t\t\t\t\t\tonClick={addOption}\r\n\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t<PlusIcon />\r\n\t\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</InputWithLabel>\r\n\t\t\t\t</InputWithLabelAndHelpText>\r\n\t\t\t\t<Droppable droppableId={droppableId}>\r\n\t\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t\t<Flex {...droppableProvided.droppableProps} ref={droppableProvided.innerRef} direction=\"column\">\r\n\t\t\t\t\t\t\t{value.map((option: SelectFieldOption, index) => (\r\n\t\t\t\t\t\t\t\t<Draggable\r\n\t\t\t\t\t\t\t\t\tdraggableId={`${option.value}-draggable`}\r\n\t\t\t\t\t\t\t\t\tindex={index}\r\n\t\t\t\t\t\t\t\t\tkey={option.value}\r\n\t\t\t\t\t\t\t\t\tisDragDisabled={disabled}\r\n\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t{({ draggableProps, dragHandleProps, innerRef }) => (\r\n\t\t\t\t\t\t\t\t\t\t<Flex\r\n\t\t\t\t\t\t\t\t\t\t\t{...dragHandleProps}\r\n\t\t\t\t\t\t\t\t\t\t\t{...draggableProps}\r\n\t\t\t\t\t\t\t\t\t\t\tref={innerRef}\r\n\t\t\t\t\t\t\t\t\t\t\tgap=\"2\"\r\n\t\t\t\t\t\t\t\t\t\t\talign=\"center\"\r\n\t\t\t\t\t\t\t\t\t\t\tjustify=\"between\"\r\n\t\t\t\t\t\t\t\t\t\t\tmb=\"1\"\r\n\t\t\t\t\t\t\t\t\t\t\tasChild\r\n\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t<Badge color=\"gray\" size=\"2\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<span>{option.label}</span>\r\n\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Delete option\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tseverity=\"info\"\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tdisabled={disabled}\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => handleDeleteOption(index)}\r\n\t\t\t\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Cross1Icon />\r\n\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t\t\t\t\t\t</Badge>\r\n\t\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t</Draggable>\r\n\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t)}\r\n\t\t\t\t</Droppable>\r\n\t\t\t</Flex>\r\n\t\t</DragDropContext>\r\n\t)\r\n})\r\n","import { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { ISerializedField, SelectFieldOption, SerializedMultiStringField } from \"@overmap-ai/core\"\r\nimport { MultiStringInput } from \"./MultiStringInput\"\r\nimport { GetInputProps, InputFieldLevelValidator } from \"../typings.ts\"\r\nimport { ReactNode } from \"react\"\r\nimport { ListBulletIcon } from \"@overmap-ai/blocks\"\r\n\r\ntype MultiStringFieldOptions = ChildFieldOptions<SelectFieldOption[]> & {\r\n\tminimum_length?: number\r\n\tmaximum_length?: number\r\n}\r\n\r\n/**\r\n * A field that lets the user input multiple strings. Each string must be unique. Useful for things like:\r\n * - Specifying the options of a SelectField (used in `SelectField.getFieldCreationSchema`\r\n * - Listing serial numbers and similar\r\n */\r\nexport class MultiStringField extends BaseField<SelectFieldOption[], \"multi-string\"> {\r\n\tstatic readonly fieldTypeName = \"Multi-string\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to provide multiple unique strings.\"\r\n\tpublic readonly minLength: number\r\n\tpublic readonly maxLength: number\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof ListBulletIcon = ListBulletIcon\r\n\r\n\tconstructor(options: MultiStringFieldOptions) {\r\n\t\tconst { minimum_length, maximum_length, ...rest } = options\r\n\t\tsuper({ ...rest, type: \"multi-string\" })\r\n\t\tthis.minLength = minimum_length ?? 0\r\n\t\tthis.maxLength = maximum_length ?? Infinity\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(\r\n\t\tevent: React.ChangeEvent<HTMLInputElement> | SelectFieldOption[],\r\n\t): SelectFieldOption[] {\r\n\t\tif (Array.isArray(event)) return event\r\n\r\n\t\tthrow new Error(\"Expected an array.\")\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <MultiStringInput field={this} {...props} />\r\n\t}\r\n\r\n\tserialize(): SerializedMultiStringField {\r\n\t\treturn { ...super._serialize(), minimum_length: this.minLength, maximum_length: this.maxLength }\r\n\t}\r\n\r\n\tprotected isBlank(value: SelectFieldOption[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tpublic getFieldValidators(): InputFieldLevelValidator<SelectFieldOption[]>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (Array.isArray(value) && value.length < this.minLength) {\r\n\t\t\t\treturn `Must have at least ${this.minLength} options.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (Array.isArray(value) && value.length > this.maxLength) {\r\n\t\t\t\treturn `Must have at most ${this.maxLength} options.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): MultiStringField {\r\n\t\tif (data.type !== \"multi-string\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new MultiStringField(data)\r\n\t}\r\n}\r\n","import { FieldValue, SelectFieldOption } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { MultiStringField } from \"../MultiStringField\"\r\n\r\n/**\r\n * The options passed to the constructor of SelectField.\r\n */\r\nexport interface BaseSelectFieldOptions<TValue, TIdentifier extends \"select\" | \"multi-select\">\r\n\textends ChildFieldOptions<TValue> {\r\n\t/** When instantiating a SelectField, you can either pass an array of strings or an array of objects. User-created\r\n\t * forms only support arrays of strings. For more complex internal purposes, you can provide an array of objects\r\n\t * where the `label` is the text to display to the user and the `value` is the value handled by Formik.*/\r\n\toptions: string[] | SelectFieldOption[]\r\n\ttype: TIdentifier\r\n}\r\n\r\nexport abstract class BaseSelectField<\r\n\tTValue extends FieldValue,\r\n\tTIdentifier extends \"select\" | \"multi-select\",\r\n> extends BaseField<TValue, TIdentifier> {\r\n\tpublic readonly options: SelectFieldOption[]\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tprotected constructor(options: BaseSelectFieldOptions<TValue, TIdentifier>) {\r\n\t\tsuper(options)\r\n\t\t// SelectField supports two types of options: string[] and { value: string, identifier: string }[]. If\r\n\t\tconst encounteredIds: Set<string> = new Set()\r\n\t\tthis.options = options.options.map((option): SelectFieldOption => {\r\n\t\t\tif (typeof option === \"string\") {\r\n\t\t\t\toption = { label: option, value: option }\r\n\t\t\t}\r\n\t\t\tencounteredIds.add(option.label)\r\n\t\t\treturn option\r\n\t\t})\r\n\t\tif (encounteredIds.size !== options.options.length) {\r\n\t\t\t// TODO: Determine if we need to prevent this.\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.error(\r\n\t\t\t\t`${\r\n\t\t\t\t\toptions.options.length - encounteredIds.size\r\n\t\t\t\t} duplicate identifiers found in options. This may cause unexpected behavior. Options:`,\r\n\t\t\t\toptions.options,\r\n\t\t\t)\r\n\t\t}\r\n\t}\r\n\r\n\tprotected _serialize() {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\toptions: this.options,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew MultiStringField({\r\n\t\t\t\tlabel: \"Options\",\r\n\t\t\t\tdescription: \"List possible options for the user to select from.\",\r\n\t\t\t\trequired: true,\r\n\t\t\t\tidentifier: \"options\",\r\n\t\t\t\tminimum_length: 2,\r\n\t\t\t\tmaximum_length: 20,\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n}\r\n","import { ISerializedField, SelectFieldOptionValue, SerializedSelectField } from \"@overmap-ai/core\"\r\nimport { ReactNode } from \"react\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport { SelectInput } from \"./SelectInput\"\r\nimport { BaseSelectField, BaseSelectFieldOptions } from \"./BaseSelectField\"\r\nimport { DropdownMenuIcon } from \"@overmap-ai/blocks\"\r\n\r\n/**\r\n * The options passed to the constructor of SelectField.\r\n */\r\nexport type SelectFieldOptions = Omit<BaseSelectFieldOptions<SelectFieldOptionValue, \"select\">, \"type\">\r\n\r\nexport class SelectField extends BaseSelectField<SelectFieldOptionValue, \"select\"> {\r\n\tstatic readonly fieldTypeName = \"Dropdown\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to select a single option from a list of options.\"\r\n\r\n\tstatic Icon: typeof DropdownMenuIcon = DropdownMenuIcon\r\n\r\n\tpublic constructor(options: SelectFieldOptions) {\r\n\t\tsuper({ ...options, type: \"select\" })\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement> | string): SelectFieldOptionValue {\r\n\t\tif (typeof event === \"string\") return event\r\n\t\treturn event.target.value\r\n\t}\r\n\r\n\tserialize(): SerializedSelectField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): SelectField {\r\n\t\tif (data.type !== \"select\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new SelectField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <SelectInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from \"../BaseField\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { ComponentProps } from \"../typings\"\r\nimport { MultiSelect } from \"@overmap-ai/blocks\"\r\nimport { MultiSelectField } from \"./MultiSelectField\"\r\n\r\nconst parseValueToArray = (value: string[] | string): string[] => {\r\n\tif (!value) return []\r\n\tif (Array.isArray(value)) return value\r\n\treturn [value]\r\n}\r\n\r\nexport const MultiSelectInput = memo(function MultiSelectInput(props: ComponentProps<MultiSelectField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange, onBlur } = fieldProps\r\n\tconst value = useMemo(() => parseValueToArray(fieldProps.value), [fieldProps.value])\r\n\r\n\tconst handleChange = useCallback(\r\n\t\t(value: string[]) => {\r\n\t\t\tonChange(value)\r\n\t\t\tonBlur(value)\r\n\t\t},\r\n\t\t[onChange, onBlur],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<InputWithLabelAndHelpText helpText={helpText} severity={severity}>\r\n\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t<MultiSelect\r\n\t\t\t\t\tvalue={value}\r\n\t\t\t\t\tonValueChange={handleChange}\r\n\t\t\t\t\toptions={field.options}\r\n\t\t\t\t\tname={fieldProps.name}\r\n\t\t\t\t\tplaceholder=\"Select one or more...\"\r\n\t\t\t\t\tid={inputId}\r\n\t\t\t\t\tseverity={severity}\r\n\t\t\t\t\t{...rest}\r\n\t\t\t\t/>\r\n\t\t\t</InputWithLabel>\r\n\t\t</InputWithLabelAndHelpText>\r\n\t)\r\n})\r\n","import { ISerializedField, SelectFieldOptionValue, SerializedMultiSelectField } from \"@overmap-ai/core\"\r\nimport { ReactNode } from \"react\"\r\nimport { GetInputProps } from \"../typings\"\r\nimport { BaseSelectField, BaseSelectFieldOptions } from \"./BaseSelectField\"\r\nimport { MultiSelectInput } from \"./MultiSelectInput\"\r\nimport { CheckboxIcon } from \"@overmap-ai/blocks\"\r\n\r\n/**\r\n * The options passed to the constructor of MultiSelectField.\r\n */\r\nexport type MultiSelectFieldOptions = Omit<BaseSelectFieldOptions<SelectFieldOptionValue[], \"multi-select\">, \"type\">\r\n\r\nexport class MultiSelectField extends BaseSelectField<SelectFieldOptionValue[], \"multi-select\"> {\r\n\tstatic readonly fieldTypeName = \"Multi-select\"\r\n\tstatic readonly fieldTypeDescription = \"Allows the user to select a multiple options from a list of options.\"\r\n\r\n\tstatic Icon: typeof CheckboxIcon = CheckboxIcon\r\n\r\n\tpublic constructor(options: MultiSelectFieldOptions) {\r\n\t\tsuper({ ...options, type: \"multi-select\" })\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: React.ChangeEvent<HTMLInputElement> | string[]): string[] {\r\n\t\tif (Array.isArray(event)) return event\r\n\t\tthrow new Error(\"Expected an array.\")\r\n\t}\r\n\r\n\tprotected isBlank(value: SelectFieldOptionValue[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tserialize(): SerializedMultiSelectField {\r\n\t\treturn super._serialize()\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): MultiSelectField {\r\n\t\tif (data.type !== \"multi-select\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new MultiSelectField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <MultiSelectInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { memo, useMemo } from \"react\"\r\nimport { deserialize, useFieldInput } from \"../../index.ts\"\r\nimport { useField } from \"formik\"\r\nimport { FieldInputClonerProps } from \"./typings.ts\"\r\n\r\n/**\r\n * Used to dynamically \"clone\" a field's input for use in conditional sections. When a field is selected for a\r\n * condition, we need to render the same input in the condition section, so the user can input a value for the\r\n * condition.\r\n */\r\nexport const FieldInputCloner = memo(function FieldInputCloner({ field, ...props }: FieldInputClonerProps) {\r\n\tconst [{ value: identifier }] = useField(field.options.clonedFieldIdentifier)\r\n\r\n\tconst deserializedField = useMemo(() => {\r\n\t\tconst options = field.options.getFieldToClone(identifier)\r\n\t\tif (!options) return null\r\n\t\treturn deserialize(options)\r\n\t}, [field.options, identifier])\r\n\r\n\treturn useFieldInput(deserializedField, props)\r\n})\r\n","import { FieldTypeIdentifier, FieldValue } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { FC, ReactNode } from \"react\"\r\nimport { GetInputProps, ISerializedOnlyField } from \"../typings\"\r\n\r\nexport interface CustomFieldOptions<TValue> extends ChildFieldOptions<TValue> {}\r\n\r\nexport class CustomField<\r\n\tTValue extends FieldValue,\r\n\t/** The options passed to constructor */\r\n\tTFieldOptions extends CustomFieldOptions<TValue>,\r\n\t/** The props passed to the custom component */\r\n\tTComponentProps extends GetInputProps<CustomField<TValue, TFieldOptions, TComponentProps>>,\r\n\tTIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier,\r\n> extends BaseField<TValue, TIdentifier> {\r\n\tstatic readonly fieldTypeName = \"Custom\"\r\n\tstatic readonly fieldTypeDescription = \"Allows re-rendering of field already in the form\"\r\n\r\n\tpublic readonly Component: FC<TComponentProps>\r\n\r\n\t// identifier of the field whose value is the label of the field to re-render\r\n\tpublic readonly options: TFieldOptions\r\n\r\n\tconstructor(options: TFieldOptions, Component: FC<TComponentProps>) {\r\n\t\tsuper({ ...options, type: \"custom\" })\r\n\t\tthis.options = options\r\n\t\tthis.Component = Component\r\n\t}\r\n\r\n\tserialize(): ISerializedOnlyField {\r\n\t\tthrow new Error(\"Serializing only supported for public input types.\")\r\n\t}\r\n\r\n\tgetInput(props: TComponentProps): ReactNode {\r\n\t\tconst CustomInput = this.Component\r\n\t\treturn <CustomInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { CustomField, CustomFieldOptions } from \"../CustomField\"\r\nimport { FieldValue, ISerializedField } from \"@overmap-ai/core\"\r\nimport { FieldInputCloner, FieldInputClonerProps } from \"./index\"\r\n\r\nexport interface FieldInputClonerFieldOptions extends CustomFieldOptions<unknown> {\r\n\t/** Given an identifier, should return the options of the field with the\r\n\t * corresponding identifier (the field being cloned) */\r\n\tgetFieldToClone: (identifier: string) => ISerializedField | null\r\n\t/** The identifier of the field to clone */\r\n\tclonedFieldIdentifier: string\r\n}\r\n\r\n/**\r\n * The purpose of this is to display a value input field in the condition of a section. The input field will look like\r\n * the input field of the condition. For example, when specifying the conditional value of a SelectField, a SelectInput\r\n * will be rendered.\r\n */\r\nexport class FieldInputClonerField extends CustomField<\r\n\tFieldValue,\r\n\tFieldInputClonerFieldOptions,\r\n\tFieldInputClonerProps\r\n> {\r\n\tconstructor(options: FieldInputClonerFieldOptions) {\r\n\t\tsuper(options, FieldInputCloner)\r\n\t}\r\n}\r\n","import { ComponentProps, isConditionMet, useFieldInputs } from \"fields\"\r\nimport { memo, useEffect, useMemo } from \"react\"\r\nimport { Card, Flex, Heading, Text } from \"@overmap-ai/blocks\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { FieldSection } from \".\"\r\nimport get from \"lodash.get\"\r\nimport styles from \"styling.module.sass\"\r\n\r\n/**\r\n * Used by FieldSection to render a section of fields.\r\n */\r\nexport const FieldSectionLayout = memo(function FieldSectionLayout(props: ComponentProps<FieldSection>) {\r\n\tconst { field: section, ...rest } = props\r\n\tconst { label, description, fields, condition } = section\r\n\tconst { values, setFieldValue } = useFormikContext()\r\n\r\n\tconst conditionValue = condition?.identifier ? get(values, condition.identifier) : undefined\r\n\t// sections without a condition are always met\r\n\tconst conditionMet = useMemo(() => isConditionMet(condition, conditionValue), [condition, conditionValue])\r\n\r\n\tuseEffect(() => {\r\n\t\t// reset all fields in section if condition is not met\r\n\t\tif (!conditionMet) {\r\n\t\t\tfor (const childField of fields) {\r\n\t\t\t\tsetFieldValue(childField.getId(), \"\").then()\r\n\t\t\t}\r\n\t\t}\r\n\t}, [conditionMet, fields, setFieldValue])\r\n\r\n\tconst inputs = useFieldInputs(fields, rest)\r\n\r\n\t// if condition is not met, do not render section\r\n\tif (!conditionMet) {\r\n\t\treturn null\r\n\t}\r\n\r\n\t// if no label is provided, only render fields without the card wrapper\r\n\tif (!label) {\r\n\t\treturn inputs\r\n\t}\r\n\r\n\treturn (\r\n\t\t<Card>\r\n\t\t\t<Flex direction=\"column\" gap=\"3\">\r\n\t\t\t\t<Flex direction=\"column\">\r\n\t\t\t\t\t<Heading as=\"h3\" size=\"3\">\r\n\t\t\t\t\t\t{label}\r\n\t\t\t\t\t</Heading>\r\n\t\t\t\t\t<Text className={styles.description}>{description}</Text>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{inputs}\r\n\t\t\t</Flex>\r\n\t\t</Card>\r\n\t)\r\n})\r\n","import {\r\n\tBaseSerializedObject,\r\n\tISerializedField,\r\n\tSelectFieldOption,\r\n\tSerializedCondition,\r\n\tSerializedFieldSection,\r\n} from \"@overmap-ai/core\"\r\nimport { BooleanField, deserializeField, GetInputProps, SelectField } from \"fields\"\r\nimport { FieldInputClonerField, FieldInputClonerFieldOptions } from \"../CustomField/FieldInputClonerField\"\r\nimport { AnyField } from \"fields/typings\"\r\nimport { BaseFormElement } from \"fields/BaseField\"\r\nimport React from \"react\"\r\nimport { FieldSectionLayout } from \"./FieldSectionLayout\"\r\nimport get from \"lodash.get\"\r\nimport set from \"lodash.set\"\r\nimport { Form } from \"typings\"\r\n\r\ninterface FieldSectionOptions extends Omit<BaseSerializedObject, \"type\"> {\r\n\tlabel?: string | null\r\n\tconditional?: boolean\r\n\tcondition?: SerializedCondition | null\r\n\tfields: AnyField[]\r\n}\r\n\r\nexport class FieldSection extends BaseFormElement<\"section\"> {\r\n\tstatic readonly fieldTypeName = \"Section\"\r\n\tstatic readonly fieldTypeDescription =\r\n\t\t\"Sections can be useful for grouping fields together. They can also be conditionally shown or hidden.\"\r\n\r\n\tpublic readonly label: string | null\r\n\tpublic readonly fields: AnyField[]\r\n\tpublic readonly condition: SerializedCondition | null\r\n\r\n\tpublic constructor(options: FieldSectionOptions) {\r\n\t\tconst { label = null, fields, condition = null, conditional, ...base } = options\r\n\r\n\t\tsuper({ ...base, type: \"section\" })\r\n\t\tthis.fields = fields\r\n\t\tthis.condition = condition\r\n\t\tthis.label = label\r\n\r\n\t\t// handle case when condition is removed\r\n\t\tif (conditional === false) {\r\n\t\t\tthis.condition = null\r\n\t\t}\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema(options: ISerializedField[]): BaseFormElement[] {\r\n\t\t// conditions require at least one field to be present\r\n\t\tif (options.length === 0) return []\r\n\r\n\t\treturn [\r\n\t\t\tnew BooleanField({\r\n\t\t\t\tlabel: \"Conditional\",\r\n\t\t\t\tdescription: \"Conditionally show or hide this section.\",\r\n\t\t\t\tidentifier: \"conditional\",\r\n\t\t\t\trequired: false,\r\n\t\t\t}),\r\n\t\t\t// Declare a section that will hold options for the condition (if any).\r\n\t\t\tnew FieldSection({\r\n\t\t\t\tlabel: \"Conditional settings\",\r\n\t\t\t\tidentifier: \"conditional-settings\",\r\n\t\t\t\t// This section will only be rendered if the above \"Conditional\" field is checked.\r\n\t\t\t\tcondition: {\r\n\t\t\t\t\tidentifier: \"conditional\",\r\n\t\t\t\t\tvalue: true,\r\n\t\t\t\t},\r\n\t\t\t\t// These are the options of the condition.\r\n\t\t\t\tfields: [\r\n\t\t\t\t\t// Declare a select field that will be used to select the field against which we will check the\r\n\t\t\t\t\t// condition. This must be selected before the next field is rendered.\r\n\t\t\t\t\tnew SelectField({\r\n\t\t\t\t\t\tlabel: \"Field\",\r\n\t\t\t\t\t\tdescription: \"The field to use for the condition.\",\r\n\t\t\t\t\t\t// The options (for the field against which we will check the condition) are all the labels of\r\n\t\t\t\t\t\t// the fields in the previous section(s) (or fields declared before with no section) that\r\n\t\t\t\t\t\t// support conditions. We pass in both the label and the identifier of each supported field. The\r\n\t\t\t\t\t\t// identifier becomes the value of the option.\r\n\t\t\t\t\t\toptions: options\r\n\t\t\t\t\t\t\t.map((option): SelectFieldOption | null => {\r\n\t\t\t\t\t\t\t\t// If the field doesn't have a label, it can't be used for a condition.\r\n\t\t\t\t\t\t\t\tif (!option.label) return null\r\n\t\t\t\t\t\t\t\t// Upload fields cannot be used for conditions.\r\n\t\t\t\t\t\t\t\tif (option.type === \"upload\") return null\r\n\r\n\t\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t\tlabel: option.label,\r\n\t\t\t\t\t\t\t\t\tvalue: option.identifier,\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t.filter((option): option is SelectFieldOption => !!option),\r\n\t\t\t\t\t\tidentifier: \"condition.identifier\",\r\n\t\t\t\t\t\trequired: true,\r\n\t\t\t\t\t}),\r\n\t\t\t\t\t// Declare a custom field that will be used to input a value for the condition. The value of the\r\n\t\t\t\t\t// conditional field selected in the previous step must be equal to the value the user inputs into\r\n\t\t\t\t\t// this field for the section to be rendered.\r\n\t\t\t\t\tnew FieldInputClonerField({\r\n\t\t\t\t\t\tlabel: \"Value\",\r\n\t\t\t\t\t\tidentifier: \"condition.value\",\r\n\t\t\t\t\t\trequired: true,\r\n\t\t\t\t\t\tclonedFieldIdentifier: \"condition.identifier\",\r\n\t\t\t\t\t\tgetFieldToClone(identifier: string) {\r\n\t\t\t\t\t\t\tif (!identifier) {\r\n\t\t\t\t\t\t\t\t// No field has been chosen yet.\r\n\t\t\t\t\t\t\t\treturn null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t// Find the field options with a matching identifier.\r\n\t\t\t\t\t\t\tconst option = options.find((option) => option.identifier === identifier)\r\n\t\t\t\t\t\t\tif (!option) {\r\n\t\t\t\t\t\t\t\t// This is unexpected, but not fatal.\r\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\t\t\t\t\tconsole.error(\"Could not find field with identifier\", identifier)\r\n\t\t\t\t\t\t\t\treturn null\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t...option,\r\n\t\t\t\t\t\t\t\t// Override some options to make it make sense in the context and to make it work with the framework.\r\n\t\t\t\t\t\t\t\tlabel: \"Value\",\r\n\t\t\t\t\t\t\t\tidentifier: \"condition.value\",\r\n\t\t\t\t\t\t\t\tdescription: \"The value to compare against.\",\r\n\t\t\t\t\t\t\t\trequired: option.type !== \"boolean\",\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t} satisfies FieldInputClonerFieldOptions),\r\n\t\t\t\t],\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): FieldSection {\r\n\t\tif (data.type !== \"section\") throw new Error(\"Invalid type\")\r\n\t\tconst fields = data.fields?.map(deserializeField) ?? []\r\n\t\treturn new FieldSection({ ...data, fields })\r\n\t}\r\n\r\n\tconditional(): this is { condition: SerializedCondition } {\r\n\t\treturn this.condition !== null\r\n\t}\r\n\r\n\tserialize(): SerializedFieldSection {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\tlabel: this.label,\r\n\t\t\tcondition: this.condition,\r\n\t\t\tconditional: this.conditional(),\r\n\t\t\tfields: this.fields.map((field) => field.serialize()),\r\n\t\t}\r\n\t}\r\n\r\n\tgetErrors(allValues: Form): Record<string, string> {\r\n\t\tconst errors: Record<string, string> = {}\r\n\t\tfor (const field of this.fields) {\r\n\t\t\tconst id = field.getId()\r\n\t\t\tconst error = field.getError(get(allValues, id), allValues)\r\n\t\t\tif (error) {\r\n\t\t\t\tset(errors, field.getId(), error)\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn errors\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): React.ReactNode {\r\n\t\treturn <FieldSectionLayout field={this} {...props} />\r\n\t}\r\n}\r\n","export const convertBytesToLargestUnit = (bytes: number) => {\r\n\t// all files must be less than 50 MB\r\n\tconst units = [\"byte\", \"kilobyte\", \"megabyte\"]\r\n\tlet sizeInUnit = bytes\r\n\tlet unitIndex = 0\r\n\twhile (sizeInUnit > 1024 && unitIndex < units.length - 1) {\r\n\t\tsizeInUnit /= 1024\r\n\t\tunitIndex++\r\n\t}\r\n\tconst formatter = new Intl.NumberFormat([], { maximumFractionDigits: 2, style: \"unit\", unit: units[unitIndex] })\r\n\treturn formatter.format(sizeInUnit)\r\n}\r\n","import { Box, Button, Card, Flex, IconButton, useSeverityColor, Cross1Icon, Text, UploadIcon } from \"@overmap-ai/blocks\"\r\nimport { ComponentProps } from \"fields/typings\"\r\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from \"react\"\r\nimport { InputWithLabel, InputWithLabelAndHelpText } from \"../BaseField\"\r\nimport { useFormikInput } from \"../BaseField\"\r\nimport { UploadField } from \"./UploadField\"\r\nimport styles from \"./UploadInput.module.sass\"\r\nimport { convertBytesToLargestUnit } from \"./utils\"\r\n\r\nexport const NumberInput = memo(function NumberInput(props: ComponentProps<UploadField>) {\r\n\tconst [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props)\r\n\tconst { onChange } = fieldProps\r\n\tconst color = useSeverityColor(severity)\r\n\tconst input = useRef<HTMLInputElement>(null)\r\n\tconst { value } = fieldProps\r\n\r\n\tconst updatedHelpText = useMemo(() => {\r\n\t\tif (helpText) return helpText\r\n\t\tif (field.maxFileSize) {\r\n\t\t\tconst size = convertBytesToLargestUnit(field.maxFileSize)\r\n\t\t\treturn `Maximum file size: ${size}`\r\n\t\t}\r\n\t\treturn null\r\n\t}, [field.maxFileSize, helpText])\r\n\r\n\tconst handleClick = useCallback(() => {\r\n\t\tinput.current?.click()\r\n\t}, [])\r\n\r\n\tconst handleRemove = useCallback(\r\n\t\t(index: number) => {\r\n\t\t\tconst files = [...value]\r\n\t\t\tfiles.splice(index, 1)\r\n\r\n\t\t\tconst event = { target: { files } }\r\n\t\t\tonChange(event)\r\n\t\t},\r\n\t\t[value, onChange],\r\n\t)\r\n\r\n\tconst multipleButtonText = value ? \"Select new files\" : \"Select files\"\r\n\tconst singleButtonText = value ? \"Select new file\" : \"Select a file\"\r\n\tconst buttonText = field.maxFiles > 1 ? multipleButtonText : singleButtonText\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t<InputWithLabelAndHelpText helpText={updatedHelpText} severity={severity}>\r\n\t\t\t\t<InputWithLabel severity={severity} inputId={inputId} labelId={labelId} label={label}>\r\n\t\t\t\t\t<Flex direction=\"row\" gap=\"2\">\r\n\t\t\t\t\t\t<Box width=\"max-content\" asChild>\r\n\t\t\t\t\t\t\t<Button {...rest} onClick={handleClick}>\r\n\t\t\t\t\t\t\t\t<UploadIcon /> {buttonText}\r\n\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t</Box>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t\t<input\r\n\t\t\t\t\t\t{...rest}\r\n\t\t\t\t\t\ttype=\"file\"\r\n\t\t\t\t\t\tref={input}\r\n\t\t\t\t\t\tid={inputId}\r\n\t\t\t\t\t\taccept={field.extensions?.join(\",\")}\r\n\t\t\t\t\t\tmultiple={field.maxFiles > 1}\r\n\t\t\t\t\t\tcolor={color}\r\n\t\t\t\t\t\tstyle={{ display: \"none\" }}\r\n\t\t\t\t\t\t{...fieldProps}\r\n\t\t\t\t\t\tvalue=\"\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</InputWithLabel>\r\n\t\t\t</InputWithLabelAndHelpText>\r\n\t\t\t{Array.isArray(value) && value.length > 0 && (\r\n\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t{value.map((file, index) => (\r\n\t\t\t\t\t\t<DisplayFile\r\n\t\t\t\t\t\t\tkey={index}\r\n\t\t\t\t\t\t\tfield={field}\r\n\t\t\t\t\t\t\tfile={file}\r\n\t\t\t\t\t\t\tonRemove={() => handleRemove(index)}\r\n\t\t\t\t\t\t\tdisabled={rest.disabled}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t))}\r\n\t\t\t\t</Flex>\r\n\t\t\t)}\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\ninterface DisplayFileProps {\r\n\tfile: File | Promise<File>\r\n\tfield: UploadField\r\n\tdisabled?: boolean\r\n\tonRemove: () => void\r\n}\r\n\r\nconst DisplayFile = memo(function DisplayFile({ file, field, onRemove, disabled }: DisplayFileProps) {\r\n\tconst [resolvedFile, setResolvedFile] = useState<File | null>(null)\r\n\tconst error = useMemo(() => resolvedFile && field.getError([resolvedFile]), [field, resolvedFile])\r\n\tconst { url, name, size } = useMemo(() => {\r\n\t\tlet url: string | null = null\r\n\t\tlet name: string\r\n\t\tlet size: string\r\n\t\t// if the file is an image, create a url for it\r\n\t\tif (resolvedFile?.type.startsWith(\"image/\")) {\r\n\t\t\turl = URL.createObjectURL(resolvedFile)\r\n\t\t}\r\n\t\tif (resolvedFile) {\r\n\t\t\tname = resolvedFile.name\r\n\t\t\tsize = convertBytesToLargestUnit(resolvedFile.size)\r\n\t\t} else {\r\n\t\t\tname = \"Downloading...\"\r\n\t\t\tsize = \"...\"\r\n\t\t}\r\n\t\treturn { url, name, size }\r\n\t}, [resolvedFile])\r\n\r\n\tuseEffect(() => {\r\n\t\tif (file instanceof Promise) {\r\n\t\t\tfile.then(setResolvedFile)\r\n\t\t} else {\r\n\t\t\tsetResolvedFile(file)\r\n\t\t}\r\n\t}, [file])\r\n\r\n\treturn (\r\n\t\t<Card>\r\n\t\t\t<Flex direction={{ initial: \"column\", sm: \"row\" }} gap=\"3\" justify=\"between\">\r\n\t\t\t\t<Flex direction=\"row\" gap=\"3\" align=\"center\" grow=\"1\" shrink=\"0\">\r\n\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\tseverity=\"info\"\r\n\t\t\t\t\t\tvariant=\"outline\"\r\n\t\t\t\t\t\taria-label={`Remove ${name}`}\r\n\t\t\t\t\t\tdisabled={disabled}\r\n\t\t\t\t\t\tonClick={onRemove}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t<Cross1Icon />\r\n\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t\t\t\t<Text>{name}</Text>\r\n\t\t\t\t\t\t<Text size=\"1\">{size}</Text>\r\n\t\t\t\t\t\t{error && (\r\n\t\t\t\t\t\t\t<Text size=\"1\" severity=\"danger\">\r\n\t\t\t\t\t\t\t\t{error}\r\n\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{url && <img className={styles.previewImage} src={url} alt={name} />}\r\n\t\t\t</Flex>\r\n\t\t</Card>\r\n\t)\r\n})\r\n","import { ISerializedField, SerializedUploadField } from \"@overmap-ai/core\"\r\nimport { BaseField, ChildFieldOptions } from \"../BaseField\"\r\nimport { GetInputProps, InputFieldLevelValidator } from \"../typings\"\r\nimport { ChangeEvent, ReactNode } from \"react\"\r\nimport { NumberInput } from \"./UploadInput\"\r\nimport { UploadIcon } from \"@overmap-ai/blocks\"\r\nimport { NumberField } from \"../NumberField\"\r\nimport { convertBytesToLargestUnit } from \"./utils\"\r\nimport { MultiSelectField } from \"../SelectField\"\r\n\r\nexport interface UploadFieldOptions extends ChildFieldOptions<File[]> {\r\n\textensions?: string[]\r\n\tmaximum_size?: number | string\r\n\tmaximum_files?: number | string\r\n}\r\n\r\nconst largestSupportedSize = 50 * 1024 * 1024 // 50 MB\r\n\r\nexport class UploadField extends BaseField<File[], \"upload\"> {\r\n\tstatic readonly fieldTypeName = \"Upload\"\r\n\tstatic readonly fieldTypeDescription = \"Allows a file to be uploaded.\"\r\n\r\n\tpublic readonly extensions?: string[]\r\n\tpublic readonly maxFileSize: number | undefined\r\n\tpublic readonly maxFiles: number\r\n\tpublic readonly onlyValidateAfterTouched = false\r\n\r\n\tstatic Icon: typeof UploadIcon = UploadIcon\r\n\r\n\tconstructor(options: UploadFieldOptions) {\r\n\t\tconst { extensions, maximum_files, maximum_size, ...base } = options\r\n\t\tsuper({ ...base, type: \"upload\" })\r\n\r\n\t\tthis.maxFileSize = typeof maximum_size === \"number\" ? maximum_size : undefined\r\n\t\t// if maximum_files is not a number or less than 1, default and clamp to 1\r\n\t\tthis.maxFiles = Math.max(typeof maximum_files === \"number\" ? maximum_files : 1, 1)\r\n\r\n\t\tthis.extensions = extensions\r\n\t}\r\n\r\n\tpublic getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement>): File[] {\r\n\t\treturn Array.from(event.target.files || [])\r\n\t}\r\n\r\n\tprotected isBlank(value: File[]): boolean {\r\n\t\treturn super.isBlank(value) || value.length === 0\r\n\t}\r\n\r\n\tstatic getFieldCreationSchema() {\r\n\t\treturn [\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"How many files can be uploaded?\",\r\n\t\t\t\tdescription: \"By default, only one file can be uploaded.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: 10,\r\n\t\t\t\tidentifier: \"maximum_files\",\r\n\t\t\t}),\r\n\t\t\tnew NumberField({\r\n\t\t\t\tlabel: \"What is the maximum size of each file?\",\r\n\t\t\t\tdescription: \"Maximum file size in bytes.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"maximum_size\",\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: largestSupportedSize,\r\n\t\t\t\tintegers: true,\r\n\t\t\t}),\r\n\t\t\tnew MultiSelectField({\r\n\t\t\t\tlabel: \"Accepted file types\",\r\n\t\t\t\tdescription: \"Types of allowed files to upload. If left blank, all files will be accepted.\",\r\n\t\t\t\trequired: false,\r\n\t\t\t\tidentifier: \"extensions\",\r\n\t\t\t\toptions: [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"image/*\",\r\n\t\t\t\t\t\tlabel: \"Images\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"audio/*\",\r\n\t\t\t\t\t\tlabel: \"Audio files\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"video/*\",\r\n\t\t\t\t\t\tlabel: \"Videos\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"text/*\",\r\n\t\t\t\t\t\tlabel: \"Text files\",\r\n\t\t\t\t\t},\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tvalue: \"application/*\",\r\n\t\t\t\t\t\tlabel: \"Application files (includes PDFs and Word documents)\",\r\n\t\t\t\t\t},\r\n\t\t\t\t],\r\n\t\t\t}),\r\n\t\t]\r\n\t}\r\n\r\n\tgetFieldValidators(): InputFieldLevelValidator<File[]>[] {\r\n\t\tconst validators = super.getFieldValidators()\r\n\t\tconst maxFileSize = this.maxFileSize ?? largestSupportedSize\r\n\t\tconst maxFiles = this.maxFiles ?? 1\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (value && value.some((file) => file.size > maxFileSize)) {\r\n\t\t\t\treturn `Files must be at most ${convertBytesToLargestUnit(maxFileSize)}.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tvalidators.push((value) => {\r\n\t\t\tif (value && value.length > maxFiles) {\r\n\t\t\t\treturn `You can only upload ${maxFiles} files.`\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn validators\r\n\t}\r\n\r\n\tserialize(): SerializedUploadField {\r\n\t\treturn {\r\n\t\t\t...super._serialize(),\r\n\t\t\textensions: this.extensions,\r\n\t\t\tmaximum_size: this.maxFileSize,\r\n\t\t\tmaximum_files: this.maxFiles,\r\n\t\t}\r\n\t}\r\n\r\n\tstatic deserialize(data: ISerializedField): UploadField {\r\n\t\tif (data.type !== \"upload\") throw new Error(\"Type mismatch.\")\r\n\t\treturn new UploadField(data)\r\n\t}\r\n\r\n\tgetInput(props: GetInputProps<this>): ReactNode {\r\n\t\treturn <NumberInput field={this} {...props} />\r\n\t}\r\n}\r\n","import { StringField, TextField } from \"./StringOrTextFields\"\r\nimport { BooleanField } from \"./BooleanField\"\r\nimport { DateField } from \"./DateField\"\r\nimport { NumberField } from \"./NumberField\"\r\nimport { MultiSelectField, SelectField } from \"./SelectField\"\r\nimport { CustomField } from \"./CustomField\"\r\nimport { MultiStringField } from \"./MultiStringField\"\r\nimport { UploadField } from \"./UploadField\"\r\n\r\nexport const FieldTypeToClsMapping = {\r\n\tdate: DateField,\r\n\tnumber: NumberField,\r\n\tboolean: BooleanField,\r\n\tselect: SelectField,\r\n\tstring: StringField,\r\n\ttext: TextField,\r\n\tcustom: CustomField,\r\n\tupload: UploadField,\r\n\t// TODO: Underscore\r\n\t\"multi-string\": MultiStringField,\r\n\t\"multi-select\": MultiSelectField,\r\n} as const\r\n","import { AnyField, ISchema, ISerializedOnlyField, SchemaMeta } from \"./typings\"\r\nimport { FieldTypeToClsMapping } from \"./constants\"\r\nimport {\r\n\tFieldTypeIdentifier,\r\n\tFieldValue,\r\n\tISerializedField,\r\n\tSelectFieldOption,\r\n\tSerializedCondition,\r\n\tUserFormRevision,\r\n} from \"@overmap-ai/core\"\r\nimport { FieldSection } from \"./FieldSection\"\r\n\r\n// Note: the deserialization methods are separate to avoid circular dependencies.\r\n\r\n/** Deserializes anything but a FieldSection.\r\n * @see `deserialize` for most use cases\r\n */\r\nexport const deserializeField = (serializedField: ISerializedOnlyField): AnyField => {\r\n\tconst fieldType: FieldTypeIdentifier = serializedField.type\r\n\tconst fieldCls = FieldTypeToClsMapping[fieldType]\r\n\treturn fieldCls.deserialize(serializedField)\r\n}\r\n\r\n/** Deserializes anything */\r\nexport const deserialize = (serialized: ISerializedField): AnyField | FieldSection => {\r\n\tif (serialized.type === \"section\") {\r\n\t\treturn FieldSection.deserialize(serialized)\r\n\t}\r\n\treturn deserializeField(serialized)\r\n}\r\n\r\nexport type PartialFormRevision = Pick<UserFormRevision, \"title\" | \"fields\" | \"description\"> & Partial<UserFormRevision>\r\n\r\nexport function formRevisionToSchema(formRevision: PartialFormRevision, meta: Partial<SchemaMeta> = {}): ISchema {\r\n\t// expanding the meta in order to set default values\r\n\tconst { readonly = false } = meta\r\n\r\n\treturn {\r\n\t\ttitle: formRevision.title,\r\n\t\tdescription: formRevision.description,\r\n\t\tfields: formRevision.fields.map((serializedField: ISerializedField) => deserialize(serializedField)),\r\n\t\tmeta: { readonly },\r\n\t}\r\n}\r\n\r\nexport function valueIsFile(v: FieldValue | Promise<File>[] | undefined): v is File[] | Promise<File>[] {\r\n\tif (Array.isArray(v) && v.some((v) => v instanceof File || v instanceof Promise)) return true\r\n\r\n\treturn false\r\n}\r\n\r\nexport function isConditionMet<TValue extends FieldValue | Promise<File>[]>(\r\n\tcondition: TValue extends FieldValue ? SerializedCondition<TValue> | null : null,\r\n\tvalue: TValue,\r\n) {\r\n\t// if no condition is provided, it is always met\r\n\tif (!condition) return true\r\n\r\n\t// conditions due not support file uploads, so we can assume that the value is not an array of File's\r\n\tif (valueIsFile(value) || valueIsFile(condition.value)) throw new Error(\"Conditions do not support file uploads\")\r\n\r\n\tconst valueAsPrimitive: Exclude<FieldValue, SelectFieldOption[] | File[]> = Array.isArray(value)\r\n\t\t? value.map((v) => (typeof v === \"string\" ? v : v.value))\r\n\t\t: value\r\n\r\n\tconst valueToCompare: Exclude<FieldValue, SelectFieldOption[] | File[]> = Array.isArray(condition.value)\r\n\t\t? condition.value.map((v) => (typeof v === \"string\" ? v : v.value))\r\n\t\t: condition.value\r\n\r\n\t// if comparing arrays, check if any of the values match\r\n\tif (Array.isArray(valueToCompare) && Array.isArray(valueAsPrimitive)) {\r\n\t\t// ensure that every value in valueToCompare is in valueAsPrimitive\r\n\t\t// though not necessarily the other way around\r\n\t\tfor (const v of valueToCompare) {\r\n\t\t\tif (!valueAsPrimitive.includes(v)) return false\r\n\t\t}\r\n\t\treturn true\r\n\t}\r\n\r\n\treturn valueToCompare === value\r\n}\r\n","import { GetInputProps } from \"./typings\"\r\nimport { ReactNode, useMemo } from \"react\"\r\nimport { BaseField, BaseFormElement } from \"./BaseField\"\r\nimport { Flex } from \"@overmap-ai/blocks\"\r\nimport { FieldValue } from \"@overmap-ai/core\"\r\n\r\nexport const useFieldInput = <TField extends BaseFormElement | null>(\r\n\tfield: TField,\r\n\tprops: TField extends BaseFormElement ? GetInputProps<TField> : null,\r\n): ReactNode => {\r\n\t// TODO: Consider deep equality check on props\r\n\treturn useMemo(() => {\r\n\t\tif (!props || !field) return null\r\n\t\treturn field.getInput(props)\r\n\t}, [field, props])\r\n}\r\n\r\nexport const useFieldInputs = (fields: BaseFormElement[], props: GetInputProps<BaseField<FieldValue>>): ReactNode => {\r\n\tconst inputs = useMemo(() => {\r\n\t\treturn fields.map((field) => {\r\n\t\t\treturn <div key={field.getId()}>{field.getInput(props)}</div>\r\n\t\t})\r\n\t}, [fields, props])\r\n\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t{inputs}\r\n\t\t</Flex>\r\n\t)\r\n}\r\n","import { FieldSection, ISchema, isConditionMet } from \"fields\"\r\nimport { BaseField, BaseFormElement } from \"fields/BaseField\"\r\nimport { FormikErrors } from \"formik\"\r\nimport cloneDeep from \"lodash.clonedeep\"\r\nimport get from \"lodash.get\"\r\nimport set from \"lodash.set\"\r\nimport { Form } from \"typings\"\r\n\r\nexport const hasKeys = (errors: object): boolean => {\r\n\treturn Object.keys(errors).length > 0\r\n}\r\n\r\nexport const validateForm = async (schema: ISchema, form: Form) => {\r\n\t// TODO: Comments\r\n\tconst errors: FormikErrors<Form> = {}\r\n\tfor (const field of schema.fields) {\r\n\t\tif (field instanceof FieldSection) {\r\n\t\t\t// if condition is not met, do not validate section\r\n\t\t\tif (field.condition) {\r\n\t\t\t\tconst { identifier } = field.condition\r\n\r\n\t\t\t\tif (!isConditionMet(field.condition, get(form, identifier))) {\r\n\t\t\t\t\tcontinue\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tObject.assign(errors, field.getErrors(form))\r\n\t\t} else {\r\n\t\t\t// REASON: WebStorm is wrong, TypeScript is right. `field` is a BaseFormElement, which may be a BaseField.\r\n\t\t\t// noinspection SuspiciousTypeOfGuard\r\n\t\t\tif (!(field instanceof BaseField)) {\r\n\t\t\t\tthrow new Error(\"Invalid field type\")\r\n\t\t\t}\r\n\t\t\tconst id = field.getId()\r\n\t\t\tconst error = field.getError(get(form, id), form)\r\n\t\t\tif (error) set(errors, id, error)\r\n\t\t}\r\n\t}\r\n\r\n\t// only return errors if there are any\r\n\tif (hasKeys(errors)) return errors\r\n}\r\n\r\nconst uncontrolledValues: unknown[] = [null, undefined]\r\n\r\n// If a value is not provided, adds empty values for all fields in the\r\n// schema so that the form is fully controlled\r\nexport const initialFormValues = (fields: BaseFormElement[], values: Form): Form => {\r\n\treturn fields.reduce<Form>(\r\n\t\t(acc, field) => {\r\n\t\t\t// check for field section\r\n\t\t\tif (field instanceof FieldSection) {\r\n\t\t\t\treturn { ...acc, ...initialFormValues(field.fields, values) }\r\n\t\t\t}\r\n\t\t\t// values must not be undefined or React will error as\r\n\t\t\t// the input changes from uncontrolled to controlled\r\n\t\t\tif (uncontrolledValues.includes(get(acc, field.getId()))) {\r\n\t\t\t\tset(acc, field.getId(), \"\")\r\n\t\t\t}\r\n\t\t\treturn acc\r\n\t\t},\r\n\t\t// TODO: Had to do this because of this error:\r\n\t\t// > Uncaught TypeError: can't define property \"description\":\r\n\t\t// > Object is not extensible\"\r\n\t\t// This means that we can't mutate `acc` because it's frozen for some\r\n\t\t// unknown reason.\r\n\t\tcloneDeep(values),\r\n\t)\r\n}\r\n","import { Button, Card, Flex, Heading, Text } from \"@overmap-ai/blocks\"\r\nimport { ISchema } from \"fields/typings\"\r\nimport { FormikProvider, useFormik } from \"formik\"\r\nimport { useMemo, memo, forwardRef, useEffect } from \"react\"\r\nimport { initialFormValues, validateForm } from \"utils\"\r\nimport styles from \"styling.module.sass\"\r\nimport { Form } from \"typings\"\r\nimport { useFieldInputs } from \"../../fields\"\r\n\r\ninterface FormRendererProps {\r\n\t/** The schema of the form the render */\r\n\tschema: ISchema\r\n\t/** Initial values of the form */\r\n\tvalues?: Form\r\n\tonSubmit?: (values: Form) => Promise<void> | void\r\n\t/** @default \"Submit\" */\r\n\tsubmitText?: string\r\n\t/** The text of the cancel button (hidden by default)\r\n\t * @default null\r\n\t */\r\n\tcancelText?: string\r\n\tonCancel?: () => void\r\n\tonDirty?: () => void\r\n\tonDirtyChange?: (dirty: boolean) => void\r\n\t/** Hide the form description\r\n\t * @default false */\r\n\thideDescription?: boolean\r\n\t/** Hide the title (and description)\r\n\t * @default false\r\n\t */\r\n\thideTitle?: boolean\r\n\tclassName?: string\r\n}\r\n\r\nconst defaultHandleSubmit = () => {\r\n\tthrow new Error(\"onSubmit must be provided if form is not readonly.\")\r\n}\r\n\r\nexport const FormRenderer = memo(\r\n\tforwardRef<HTMLDivElement, FormRendererProps>((props, ref) => {\r\n\t\tconst {\r\n\t\t\tschema,\r\n\t\t\tvalues = {},\r\n\t\t\tonSubmit = defaultHandleSubmit,\r\n\t\t\tsubmitText = \"Submit\",\r\n\t\t\tcancelText,\r\n\t\t\tonCancel,\r\n\t\t\tonDirty,\r\n\t\t\tonDirtyChange,\r\n\t\t\t// if the title isn't provided, hide it by default\r\n\t\t\thideTitle = !schema.title,\r\n\t\t\thideDescription,\r\n\t\t\tclassName,\r\n\t\t} = props\r\n\t\tconst { readonly } = schema.meta\r\n\r\n\t\t// randomly generate a form id to ensure field ids are unique\r\n\t\tconst formId = useMemo(() => crypto.randomUUID(), [])\r\n\r\n\t\tconst formik = useFormik<Form>({\r\n\t\t\tinitialValues: initialFormValues(schema.fields, values),\r\n\t\t\tonSubmit,\r\n\t\t\tvalidate: (form) => validateForm(schema, form),\r\n\t\t\t// only validate the entire form on submit\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t\tvalidateOnChange: false,\r\n\t\t})\r\n\t\tconst { dirty } = formik\r\n\r\n\t\tconst Title = useMemo(\r\n\t\t\t() => (typeof schema.title === \"string\" ? <Heading>{schema.title}</Heading> : schema.title),\r\n\t\t\t[schema.title],\r\n\t\t)\r\n\r\n\t\tconst Description = useMemo(\r\n\t\t\t() =>\r\n\t\t\t\ttypeof schema.description === \"string\" ? (\r\n\t\t\t\t\t<Text className={styles.description}>{schema.description}</Text>\r\n\t\t\t\t) : (\r\n\t\t\t\t\tschema.description\r\n\t\t\t\t),\r\n\t\t\t[schema.description],\r\n\t\t)\r\n\r\n\t\tconst inputs = useFieldInputs(schema.fields, { formId, disabled: readonly })\r\n\r\n\t\tuseEffect(() => {\r\n\t\t\tif (dirty && onDirty) onDirty()\r\n\t\t\tif (onDirtyChange) onDirtyChange(dirty)\r\n\t\t}, [dirty, onDirty, onDirtyChange])\r\n\r\n\t\treturn (\r\n\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t<Flex ref={ref} direction=\"column\" gap=\"2\" className={className} asChild>\r\n\t\t\t\t\t<form id={formId} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t\t{!hideTitle && (\r\n\t\t\t\t\t\t\t<Card>\r\n\t\t\t\t\t\t\t\t<Flex direction=\"column\" gap=\"1\">\r\n\t\t\t\t\t\t\t\t\t{Title}\r\n\t\t\t\t\t\t\t\t\t{!hideDescription && Description}\r\n\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t</Card>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t{inputs}\r\n\t\t\t\t\t\t{!readonly && (\r\n\t\t\t\t\t\t\t<Flex justify=\"end\" gap=\"2\">\r\n\t\t\t\t\t\t\t\t{cancelText && (\r\n\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"soft\" onClick={onCancel}>\r\n\t\t\t\t\t\t\t\t\t\t{cancelText}\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t<Button type=\"submit\" disabled={!formik.isValid}>\r\n\t\t\t\t\t\t\t\t\t{submitText}\r\n\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t)}\r\n\t\t\t\t\t</form>\r\n\t\t\t\t</Flex>\r\n\t\t\t</FormikProvider>\r\n\t\t)\r\n\t}),\r\n)\r\n","import { useMemo, memo, forwardRef } from \"react\"\r\nimport {\r\n\tOffline,\r\n\tselectFormRevision,\r\n\tuseAppSelector,\r\n\tUserFormSubmissionPayload,\r\n\tselectSubmissionAttachments,\r\n\tuseSDK,\r\n} from \"@overmap-ai/core\"\r\nimport { FormRenderer } from \"../FormRenderer/FormRenderer\"\r\nimport { formRevisionToSchema } from \"fields/utils\"\r\nimport { ISchema } from \"fields/typings\"\r\n\r\ninterface FormSubmissionViewerProps {\r\n\t/** The submission to render for viewing */\r\n\tsubmission: Offline<UserFormSubmissionPayload>\r\n\t/** @default false */\r\n\tshowFormDescription?: boolean\r\n\t/** @default true */\r\n\tshowFormTitle?: boolean\r\n}\r\n\r\n/**\r\n * Wrapper for `FormRenderer` that takes a `UserFormSubmissionPayload` instead of an `ISchema`.\r\n * Also, unlike `FormRenderer`, this component depends on the redux store.\r\n * @see FormRenderer\r\n */\r\nexport const FormSubmissionViewer = memo(\r\n\tforwardRef<HTMLDivElement, FormSubmissionViewerProps>((props, ref) => {\r\n\t\tconst { submission, showFormDescription = false, showFormTitle = true } = props\r\n\t\tconst revision = useAppSelector(selectFormRevision(submission.form_revision))\r\n\t\tconst { sdk } = useSDK()\r\n\r\n\t\tif (!revision) {\r\n\t\t\tthrow new Error(\r\n\t\t\t\t`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`,\r\n\t\t\t)\r\n\t\t}\r\n\t\tconst schema: ISchema = useMemo(() => {\r\n\t\t\treturn formRevisionToSchema(revision, { readonly: true })\r\n\t\t}, [revision])\r\n\r\n\t\tconst submissionValuesWithAttachments = useMemo(() => {\r\n\t\t\tconst attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? []\r\n\t\t\tconst downloadedAttachments: Record<string, Promise<File>[]> = {}\r\n\r\n\t\t\tfor (const attachment of attachments) {\r\n\t\t\t\tconst promise = sdk.files\r\n\t\t\t\t\t.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name)\r\n\t\t\t\t\t.then((response) => {\r\n\t\t\t\t\t\tif (!response.success) throw new Error(`Failed to download attachment ${attachment.file_name}.`)\r\n\t\t\t\t\t\treturn response.body\r\n\t\t\t\t\t})\r\n\r\n\t\t\t\tconst fieldAttachments = downloadedAttachments[attachment.field_identifier]\r\n\t\t\t\tif (fieldAttachments) {\r\n\t\t\t\t\tfieldAttachments.push(promise)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdownloadedAttachments[attachment.field_identifier] = [promise]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn { ...submission.values, ...downloadedAttachments }\r\n\t\t}, [sdk.files, sdk.store, submission.offline_id, submission.values])\r\n\r\n\t\treturn (\r\n\t\t\t<FormRenderer\r\n\t\t\t\tref={ref}\r\n\t\t\t\tschema={schema}\r\n\t\t\t\tvalues={submissionValuesWithAttachments}\r\n\t\t\t\thideDescription={!showFormDescription}\r\n\t\t\t\thideTitle={!showFormTitle}\r\n\t\t\t/>\r\n\t\t)\r\n\t}),\r\n)\r\n","import {\r\n\tFlex,\r\n\tButtonList,\r\n\tText,\r\n\tIconButton,\r\n\tStarFilledIcon,\r\n\tStarIcon,\r\n\tTextField,\r\n\tdivButtonProps,\r\n\tTooltip,\r\n\tQuestionMarkCircledIcon,\r\n\tPersonIcon,\r\n\tSelect,\r\n\tBox,\r\n} from \"@overmap-ai/blocks\"\r\nimport {\r\n\tselectNumberOfUserForms,\r\n\tuseAppSelector,\r\n\tCachedUserForm,\r\n\tuseSDK,\r\n\tselectOrganization,\r\n\tselectUser,\r\n\tselectCurrentUser,\r\n\tselectUserFormMapping,\r\n\tselectFilteredUserForms,\r\n\ttype UserFormSearchArgs,\r\n\tclassNames,\r\n} from \"@overmap-ai/core\"\r\nimport { ChangeEventHandler, MouseEventHandler, forwardRef, memo, useCallback, useMemo, useState } from \"react\"\r\nimport styles from \"./FormBrowser.module.sass\"\r\n\r\ninterface FormBrowserProps {\r\n\t/** If `true`, the user can toggle the favorite state of the forms they have access to */\r\n\tisFavoriteEditable?: boolean\r\n\tonSelectForm: (form: CachedUserForm) => void\r\n\t/** @default 20 */\r\n\tmaxResults?: number\r\n}\r\n\r\n// there is one dropdown with both organizations and users as options\r\n// the value is prefixed with either \"organization:\" or \"user:\" to indicate which it is\r\n// this is done to avoid collisions between the two, as they are both integers\r\nconst orgOptionPrefix = \"organization:\"\r\nconst userOptionPrefix = \"user:\"\r\n\r\nexport const FormBrowser = memo(\r\n\tforwardRef<HTMLDivElement, FormBrowserProps>((props, ref) => {\r\n\t\tconst { maxResults = 20, ...entryProps } = props\r\n\t\tconst [filter, setFilter] = useState(\"\")\r\n\t\tconst [ownerFilter, setOwnerFilter] = useState(\"\")\r\n\t\tconst { sdk } = useSDK()\r\n\r\n\t\tconst ownerFilterOptions = useMemo(() => {\r\n\t\t\tconst ret: UserFormSearchArgs = { maxResults, searchTerm: filter }\r\n\r\n\t\t\tif (ownerFilter) {\r\n\t\t\t\tif (ownerFilter.startsWith(orgOptionPrefix)) {\r\n\t\t\t\t\tret.owner_organization = parseInt(ownerFilter.slice(orgOptionPrefix.length))\r\n\t\t\t\t} else if (ownerFilter.startsWith(userOptionPrefix)) {\r\n\t\t\t\t\tret.owner_user = parseInt(ownerFilter.slice(userOptionPrefix.length))\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn ret\r\n\t\t}, [filter, maxResults, ownerFilter])\r\n\t\tconst userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? []\r\n\r\n\t\tconst userFormMapping = useAppSelector(selectUserFormMapping)\r\n\r\n\t\tconst handleToggleFavorite = useCallback(\r\n\t\t\t(form: CachedUserForm) => {\r\n\t\t\t\tif (form.favorite) {\r\n\t\t\t\t\tsdk.userForms.unfavorite(form.offline_id).then()\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsdk.userForms.favorite(form.offline_id).then()\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[sdk],\r\n\t\t)\r\n\r\n\t\tconst options = useMemo(() => {\r\n\t\t\tconst state = sdk.store.getState()\r\n\r\n\t\t\t// value to label mapping\r\n\t\t\tconst accumulator: Record<string, string> = {}\r\n\r\n\t\t\tfor (const form of Object.values(userFormMapping)) {\r\n\t\t\t\tconst organization = selectOrganization(form.owner_organization || -1)(state)\r\n\t\t\t\tif (organization) {\r\n\t\t\t\t\taccumulator[`${orgOptionPrefix}${organization.id}`] = organization.name\r\n\t\t\t\t}\r\n\t\t\t\tconst user = selectUser(form.owner_user || -1)(state)\r\n\r\n\t\t\t\tif (user) {\r\n\t\t\t\t\taccumulator[`${userOptionPrefix}${user.id}`] = user.username\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn Object.entries(accumulator).map(([value, label]) => ({ itemContent: label, value }))\r\n\t\t}, [userFormMapping, sdk.store])\r\n\r\n\t\tconst handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>((e) => {\r\n\t\t\tsetFilter(e.currentTarget.value)\r\n\t\t}, [])\r\n\r\n\t\tconst numberOfForms = useAppSelector(selectNumberOfUserForms) || 0\r\n\t\tconst numberOfHiddenForms = numberOfForms - userForms.length\r\n\t\tconst overflowMessage =\r\n\t\t\tuserForms.length == maxResults && numberOfHiddenForms > 0\r\n\t\t\t\t? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)`\r\n\t\t\t\t: numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`\r\n\r\n\t\treturn (\r\n\t\t\t<Flex ref={ref} direction=\"column\" gap=\"2\">\r\n\t\t\t\t<Flex gap=\"2\" grow=\"1\">\r\n\t\t\t\t\t<Box grow=\"1\" asChild>\r\n\t\t\t\t\t\t<TextField.Root size=\"3\">\r\n\t\t\t\t\t\t\t<TextField.Input placeholder=\"Filter\" value={filter} onChange={handleChange} />\r\n\t\t\t\t\t\t</TextField.Root>\r\n\t\t\t\t\t</Box>\r\n\t\t\t\t\t<Select\r\n\t\t\t\t\t\titems={options}\r\n\t\t\t\t\t\tvalue={ownerFilter}\r\n\t\t\t\t\t\tonValueChange={setOwnerFilter}\r\n\t\t\t\t\t\tplaceholder=\"Owner\"\r\n\t\t\t\t\t\tsize=\"large\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{userForms.length > 0 && (\r\n\t\t\t\t\t<ButtonList.Root>\r\n\t\t\t\t\t\t{userForms.map((form) => (\r\n\t\t\t\t\t\t\t<FormBrowserEntry\r\n\t\t\t\t\t\t\t\tkey={form.offline_id}\r\n\t\t\t\t\t\t\t\t{...entryProps}\r\n\t\t\t\t\t\t\t\tform={form}\r\n\t\t\t\t\t\t\t\thandleToggleFavorite={() => handleToggleFavorite(form)}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t</ButtonList.Root>\r\n\t\t\t\t)}\r\n\t\t\t\t<Box px=\"3\">\r\n\t\t\t\t\t<Text size=\"2\" severity=\"info\">\r\n\t\t\t\t\t\t{overflowMessage}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Box>\r\n\t\t\t</Flex>\r\n\t\t)\r\n\t}),\r\n)\r\n\r\ninterface FormBrowserEntryProps extends Omit<FormBrowserProps, \"maxResults\"> {\r\n\tform: CachedUserForm\r\n\thandleToggleFavorite: () => void\r\n}\r\n\r\nconst FormBrowserEntry = (props: FormBrowserEntryProps) => {\r\n\tconst { form, onSelectForm, isFavoriteEditable, handleToggleFavorite } = props\r\n\tconst ownerOrganization = useAppSelector(selectOrganization(form.owner_organization || -1))?.name\r\n\tconst ownerUser = useAppSelector(selectUser(form.owner_user || -1))\r\n\tconst currentUserId = useAppSelector(selectCurrentUser).id\r\n\tconst ownedByCurrentUser = !!ownerUser && ownerUser.id === currentUserId\r\n\tconst owner = ownerOrganization ?? (ownedByCurrentUser ? \"You\" : ownerUser?.username) ?? \"Unknown\"\r\n\r\n\tconst handleFavoriteClick = useCallback<MouseEventHandler<HTMLButtonElement>>(\r\n\t\t(e) => {\r\n\t\t\te.stopPropagation()\r\n\t\t\thandleToggleFavorite()\r\n\t\t},\r\n\t\t[handleToggleFavorite],\r\n\t)\r\n\r\n\tconst ret = (\r\n\t\t<ButtonList.Item onClick={() => onSelectForm(form)} asChild>\r\n\t\t\t<Flex justify=\"between\" gap=\"2\" py=\"2\" px=\"3\" {...divButtonProps}>\r\n\t\t\t\t<Flex grow=\"1\" align=\"center\" gap=\"2\">\r\n\t\t\t\t\t<IconButton\r\n\t\t\t\t\t\tclassName={classNames(form.favorite ? styles.favoriteIcon : styles.regularIcon)}\r\n\t\t\t\t\t\tvariant=\"ghost\"\r\n\t\t\t\t\t\tonClick={handleFavoriteClick}\r\n\t\t\t\t\t\taria-label={form.favorite ? \"Favorite form\" : \"Standard form\"}\r\n\t\t\t\t\t\tdisabled={!isFavoriteEditable}\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{form.favorite ? <StarFilledIcon /> : <StarIcon />}\r\n\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t<Text noWrap>{form.latestRevision.title}</Text>\r\n\t\t\t\t\t{form.latestRevision.description && <QuestionMarkCircledIcon />}\r\n\t\t\t\t</Flex>\r\n\t\t\t\t{owner && (\r\n\t\t\t\t\t<Flex align=\"center\" gap=\"2\">\r\n\t\t\t\t\t\t<PersonIcon /> {owner}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t)}\r\n\t\t\t</Flex>\r\n\t\t</ButtonList.Item>\r\n\t)\r\n\r\n\t// wrap the button in a tooltip if there is a description\r\n\tif (form.latestRevision.description) {\r\n\t\treturn (\r\n\t\t\t<Tooltip key={form.offline_id} content={form.latestRevision.description}>\r\n\t\t\t\t{ret}\r\n\t\t\t</Tooltip>\r\n\t\t)\r\n\t}\r\n\r\n\treturn ret\r\n}\r\n","import React, { ReactNode, memo, useMemo } from \"react\"\r\nimport styles from \"./FormSubmissionBrowser.module.sass\"\r\nimport {\r\n\tOffline,\r\n\tselectCurrentUser,\r\n\tselectFormRevision,\r\n\tselectLatestFormRevision,\r\n\tselectSubmissionsForForm,\r\n\tselectUser,\r\n\tuseAppSelector,\r\n\tUserFormSubmission,\r\n\tUserFormSubmissionPayload,\r\n\tgetLocalDateString,\r\n\tisToday,\r\n\tuseFileSrc,\r\n\tclassNames,\r\n} from \"@overmap-ai/core\"\r\nimport { Badge, Flex, Text, ButtonList, Avatar } from \"@overmap-ai/blocks\"\r\n\r\nexport type FormSubmissionClickEvent = {\r\n\tsubmission: Offline<UserFormSubmissionPayload>\r\n}\r\n\r\ninterface UserFormSubmissionBrowserEntryProps {\r\n\tsubmission: Offline<UserFormSubmissionPayload> | UserFormSubmission\r\n\tonSubmissionClick?: (e: FormSubmissionClickEvent) => void\r\n\trowDecorator?: (submission: Offline<UserFormSubmissionPayload> | UserFormSubmission, Row: ReactNode) => ReactNode\r\n\tcompact: boolean\r\n\tlabelType: \"creator\" | \"formName\"\r\n}\r\n\r\nconst FormSubmissionBrowserEntry = memo(function FormSubmissionBrowserEntry(\r\n\tprops: UserFormSubmissionBrowserEntryProps,\r\n) {\r\n\tconst { submission, onSubmissionClick, compact, labelType, rowDecorator } = props\r\n\tconst currentUser = useAppSelector(selectCurrentUser)\r\n\tconst createdBy = useAppSelector(selectUser(\"created_by\" in submission ? submission.created_by : currentUser.id))\r\n\tconst dateToUse = getCreatedAtOrSubmittedAtDate(submission)\r\n\tconst formattedDateTime = isToday(dateToUse)\r\n\t\t? dateToUse.toLocaleTimeString([], {\r\n\t\t\t\thour: \"2-digit\",\r\n\t\t\t\tminute: \"2-digit\",\r\n\t\t })\r\n\t\t: getLocalDateString(dateToUse)\r\n\tconst revision = useAppSelector(selectFormRevision(submission.form_revision))\r\n\tif (!revision) {\r\n\t\tthrow new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`)\r\n\t}\r\n\tconst latestRevisionNumber = useAppSelector(selectLatestFormRevision(revision.form))?.revision\r\n\tconst creatorProfileSrc = useFileSrc({\r\n\t\tfile: createdBy?.profile.file ?? null,\r\n\t\tfileSha1: createdBy?.profile.file_sha1 ?? null,\r\n\t})\r\n\tconst creatorProfileFallback = createdBy?.username.charAt(0).toUpperCase() ?? \"?\"\r\n\r\n\tconst isLatestRevision = revision.revision === latestRevisionNumber\r\n\r\n\tconst handleClick = React.useCallback(() => {\r\n\t\tif (onSubmissionClick) {\r\n\t\t\tonSubmissionClick({ submission })\r\n\t\t}\r\n\t}, [submission, onSubmissionClick])\r\n\r\n\tconst row = (\r\n\t\t<ButtonList.Item onClick={handleClick} asChild>\r\n\t\t\t<Flex grow=\"1\" width=\"100%\" p=\"2\" gap=\"2\" justify=\"between\">\r\n\t\t\t\t<Flex gap=\"2\" align=\"center\" className={styles.stopHorizontalOverflow}>\r\n\t\t\t\t\t<Avatar src={creatorProfileSrc} size=\"1\" fallback={creatorProfileFallback} />\r\n\t\t\t\t\t<Text size=\"2\" noWrap>\r\n\t\t\t\t\t\t{labelType === \"creator\" ? (createdBy || currentUser).username : revision.title}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Flex>\r\n\t\t\t\t<Flex gap=\"2\" align=\"center\">\r\n\t\t\t\t\t{!compact &&\r\n\t\t\t\t\t\t(revision.revision ? (\r\n\t\t\t\t\t\t\t<Badge variant=\"soft\" severity={isLatestRevision ? \"primary\" : \"info\"}>\r\n\t\t\t\t\t\t\t\t{compact ? revision.revision.toString() : `Revision #${revision.revision}`}\r\n\t\t\t\t\t\t\t</Badge>\r\n\t\t\t\t\t\t) : (\r\n\t\t\t\t\t\t\t!!latestRevisionNumber && <Badge>Original</Badge>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t<Text size=\"2\" noWrap>\r\n\t\t\t\t\t\t{formattedDateTime}\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t</Flex>\r\n\t\t\t</Flex>\r\n\t\t</ButtonList.Item>\r\n\t)\r\n\r\n\tif (rowDecorator) {\r\n\t\treturn rowDecorator(submission, row)\r\n\t}\r\n\r\n\treturn row\r\n})\r\n\r\ninterface FormSubmissionBrowserProps {\r\n\t// If not set, `submissions` must be provided.\r\n\tformId?: string\r\n\t// If not provided, `formId` is expected, and all submissions of that form will be displayed.\r\n\tsubmissions?: (Offline<UserFormSubmissionPayload> | UserFormSubmission)[]\r\n\tonSubmissionClick?: (e: FormSubmissionClickEvent) => void\r\n\trowDecorator?: UserFormSubmissionBrowserEntryProps[\"rowDecorator\"]\r\n\t/** @default false */\r\n\tcompact?: boolean\r\n\tlabelType: \"creator\" | \"formName\"\r\n\tclassName?: string\r\n\t/** @default outline */\r\n\tvariant?: \"ghost\" | \"outline\"\r\n\t/** Content displayed within the container but after the list */\r\n\tafter?: ReactNode\r\n}\r\n\r\n// UserFOrmSubmission objects have a \"created_at\" field, but UserFormSubmissionPayload objects have a \"submitted_at\"\r\n// field. We use the \"created_at\" field if it exists, otherwise we use the \"submitted_at\" field. Unless someone\r\n// decides to hack the payload to bring their own submissions to the top by spoofing the `submitted_at` field, this\r\n// should be fine and allows a real life timeline instead of one that's based on internet access.\r\nconst getCreatedAtOrSubmittedAtDate = (submission: UserFormSubmissionPayload | UserFormSubmission) => {\r\n\tconst date = \"created_at\" in submission ? submission.created_at : submission.submitted_at\r\n\treturn new Date(date)\r\n}\r\n\r\nexport const FormSubmissionBrowser = memo(function FormSubmissionBrowser(props: FormSubmissionBrowserProps) {\r\n\tconst {\r\n\t\tformId,\r\n\t\tsubmissions: propSubmissions,\r\n\t\tcompact = false,\r\n\t\tclassName,\r\n\t\tafter,\r\n\t\tvariant = \"outline\",\r\n\t\t...submissionEntryProps\r\n\t} = props\r\n\tif (!!formId === !!propSubmissions) {\r\n\t\tthrow new Error(\"Either formId or submissions must be provided, but not both.\")\r\n\t}\r\n\tconst submissions = useAppSelector(\r\n\t\tpropSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId as string),\r\n\t)\r\n\tconst sortedSubmissions = useMemo(\r\n\t\t() =>\r\n\t\t\tsubmissions?.sort((a, b) => {\r\n\t\t\t\treturn getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime()\r\n\t\t\t}),\r\n\t\t[submissions],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<ButtonList.Root\r\n\t\t\tclassName={classNames(styles.submissionsContainer, className)}\r\n\t\t\tsize=\"small\"\r\n\t\t\tvariant={variant}\r\n\t\t\tbefore={\r\n\t\t\t\t!compact && (\r\n\t\t\t\t\t<Text severity=\"info\">\r\n\t\t\t\t\t\tThere are {(submissions?.length || 0).toString()} submissions of this form.\r\n\t\t\t\t\t</Text>\r\n\t\t\t\t)\r\n\t\t\t}\r\n\t\t\tafter={after}\r\n\t\t>\r\n\t\t\t{sortedSubmissions?.map((submission, index) => {\r\n\t\t\t\treturn (\r\n\t\t\t\t\t<FormSubmissionBrowserEntry\r\n\t\t\t\t\t\tkey={index}\r\n\t\t\t\t\t\tsubmission={submission}\r\n\t\t\t\t\t\tcompact={compact}\r\n\t\t\t\t\t\t{...submissionEntryProps}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)\r\n\t\t\t})}\r\n\t\t</ButtonList.Root>\r\n\t)\r\n})\r\n","import { ReactNode, memo, useMemo } from \"react\"\r\nimport { FieldValue } from \"@overmap-ai/core\"\r\nimport { useField, useFormikContext } from \"formik\"\r\n\r\ninterface RenderArgs {\r\n\tvalue: FieldValue\r\n\t/** Intermediate changes to the field value */\r\n\tsetValue: (value: FieldValue) => void\r\n\t/** EX: when the onBlur event is fired */\r\n\tpatchValue: () => void\r\n}\r\n\r\ninterface PatchFieldProps {\r\n\tname: string\r\n\trender: (args: RenderArgs) => ReactNode\r\n}\r\n\r\nexport const PatchField = memo(function PatchField(props: PatchFieldProps) {\r\n\tconst { name, render } = props\r\n\tconst { submitForm } = useFormikContext()\r\n\tconst [fieldProps, _meta, helpers] = useField(name)\r\n\r\n\treturn useMemo(() => {\r\n\t\tconst setValue = (value: FieldValue) => helpers.setValue(value, false)\r\n\t\treturn render({\r\n\t\t\tvalue: fieldProps.value,\r\n\t\t\tsetValue,\r\n\t\t\tpatchValue: submitForm,\r\n\t\t})\r\n\t}, [submitForm, helpers, fieldProps.value, render])\r\n})\r\n","import { ISchema } from \"fields\"\r\nimport { FormikErrors, FormikProvider, useFormik } from \"formik\"\r\nimport { forwardRef, memo, useCallback, useEffect, useMemo } from \"react\"\r\nimport { Form } from \"typings\"\r\nimport { hasKeys, initialFormValues, validateForm } from \"utils\"\r\nimport { useToast } from \"@overmap-ai/blocks\"\r\n\r\ninterface PatchFormProviderProps {\r\n\tchildren: React.ReactNode\r\n\tschema: ISchema\r\n\tvalues: Form\r\n\t/** Called when `patchValue` is called on a child `PatchField` and the form is valid.\r\n\t * @example ```js\r\n\t * {\"field name\": \"field value\"}\r\n\t * ``` */\r\n\tonPatch: (values: Form) => void\r\n\t/** Called when `patchValue` is called on a child `PatchField` and the form is not valid.\r\n\t * After this event is fired, the form is reset to the initial values.\r\n\t * @example ```js\r\n\t * {\"field name\": \"error message\"}\r\n\t * ``` */\r\n\tonError: (error: FormikErrors<Form>) => void\r\n\tclassName?: string\r\n}\r\n\r\n/** Use PatchForms to create patch edits to existing forms rather than editing the entire form. */\r\nexport const PatchFormProvider = memo(\r\n\tforwardRef<HTMLFormElement, PatchFormProviderProps>((props, ref) => {\r\n\t\tconst { children, schema, values, onPatch, onError, ...rest } = props\r\n\t\tconst { showError } = useToast()\r\n\t\tconst initialValues = useMemo(() => initialFormValues(schema.fields, values), [schema.fields, values])\r\n\r\n\t\tconst handlePatch = useCallback(\r\n\t\t\t(values: Form) => {\r\n\t\t\t\tconst diff: Form = {}\r\n\r\n\t\t\t\tfor (const key in values) {\r\n\t\t\t\t\tconst value = values[key]\r\n\t\t\t\t\tif (value !== initialValues[key] && value !== undefined) {\r\n\t\t\t\t\t\tdiff[key] = value\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// skip if no changes\r\n\t\t\t\tif (!hasKeys(diff)) return\r\n\t\t\t\tconsole.log(\"onpatch runs\", diff)\r\n\t\t\t\tonPatch(diff)\r\n\t\t\t},\r\n\t\t\t[initialValues, onPatch],\r\n\t\t)\r\n\r\n\t\tconst validate = useCallback(\r\n\t\t\tasync (form: Form) => {\r\n\t\t\t\tconst error = await validateForm(schema, form)\r\n\r\n\t\t\t\tif (error) {\r\n\t\t\t\t\t// report the error\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn error\r\n\t\t\t},\r\n\t\t\t[schema, onError],\r\n\t\t)\r\n\r\n\t\tconst formik = useFormik<Form>({\r\n\t\t\tinitialValues,\r\n\t\t\tonSubmit: handlePatch,\r\n\t\t\tvalidate,\r\n\t\t\t// only validate the entire form on submit\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t\tvalidateOnChange: false,\r\n\t\t})\r\n\r\n\t\tconst { errors, resetForm } = formik\r\n\r\n\t\tuseEffect(() => {\r\n\t\t\t// on errors, reset the form to the initial values\r\n\t\t\tif (hasKeys(errors)) {\r\n\t\t\t\tconsole.log(errors)\r\n\t\t\t\tshowError({\r\n\t\t\t\t\ttitle: \"test title\",\r\n\t\t\t\t\tdescription: \"Sections with conditions must be below the fields they reference.\",\r\n\t\t\t\t})\r\n\t\t\t\t// resetForm({ values: initialValues, errors: {} })\r\n\t\t\t}\r\n\t\t}, [showError, errors, initialValues, resetForm])\r\n\r\n\t\treturn (\r\n\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t{/* the `form` captures any submit events that are generated */}\r\n\t\t\t\t<form {...rest} ref={ref} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t{children}\r\n\t\t\t\t</form>\r\n\t\t\t</FormikProvider>\r\n\t\t)\r\n\t}),\r\n)\r\n","import { FormikUserFormRevision, NestedFieldPath } from \"./typings\"\r\nimport { FC, ReactNode, memo, useCallback, useMemo, useState } from \"react\"\r\nimport { FieldTypeToClsMapping } from \"fields/constants\"\r\nimport { AnyField, ISchema } from \"fields/typings\"\r\nimport { FieldTypeIdentifier, ISerializedField, SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport {\r\n\tButton,\r\n\tCloseDialogWithOptions,\r\n\tDialog,\r\n\tFlex,\r\n\tSeparator,\r\n\tText,\r\n\tuseDiscardAlertDialog,\r\n} from \"@overmap-ai/blocks\"\r\nimport { FormRenderer } from \"renderer\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { BooleanField, deserialize, StringField, TextField } from \"fields\"\r\nimport { Form } from \"typings\"\r\nimport { insert, makeIdentifier, replace, getTakenFieldLabels } from \"./utils\"\r\nimport { BaseField, BaseFormElement } from \"../fields/BaseField\"\r\nimport { FieldSection } from \"../fields\"\r\nimport get from \"lodash.get\"\r\n\r\ninterface ChooseFieldToAddProps {\r\n\tsetFieldType: (id: FieldTypeIdentifier) => void\r\n}\r\n\r\ninterface FieldToChooseProps extends ChooseFieldToAddProps {\r\n\tfield: (typeof CompleteFieldTypeToClsMapping)[(typeof fieldsToChoose)[number][number]]\r\n\tsetFieldType: () => void\r\n}\r\n\r\nconst CompleteFieldTypeToClsMapping = {\r\n\t...FieldTypeToClsMapping,\r\n\tsection: FieldSection,\r\n}\r\n\r\nconst FieldToChoose = memo(function FieldToChoose(props: FieldToChooseProps) {\r\n\tconst { field, setFieldType } = props\r\n\r\n\tconst typeName = field.fieldTypeName\r\n\tconst description = field.fieldTypeDescription\r\n\tconst Icon = field.Icon\r\n\treturn (\r\n\t\t<Flex gap=\"4\" align=\"center\">\r\n\t\t\t<Button type=\"button\" variant=\"surface\" onClick={setFieldType} style={{ width: \"135px\" }}>\r\n\t\t\t\t<Flex gap=\"3\" align=\"center\" grow=\"1\">\r\n\t\t\t\t\t<Icon />\r\n\t\t\t\t\t{typeName}\r\n\t\t\t\t</Flex>\r\n\t\t\t</Button>\r\n\t\t\t<Text>{description}</Text>\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\nconst fieldsToChoose = [\r\n\t[\"string\", \"text\"],\r\n\t[\"select\", \"multi-select\", \"upload\"],\r\n\t[\"boolean\", \"date\", \"number\", \"multi-string\"],\r\n] satisfies FieldTypeIdentifier[][]\r\nconst indexOfLastFieldGroup = fieldsToChoose.length - 1\r\n\r\nconst ChooseFieldToAdd = memo(function ChooseFieldToAdd(props: ChooseFieldToAddProps) {\r\n\tconst { setFieldType } = props\r\n\treturn (\r\n\t\t<Flex direction=\"column\" gap=\"3\">\r\n\t\t\t{fieldsToChoose.map((fieldGroup, index) => (\r\n\t\t\t\t<Flex key={index} direction=\"column\" gap=\"3\">\r\n\t\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t\t{fieldGroup.map((identifier) => (\r\n\t\t\t\t\t\t\t<FieldToChoose\r\n\t\t\t\t\t\t\t\tkey={identifier}\r\n\t\t\t\t\t\t\t\tfield={FieldTypeToClsMapping[identifier]}\r\n\t\t\t\t\t\t\t\tsetFieldType={() => setFieldType(identifier)}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t\t{index < indexOfLastFieldGroup && <Separator size=\"4\" />}\r\n\t\t\t\t</Flex>\r\n\t\t\t))}\r\n\t\t</Flex>\r\n\t)\r\n})\r\n\r\ninterface FieldOptionsFormProps {\r\n\tdefaultField?: ISerializedField\r\n\tfieldType: FieldTypeIdentifier\r\n\t/** fields that can be used as a condition */\r\n\tconditionalSourceFields?: ISerializedField[]\r\n\thandleCancel: () => void\r\n\thandleDirtyChange: (dirty: boolean) => void\r\n\thandleCreateField: (form: Form) => void\r\n}\r\n\r\nconst validateNewFieldName = (takenLabels: string[]) => {\r\n\treturn (value: unknown) => {\r\n\t\tif (!value || typeof value !== \"string\") return\r\n\r\n\t\tif (takenLabels.includes(value.trim())) {\r\n\t\t\treturn \"This name is already taken.\"\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/** Creates the common field at the beginning of each field creation schema.\r\n *\r\n * Note: this is not in the BaseField class due to circular dependencies.\r\n */\r\nconst commonFields = (takenLabels: string[], type: FieldTypeIdentifier): AnyField[] => {\r\n\tconst base = [\r\n\t\tnew StringField({\r\n\t\t\tlabel: \"Label\",\r\n\t\t\trequired: true,\r\n\t\t\tmaxLength: 200,\r\n\t\t\tidentifier: \"label\",\r\n\t\t\tfieldValidators: [validateNewFieldName(takenLabels)],\r\n\t\t}),\r\n\t\tnew TextField({\r\n\t\t\tlabel: \"Description\",\r\n\t\t\trequired: false,\r\n\t\t\tmaxLength: 1000,\r\n\t\t\tidentifier: \"description\",\r\n\t\t}),\r\n\t]\r\n\r\n\t// sections do not have a required field\r\n\tif (type === \"section\") return base\r\n\r\n\treturn [\r\n\t\t...base,\r\n\t\tnew BooleanField({ label: \"Required\", description: null, required: false, identifier: \"required\" }),\r\n\t]\r\n}\r\n\r\nconst FieldOptionsForm = memo(function FieldOptionsForm(props: FieldOptionsFormProps) {\r\n\tconst { fieldType, handleCancel, handleCreateField, handleDirtyChange, defaultField, conditionalSourceFields } =\r\n\t\tprops\r\n\tconst fieldCls = CompleteFieldTypeToClsMapping[fieldType]\r\n\tconst formik = useFormikContext<FormikUserFormRevision>()\r\n\r\n\tconst schema: ISchema = useMemo(() => {\r\n\t\tconst takenFieldLabels = getTakenFieldLabels(formik.values.fields)\r\n\t\t\t// when editing a field, we want to allow the user to keep the same label\r\n\t\t\t.filter((id) => id !== defaultField?.label)\r\n\r\n\t\tlet fields: BaseFormElement[] = commonFields(takenFieldLabels, fieldType)\r\n\t\tif (fieldCls === FieldSection) {\r\n\t\t\tif (conditionalSourceFields === undefined) {\r\n\t\t\t\tthrow new Error(\"Conditional source fields must be provided when changing sections.\")\r\n\t\t\t}\r\n\t\t\tfields = fields.concat(fieldCls.getFieldCreationSchema(conditionalSourceFields))\r\n\t\t} else {\r\n\t\t\tif (!(fieldCls.prototype instanceof BaseField)) {\r\n\t\t\t\tthrow new Error(`Field must be an instance of BaseField. Got ${fieldCls}.`)\r\n\t\t\t}\r\n\r\n\t\t\t// We now know that this is not a FieldSection. We need to tell TypeScript that.\r\n\t\t\ttype FieldClass = Exclude<typeof fieldCls, typeof FieldSection>\r\n\t\t\tfields = [...fields, ...(fieldCls as FieldClass).getFieldCreationSchema()]\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tfields,\r\n\t\t\tmeta: { readonly: false },\r\n\t\t\t// using the dialog title as the form title\r\n\t\t\ttitle: null,\r\n\t\t}\r\n\t}, [formik.values.fields, fieldType, fieldCls, defaultField?.label, conditionalSourceFields])\r\n\r\n\treturn (\r\n\t\t<FormRenderer\r\n\t\t\tschema={schema}\r\n\t\t\tvalues={defaultField as Form | undefined}\r\n\t\t\tonSubmit={handleCreateField}\r\n\t\t\t// only show cancel button if we are creating a new field, not editing an existing one\r\n\t\t\tcancelText={defaultField ? undefined : \"Back\"}\r\n\t\t\tonCancel={handleCancel}\r\n\t\t\tonDirtyChange={handleDirtyChange}\r\n\t\t/>\r\n\t)\r\n})\r\n\r\ninterface FieldBuilderProps extends Pick<FieldOptionsFormProps, \"conditionalSourceFields\"> {\r\n\tindex: number\r\n\tparentPath: NestedFieldPath\r\n\tinitial?: ISerializedField\r\n\tediting?: boolean\r\n\tchildren: ReactNode\r\n}\r\n\r\nexport type FieldBuilderArgs = Omit<FieldBuilderProps, \"children\">\r\n\r\nexport const FieldBuilder: FC<FieldBuilderProps> = memo(function FieldBuilder(props: FieldBuilderProps) {\r\n\tconst { parentPath, index, children, initial, editing, conditionalSourceFields } = props\r\n\tconst [fieldType, setFieldType] = useState<FieldTypeIdentifier>()\r\n\tconst [formIsDirty, setFormIsDirty] = useState<boolean>(false)\r\n\tconst type = initial?.type ?? fieldType\r\n\tconst typeName = type ? CompleteFieldTypeToClsMapping[type].fieldTypeName : undefined\r\n\tconst { setFieldValue, values } = useFormikContext<FormikUserFormRevision>()\r\n\r\n\tif (editing && !initial) throw new Error(\"Initial field must be provided if editing is true.\")\r\n\r\n\tconst openConfirmDiscardChangesDialog = useDiscardAlertDialog()\r\n\r\n\tconst showChooseField = !type && !editing && !initial\r\n\tconst title = showChooseField ? \"Choose a field type\" : `${typeName} settings`\r\n\r\n\tconst description = showChooseField\r\n\t\t? \"Select a field type to add to this section.\"\r\n\t\t: typeName?.toLowerCase() === \"section\"\r\n\t\t? \"Customize your section\"\r\n\t\t: `Customize your ${typeName?.toLowerCase()} field.`\r\n\r\n\tconst handleCancel = useCallback(() => {\r\n\t\tsetFieldType(undefined)\r\n\t\tsetFormIsDirty(false)\r\n\t}, [])\r\n\r\n\tconst handleCloseInterrupt = useCallback(\r\n\t\t(confirmClose: () => void) => {\r\n\t\t\tif (formIsDirty) {\r\n\t\t\t\topenConfirmDiscardChangesDialog({\r\n\t\t\t\t\tonDiscard: () => {\r\n\t\t\t\t\t\t// reset field type\r\n\t\t\t\t\t\tsetFieldType(undefined)\r\n\t\t\t\t\t\tconfirmClose()\r\n\t\t\t\t\t},\r\n\t\t\t\t})\r\n\t\t\t} else {\r\n\t\t\t\t// reset field type\r\n\t\t\t\tsetFieldType(undefined)\r\n\t\t\t\tconfirmClose()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[formIsDirty, openConfirmDiscardChangesDialog],\r\n\t)\r\n\r\n\tconst handleCreateField = useCallback(\r\n\t\t(form: Form, closeDialog: CloseDialogWithOptions) => {\r\n\t\t\tconst { label } = form\r\n\t\t\tif (!type) throw new Error(\"Field type must be selected before creating a field.\")\r\n\t\t\tif (!label || typeof label !== \"string\") throw new Error(\"Label must be provided before creating a field.\")\r\n\r\n\t\t\t// maintain the same identifier if we are editing an existing field\r\n\t\t\t// so that conditional pointers are not broken\r\n\t\t\tconst field = deserialize({\r\n\t\t\t\ttype,\r\n\t\t\t\t...form,\r\n\t\t\t\tidentifier: makeIdentifier(form.identifier, label),\r\n\t\t\t} as ISerializedField).serialize()\r\n\r\n\t\t\tconst parent: SerializedFieldSection[] | undefined = get(values, parentPath)\r\n\r\n\t\t\tif (parent === undefined) {\r\n\t\t\t\tthrow new Error(\"Parent path must point to an existing field.\")\r\n\t\t\t}\r\n\r\n\t\t\tlet newFields\r\n\r\n\t\t\tif (!Array.isArray(parent)) throw new Error(\"Parent path must point to an array.\")\r\n\r\n\t\t\tif (editing) {\r\n\t\t\t\t// replace existing field\r\n\t\t\t\tnewFields = replace(parent, index, field)\r\n\t\t\t} else {\r\n\t\t\t\t// insert new field\r\n\t\t\t\tnewFields = insert(parent, index, field)\r\n\t\t\t}\r\n\r\n\t\t\tsetFieldValue(parentPath, newFields).then()\r\n\t\t\tcloseDialog({ force: true })\r\n\t\t},\r\n\t\t[editing, type, values, parentPath, setFieldValue, index],\r\n\t)\r\n\r\n\tconst handleDirtyChange = useCallback((dirty: boolean) => setFormIsDirty(dirty), [])\r\n\r\n\tconst dialogContent = useCallback(\r\n\t\t(closeDialog: CloseDialogWithOptions) => {\r\n\t\t\tif (showChooseField) {\r\n\t\t\t\treturn <ChooseFieldToAdd setFieldType={setFieldType} />\r\n\t\t\t}\r\n\t\t\treturn (\r\n\t\t\t\t<FieldOptionsForm\r\n\t\t\t\t\tconditionalSourceFields={conditionalSourceFields}\r\n\t\t\t\t\thandleCancel={handleCancel}\r\n\t\t\t\t\thandleCreateField={(form) => handleCreateField(form, closeDialog)}\r\n\t\t\t\t\tfieldType={type as FieldTypeIdentifier}\r\n\t\t\t\t\tdefaultField={initial}\r\n\t\t\t\t\thandleDirtyChange={handleDirtyChange}\r\n\t\t\t\t/>\r\n\t\t\t)\r\n\t\t},\r\n\t\t[conditionalSourceFields, handleCancel, handleCreateField, handleDirtyChange, initial, showChooseField, type],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<Dialog onCloseInterrupt={handleCloseInterrupt} title={title} description={description} content={dialogContent}>\r\n\t\t\t{children}\r\n\t\t</Dialog>\r\n\t)\r\n})\r\n","import { DropdownMenuItemProps, IconButton } from \"@overmap-ai/blocks\"\r\nimport { Pencil1Icon, TrashIcon, PlusIcon, DragHandleDots2Icon, DotsVerticalIcon, CopyIcon } from \"@overmap-ai/blocks\"\r\nimport { Flex, DropdownMenu, Box, Responsive } from \"@overmap-ai/blocks\"\r\nimport { FC, PropsWithChildren, ReactNode, memo, useMemo } from \"react\"\r\nimport { DraggableProvidedDragHandleProps } from \"@hello-pangea/dnd\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\n\r\ninterface FieldActionsProps {\r\n\tremove: () => void\r\n\tdragHandleProps: DraggableProvidedDragHandleProps | null | undefined\r\n\teditProps: FieldBuilderArgs\r\n\tinsertAfterProps: FieldBuilderArgs\r\n\tduplicateProps: FieldBuilderArgs\r\n}\r\n\r\nconst DefaultWrapper: FC<{ children: ReactNode }> = ({ children }) => <>{children}</>\r\n\r\nconst forMobile = <D extends \"block\" | \"flex\">(mobile: boolean, display: D): Responsive<D | \"none\"> => ({\r\n\tinitial: mobile ? display : \"none\",\r\n\tsm: mobile ? \"none\" : display,\r\n})\r\n\r\nexport const FieldActions = memo(function FieldActions(props: FieldActionsProps) {\r\n\tconst { remove, dragHandleProps, editProps, insertAfterProps, duplicateProps } = props\r\n\r\n\tconst actions = useMemo(\r\n\t\t() => [\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: editProps,\r\n\t\t\t\tIcon: Pencil1Icon,\r\n\t\t\t\ttext: \"Edit\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tIcon: TrashIcon,\r\n\t\t\t\tbuttonProps: {\r\n\t\t\t\t\tonClick: remove,\r\n\t\t\t\t},\r\n\t\t\t\ttext: \"Delete\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: duplicateProps,\r\n\t\t\t\tIcon: CopyIcon,\r\n\t\t\t\ttext: \"Duplicate\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tWrapper: FieldBuilder,\r\n\t\t\t\twrapperProps: insertAfterProps,\r\n\t\t\t\tIcon: PlusIcon,\r\n\t\t\t\ttext: \"Add after\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\t// Wrapping icon in a div so that the asChild turns the button into a div\r\n\t\t\t\t// so that the drag handle props are not applied to the icon\r\n\t\t\t\t// Note: b/c the <button> does not handle the space-press event correctly\r\n\t\t\t\tIcon: (props: PropsWithChildren) => (\r\n\t\t\t\t\t<div {...props}>\r\n\t\t\t\t\t\t<DragHandleDots2Icon />\r\n\t\t\t\t\t</div>\r\n\t\t\t\t),\r\n\t\t\t\ttext: \"Reorder\",\r\n\t\t\t\tdisableOnMobile: true,\r\n\t\t\t\tbuttonProps: { ...dragHandleProps, asChild: true },\r\n\t\t\t},\r\n\t\t],\r\n\t\t[dragHandleProps, duplicateProps, editProps, insertAfterProps, remove],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<>\r\n\t\t\t{/* For tablet and up */}\r\n\t\t\t<Flex gap=\"4\" display={forMobile(false, \"flex\")}>\r\n\t\t\t\t{actions.map((Action) => {\r\n\t\t\t\t\tconst Wrapper = Action.Wrapper ?? DefaultWrapper\r\n\t\t\t\t\treturn (\r\n\t\t\t\t\t\t<Wrapper key={Action.text} {...(Action.wrapperProps as FieldBuilderArgs)}>\r\n\t\t\t\t\t\t\t<IconButton type=\"button\" variant=\"ghost\" aria-label={Action.text} {...Action.buttonProps}>\r\n\t\t\t\t\t\t\t\t<Action.Icon />\r\n\t\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t\t</Wrapper>\r\n\t\t\t\t\t)\r\n\t\t\t\t})}\r\n\t\t\t</Flex>\r\n\t\t\t{/* For mobile devices */}\r\n\t\t\t<Box display={forMobile(true, \"block\")}>\r\n\t\t\t\t<DropdownMenu\r\n\t\t\t\t\ttrigger={\r\n\t\t\t\t\t\t<IconButton variant=\"ghost\" aria-label=\"Actions menu\">\r\n\t\t\t\t\t\t\t<DotsVerticalIcon />\r\n\t\t\t\t\t\t</IconButton>\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// TODO: close on select when we can wrap the menu item in a FieldBuilder (via Wrapper)\r\n\t\t\t\t\tcloseOnSelect={false}\r\n\t\t\t\t\titems={actions\r\n\t\t\t\t\t\t.map((Action): DropdownMenuItemProps | null => {\r\n\t\t\t\t\t\t\tif (Action.disableOnMobile) return null\r\n\r\n\t\t\t\t\t\t\tconst Wrapper = Action.Wrapper ?? DefaultWrapper\r\n\t\t\t\t\t\t\treturn {\r\n\t\t\t\t\t\t\t\t...Action.buttonProps,\r\n\t\t\t\t\t\t\t\tonSelect: Action.buttonProps?.onClick,\r\n\t\t\t\t\t\t\t\tcontent: (\r\n\t\t\t\t\t\t\t\t\t<Wrapper {...(Action.wrapperProps as FieldBuilderArgs)}>\r\n\t\t\t\t\t\t\t\t\t\t<Flex gap=\"2\" align=\"center\">\r\n\t\t\t\t\t\t\t\t\t\t\t<Action.Icon />\r\n\t\t\t\t\t\t\t\t\t\t\t{Action.text}\r\n\t\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t\t</Wrapper>\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\t.filter((x): x is DropdownMenuItemProps => x !== null)}\r\n\t\t\t\t/>\r\n\t\t\t</Box>\r\n\t\t</>\r\n\t)\r\n})\r\n","export const formId = \"form-builder\"\r\n","import { ISerializedField } from \"@overmap-ai/core\"\r\nimport { Card, Flex } from \"@overmap-ai/blocks\"\r\nimport { deserialize, useFieldInput } from \"fields\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { Draggable } from \"@hello-pangea/dnd\"\r\nimport { FieldActions } from \"./FieldActions\"\r\nimport { formId } from \"./constants\"\r\nimport { FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { incrementFieldLabel } from \"./utils\"\r\n\r\ninterface FieldWithActionsProps {\r\n\tfield: ISerializedField\r\n\tindex: number\r\n\tsectionIndex: number\r\n\ttakenLabels: string[]\r\n\tremove: () => void\r\n}\r\n\r\nexport const FieldWithActions = memo(function FieldWithActions(props: FieldWithActionsProps) {\r\n\tconst { field, index, sectionIndex, takenLabels, remove } = props\r\n\tconst deserializedField = useMemo(() => deserialize(field), [field])\r\n\tconst input = useFieldInput(deserializedField, { formId, disabled: true })\r\n\r\n\tconst duplicateField = useCallback(\r\n\t\t(field: ISerializedField) => {\r\n\t\t\t// only already created sections can be duplicated so labels should exist\r\n\t\t\tif (field.label === null) {\r\n\t\t\t\tthrow new Error(`Expected a label for field ${field.identifier}`)\r\n\t\t\t}\r\n\t\t\treturn { ...field, label: incrementFieldLabel(field.label, takenLabels), identifier: \"\" }\r\n\t\t},\r\n\t\t[takenLabels],\r\n\t)\r\n\r\n\tconst editFieldProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex,\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tinitial: field,\r\n\t\t\tediting: true,\r\n\t\t}),\r\n\t\t[field, index, sectionIndex],\r\n\t)\r\n\r\n\tconst duplicateFieldProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: index + 1,\r\n\t\t\tinitial: duplicateField(field),\r\n\t\t}),\r\n\t\t[duplicateField, field, index, sectionIndex],\r\n\t)\r\n\r\n\tconst insertAfterProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: index + 1,\r\n\t\t\tinitial: undefined,\r\n\t\t}),\r\n\t\t[index, sectionIndex],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<Draggable draggableId={field.identifier} index={index}>\r\n\t\t\t{(draggableProvided) => (\r\n\t\t\t\t<Card\r\n\t\t\t\t\tref={draggableProvided.innerRef}\r\n\t\t\t\t\t{...draggableProvided.draggableProps}\r\n\t\t\t\t\t{...draggableProvided.dragHandleProps}\r\n\t\t\t\t\t// using margin bottom instead of flex gap to avoid a bug where the\r\n\t\t\t\t\t// gap is not applied to dragged elements\r\n\t\t\t\t\tmb=\"4\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Flex gap=\"4\" justify=\"between\" align=\"center\">\r\n\t\t\t\t\t\t{input}\r\n\t\t\t\t\t\t<FieldActions\r\n\t\t\t\t\t\t\tremove={remove}\r\n\t\t\t\t\t\t\teditProps={editFieldProps}\r\n\t\t\t\t\t\t\tduplicateProps={duplicateFieldProps}\r\n\t\t\t\t\t\t\tinsertAfterProps={insertAfterProps}\r\n\t\t\t\t\t\t\tdragHandleProps={draggableProvided.dragHandleProps}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Card>\r\n\t\t\t)}\r\n\t\t</Draggable>\r\n\t)\r\n})\r\n","import { PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { Button, Card, Em, Flex, Heading, Strong, Text } from \"@overmap-ai/blocks\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { memo, useCallback, useMemo } from \"react\"\r\nimport { Draggable, Droppable } from \"@hello-pangea/dnd\"\r\nimport { FieldActions } from \"./FieldActions\"\r\nimport { FormikUserFormRevision } from \"./typings\"\r\nimport {\r\n\temptySection,\r\n\tfindFieldByIdentifier,\r\n\tmakeConditionalSourceFields,\r\n\tremove,\r\n\tincrementFieldLabel,\r\n\tgetTakenFieldLabels,\r\n\tmakeIdentifier,\r\n} from \"./utils\"\r\nimport { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { DropState } from \"./DropDispatch\"\r\nimport { useAlertDialog } from \"@overmap-ai/blocks\"\r\nimport { FieldWithActions } from \"./FieldWithActions\"\r\nimport styles from \"styling.module.sass\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { valueIsFile } from \"fields\"\r\n\r\ninterface FieldSectionWithActionsProps {\r\n\tfield: SerializedFieldSection\r\n\tindex: number\r\n\tdropState: DropState\r\n}\r\n\r\nexport const FieldSectionWithActions = memo(function FieldSectionWithActions(props: FieldSectionWithActionsProps) {\r\n\tconst { field, index: sectionIndex, dropState } = props\r\n\tconst isDropDisabled = dropState[field.identifier]?.disabled\r\n\tconst { setFieldValue, values } = useFormikContext<FormikUserFormRevision>()\r\n\tconst alertDialog = useAlertDialog()\r\n\tconst takenFieldLabels = getTakenFieldLabels(values.fields)\r\n\r\n\tconst removeSectionConditions = useCallback(\r\n\t\t(sectionsToUpdate: SerializedFieldSection[], allSections: SerializedFieldSection[]) => {\r\n\t\t\tfor (const section of sectionsToUpdate) {\r\n\t\t\t\tconst sectionIndex = allSections.indexOf(section)\r\n\t\t\t\tsetFieldValue(`fields.${sectionIndex}.condition`, null).then()\r\n\t\t\t\tsetFieldValue(`fields.${sectionIndex}.conditional`, false).then()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[setFieldValue],\r\n\t)\r\n\r\n\tconst makeRemoveFieldAction = useCallback(\r\n\t\t(fieldIndex: number) => {\r\n\t\t\tconst removing = field.fields[fieldIndex]\r\n\t\t\tif (!removing) throw new Error(\"Could not find field to remove.\")\r\n\r\n\t\t\t// check if field is being used as a condition\r\n\t\t\tconst sectionsWithMatchingCondition: SerializedFieldSection[] = []\r\n\t\t\tfor (const section of values.fields) {\r\n\t\t\t\tif (section.condition?.identifier === removing.identifier) {\r\n\t\t\t\t\tsectionsWithMatchingCondition.push(section)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn {\r\n\t\t\t\tremoving,\r\n\t\t\t\taffectedSections: sectionsWithMatchingCondition,\r\n\t\t\t\taction: () => setFieldValue(`fields.${sectionIndex}.fields`, remove(field.fields, fieldIndex)),\r\n\t\t\t}\r\n\t\t},\r\n\t\t[field.fields, values.fields, setFieldValue, sectionIndex],\r\n\t)\r\n\r\n\tconst removeField = useCallback(\r\n\t\t(i: number) => {\r\n\t\t\tconst { affectedSections, action, removing } = makeRemoveFieldAction(i)\r\n\r\n\t\t\tconst cmd = () => {\r\n\t\t\t\taction().then()\r\n\t\t\t\tremoveSectionConditions(affectedSections, values.fields)\r\n\t\t\t}\r\n\r\n\t\t\tif (affectedSections.length > 0) {\r\n\t\t\t\tconst labels = affectedSections.map((section) => section.label).join(\", \")\r\n\t\t\t\treturn alertDialog({\r\n\t\t\t\t\ttitle: \"Remove condition?\",\r\n\t\t\t\t\tdescription: `${removing.label} is being used as a condition, deleting it will remove the condition from the ${labels} section(s).`,\r\n\t\t\t\t\tseverity: \"danger\",\r\n\t\t\t\t\tactionText: \"Remove\",\r\n\t\t\t\t\tonAction: cmd,\r\n\t\t\t\t})\r\n\t\t\t}\r\n\r\n\t\t\t// not a condition, remove field\r\n\t\t\tcmd()\r\n\t\t},\r\n\t\t[makeRemoveFieldAction, removeSectionConditions, values.fields, alertDialog],\r\n\t)\r\n\r\n\tconst removeSection = useCallback(() => {\r\n\t\tconst fieldSideEffects = field.fields.map((_, i) => makeRemoveFieldAction(i))\r\n\t\tconst affectedSections = fieldSideEffects.flatMap((sideEffect) => sideEffect.affectedSections)\r\n\r\n\t\tconst title = affectedSections.length ? \"Remove fields and conditions?\" : \"Remove fields?\"\r\n\t\tconst numFields = field.fields.length\r\n\t\tconst sectionLabels = affectedSections.map((section) => section.label).join(\", \")\r\n\t\tconst description = affectedSections.length\r\n\t\t\t? `Deleting this section will remove the ${numFields} field(s) it contains and will remove the conditions from following sections: ${sectionLabels}`\r\n\t\t\t: `Deleting this section will remove the ${numFields} field(s) it contains.`\r\n\r\n\t\tconst updatedSections = remove(values.fields, sectionIndex)\r\n\t\tconst cmd = () => setFieldValue(\"fields\", updatedSections)\r\n\r\n\t\tif (affectedSections.length > 0) {\r\n\t\t\treturn alertDialog({\r\n\t\t\t\ttitle,\r\n\t\t\t\tdescription,\r\n\t\t\t\tseverity: \"danger\",\r\n\t\t\t\tactionText: \"Remove\",\r\n\t\t\t\tonAction: () => {\r\n\t\t\t\t\t// remove the section (and fields)\r\n\t\t\t\t\tcmd().then(() => {\r\n\t\t\t\t\t\t// remove conditions from affected sections\r\n\t\t\t\t\t\tremoveSectionConditions(affectedSections, updatedSections)\r\n\t\t\t\t\t})\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\t// if no side effects for other sections, just remove the section\r\n\t\tcmd().then()\r\n\t}, [\r\n\t\tfield.fields,\r\n\t\tvalues.fields,\r\n\t\tsectionIndex,\r\n\t\tmakeRemoveFieldAction,\r\n\t\tsetFieldValue,\r\n\t\talertDialog,\r\n\t\tremoveSectionConditions,\r\n\t])\r\n\r\n\tconst duplicateSection = useCallback(\r\n\t\t(field: SerializedFieldSection) => {\r\n\t\t\t// only already created sections can be duplicated so labels should exist\r\n\t\t\tif (field.label === null) {\r\n\t\t\t\tthrow new Error(`Expected a label for field ${field.identifier}`)\r\n\t\t\t}\r\n\t\t\tconst newSectionLabel = incrementFieldLabel(field.label, takenFieldLabels)\r\n\t\t\tconst newFields = field.fields.map((f) => {\r\n\t\t\t\tconst newLabel = incrementFieldLabel(f.label, takenFieldLabels)\r\n\t\t\t\t// Make new identifiers now as they will not be made by FieldBuilder\r\n\t\t\t\treturn {\r\n\t\t\t\t\t...f,\r\n\t\t\t\t\tlabel: newLabel,\r\n\t\t\t\t\tidentifier: makeIdentifier(undefined, newLabel),\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\treturn { ...field, label: newSectionLabel, fields: newFields, identifier: \"\" }\r\n\t\t},\r\n\t\t[takenFieldLabels],\r\n\t)\r\n\r\n\tconst editSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: field,\r\n\t\t\tediting: true,\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex),\r\n\t\t}),\r\n\t\t[field, sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst insertSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex + 1,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: emptySection(),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1),\r\n\t\t}),\r\n\t\t[sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst insertFieldAtEndOfSection: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tparentPath: `fields.${sectionIndex}.fields`,\r\n\t\t\tindex: field.fields.length,\r\n\t\t\tinitial: undefined,\r\n\t\t}),\r\n\t\t[field.fields.length, sectionIndex],\r\n\t)\r\n\r\n\tconst duplicateSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: sectionIndex + 1,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: duplicateSection(field),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1),\r\n\t\t}),\r\n\t\t[duplicateSection, field, sectionIndex, values.fields],\r\n\t)\r\n\r\n\tconst conditionLabel = useMemo(\r\n\t\t() => findFieldByIdentifier(values.fields, field.condition?.identifier)?.label,\r\n\t\t[field.condition?.identifier, values.fields],\r\n\t)\r\n\r\n\tconst conditionComparison = Array.isArray(field.condition?.value) ? \"contains all of\" : \"equals\"\r\n\tif (valueIsFile(field.condition?.value)) throw new Error(\"File values are not supported for conditions.\")\r\n\tconst conditionValue = Array.isArray(field.condition?.value)\r\n\t\t? field.condition?.value?.map((v) => (typeof v === \"string\" ? v : v.label)).join(\", \")\r\n\t\t: field.condition?.value?.toString()\r\n\r\n\treturn (\r\n\t\t<Draggable draggableId={field.identifier} index={sectionIndex}>\r\n\t\t\t{(draggableProvided) => (\r\n\t\t\t\t<Card\r\n\t\t\t\t\tref={draggableProvided.innerRef}\r\n\t\t\t\t\t{...draggableProvided.draggableProps}\r\n\t\t\t\t\t{...draggableProvided.dragHandleProps}\r\n\t\t\t\t\t// using margin bottom instead of flex gap to avoid a bug where the\r\n\t\t\t\t\t// gap is not applied to dragged elements\r\n\t\t\t\t\tmb=\"4\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<Flex gap=\"3\" justify=\"between\" align=\"center\">\r\n\t\t\t\t\t\t<Flex direction=\"column\" gap=\"2\" grow=\"1\">\r\n\t\t\t\t\t\t\t<Flex direction=\"column\">\r\n\t\t\t\t\t\t\t\t<Heading as=\"h3\" size=\"3\">\r\n\t\t\t\t\t\t\t\t\t{field.label}\r\n\t\t\t\t\t\t\t\t</Heading>\r\n\t\t\t\t\t\t\t\t<Text className={styles.description}>{field.description}</Text>\r\n\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t{field.condition && (\r\n\t\t\t\t\t\t\t\t<Text size=\"1\">\r\n\t\t\t\t\t\t\t\t\t<Em>\r\n\t\t\t\t\t\t\t\t\t\tDisplay only if <Strong>{conditionLabel}</Strong> {conditionComparison}{\" \"}\r\n\t\t\t\t\t\t\t\t\t\t<Strong>{conditionValue}</Strong>\r\n\t\t\t\t\t\t\t\t\t</Em>\r\n\t\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t<Droppable droppableId={field.identifier} type=\"SECTION\" isDropDisabled={isDropDisabled}>\r\n\t\t\t\t\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t\t\t\t\t<Flex\r\n\t\t\t\t\t\t\t\t\t\tref={droppableProvided.innerRef}\r\n\t\t\t\t\t\t\t\t\t\t{...droppableProvided.droppableProps}\r\n\t\t\t\t\t\t\t\t\t\tdirection=\"column\"\r\n\t\t\t\t\t\t\t\t\t\tgap=\"0\"\r\n\t\t\t\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t\t\t\t{field.fields.map((child, i) => (\r\n\t\t\t\t\t\t\t\t\t\t\t<FieldWithActions\r\n\t\t\t\t\t\t\t\t\t\t\t\tkey={child.identifier}\r\n\t\t\t\t\t\t\t\t\t\t\t\tfield={child}\r\n\t\t\t\t\t\t\t\t\t\t\t\tindex={i}\r\n\t\t\t\t\t\t\t\t\t\t\t\tsectionIndex={sectionIndex}\r\n\t\t\t\t\t\t\t\t\t\t\t\tremove={() => removeField(i)}\r\n\t\t\t\t\t\t\t\t\t\t\t\ttakenLabels={takenFieldLabels}\r\n\t\t\t\t\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\r\n\t\t\t\t\t\t\t\t\t\t<FieldBuilder {...insertFieldAtEndOfSection}>\r\n\t\t\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"outline\">\r\n\t\t\t\t\t\t\t\t\t\t\t\t<PlusIcon /> Add a field\r\n\t\t\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t\t\t</FieldBuilder>\r\n\t\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t</Droppable>\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t<FieldActions\r\n\t\t\t\t\t\t\tremove={removeSection}\r\n\t\t\t\t\t\t\tinsertAfterProps={insertSectionProps}\r\n\t\t\t\t\t\t\tdragHandleProps={draggableProvided.dragHandleProps}\r\n\t\t\t\t\t\t\teditProps={editSectionProps}\r\n\t\t\t\t\t\t\tduplicateProps={duplicateSectionProps}\r\n\t\t\t\t\t\t/>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t</Card>\r\n\t\t\t)}\r\n\t\t</Draggable>\r\n\t)\r\n})\r\n","import { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { Reducer } from \"react\"\r\n\r\nexport interface SmallFieldSection {\r\n\t/** is dropping disabled in this section? */\r\n\tdisabled: boolean\r\n\t/** id's of field that may not be dropped on this section */\r\n\tconditionFields: Set<string>\r\n\t/** the index of the section the condition is in */\r\n\tconditionIndex?: number\r\n\t/** the index of the section */\r\n\tindex: number\r\n\t/** label of the section */\r\n\tlabel: string | null\r\n}\r\n\r\n// section id -> section state\r\nexport type DropState = Record<string, SmallFieldSection>\r\n\r\nexport type DropAction = { type: \"release\" } | { type: \"hold\"; fieldId: string } | { type: \"update\"; state: DropState }\r\n\r\nexport const reducer: Reducer<DropState, DropAction> = (state, action) => {\r\n\tconst next = { ...state }\r\n\r\n\tswitch (action.type) {\r\n\t\tcase \"release\":\r\n\t\t\tfor (const sectionId in next) {\r\n\t\t\t\tnext[sectionId]!.disabled = false\r\n\t\t\t}\r\n\t\t\treturn next\r\n\t\tcase \"hold\":\r\n\t\t\tfor (const sectionId in next) {\r\n\t\t\t\tif (next[sectionId]?.conditionFields.has(action.fieldId)) {\r\n\t\t\t\t\tnext[sectionId]!.disabled = true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn next\r\n\t\tcase \"update\":\r\n\t\t\treturn action.state\r\n\t}\r\n}\r\n\r\n/** @returns the index of the section containing the field */\r\nconst getConditionIndex = (fields: SerializedFieldSection[], identifier?: string): number | undefined => {\r\n\tif (!identifier) return undefined\r\n\r\n\tfor (let i = 0; i < fields.length; i++) {\r\n\t\tconst section = fields[i]\r\n\r\n\t\tif (!section) continue\r\n\r\n\t\tfor (const field of section.fields) {\r\n\t\t\tif (field.identifier === identifier) return i\r\n\t\t}\r\n\t}\r\n}\r\n\r\n/** creates a `DropState` from a list of `SerializedFieldSection` objects */\r\nexport const initializer = (fields: SerializedFieldSection[]): DropState => {\r\n\tconst acc: DropState = {}\r\n\r\n\tfor (let index = 0; index < fields.length; index++) {\r\n\t\tconst field = fields[index]\r\n\t\tif (!field) throw new Error(\"Field is undefined.\")\r\n\r\n\t\t// include any fields that are disabled by the condition of the previous field\r\n\t\tconst previousConditionFields = index > 0 ? acc[fields[index - 1]!.identifier]?.conditionFields : undefined\r\n\t\tconst disabledFields = new Set<string>(previousConditionFields)\r\n\t\tif (field.condition?.identifier) {\r\n\t\t\tdisabledFields.add(field.condition.identifier)\r\n\t\t}\r\n\r\n\t\tacc[field.identifier] = {\r\n\t\t\tdisabled: false,\r\n\t\t\tconditionFields: disabledFields,\r\n\t\t\tconditionIndex: getConditionIndex(fields, field.condition?.identifier),\r\n\t\t\tindex,\r\n\t\t\tlabel: field.label,\r\n\t\t}\r\n\t}\r\n\r\n\treturn acc\r\n}\r\n","import { SerializedFieldSection } from \"@overmap-ai/core\"\r\nimport { memo, useCallback, useEffect, useMemo, useReducer } from \"react\"\r\nimport { DragDropContext, Droppable, OnDragEndResponder, OnDragStartResponder } from \"@hello-pangea/dnd\"\r\nimport { FieldBuilder, FieldBuilderArgs } from \"./FieldBuilder\"\r\nimport { FormikUserFormRevision } from \"./typings\"\r\nimport { Flex, Button, useToast } from \"@overmap-ai/blocks\"\r\nimport { PlusIcon } from \"@overmap-ai/blocks\"\r\nimport { useFormikContext } from \"formik\"\r\nimport { emptySection, insert, makeConditionalSourceFields, remove, reorder } from \"./utils\"\r\nimport { FieldSectionWithActions } from \"./FieldSectionWithActions\"\r\nimport { initializer, reducer } from \"./DropDispatch\"\r\n\r\n/** \r\n * NOTE: Because this returns a new array instance on every call, it will cause re-renders if not destructured.\r\n * \r\n * BAD:\r\n * ```\r\nconst section: [SerializedFieldSection, string] | undefined = findSection(values.fields, source.droppableId)\r\nconst myEffect = useEffect(() => { doSomethingWith(section) }, [section])\r\n```\r\n * GOOD:\r\n```\r\nconst [section, i]: [SerializedFieldSection, string] | undefined = findSection(values.fields, source.droppableId)\r\nconst myEffect = useEffect(() => { doSomethingWith(section, index) }, [section, i])\r\n```\r\n*/\r\nconst findSection = (\r\n\tfields: SerializedFieldSection[],\r\n\tsectionId: string,\r\n): [SerializedFieldSection, string] | undefined => {\r\n\tfor (const [i, section] of Object.entries(fields)) {\r\n\t\tif (section.identifier === sectionId) return [section, i]\r\n\t}\r\n}\r\n\r\nexport const FieldsEditor = memo(function FieldsEditor() {\r\n\tconst { values, setFieldValue } = useFormikContext<FormikUserFormRevision>()\r\n\t// used to conditionally disable dropping on field sections so that a field\r\n\t// using a condition cannot be dropped after the section referencing it\r\n\tconst [dropState, dispatch] = useReducer(reducer, values.fields, initializer)\r\n\tconst { showInfo } = useToast()\r\n\r\n\tuseEffect(() => {\r\n\t\tdispatch({ type: \"update\", state: initializer(values.fields) })\r\n\t}, [dispatch, values.fields])\r\n\r\n\tconst handleDragStart = useCallback<OnDragStartResponder>((start) => {\r\n\t\t// validation for ensuring a condition is before the section\r\n\t\t// when dragging a section occurs in `handleDragEnd`\r\n\r\n\t\t// if dragging a field between sections\r\n\t\tif (start.type === \"SECTION\") {\r\n\t\t\tdispatch({ type: \"hold\", fieldId: start.draggableId })\r\n\t\t}\r\n\t}, [])\r\n\r\n\tconst handleDragEnd = useCallback<OnDragEndResponder>(\r\n\t\t(result) => {\r\n\t\t\tconst { source, destination, type, reason, draggableId } = result\r\n\t\t\tdispatch({ type: \"release\" })\r\n\r\n\t\t\tif (!destination || reason === \"CANCEL\") return\r\n\r\n\t\t\tif (type === \"ROOT\") {\r\n\t\t\t\tconst state = dropState[draggableId]\r\n\t\t\t\tif (!state) throw new Error(\"Could not find section context.\")\r\n\r\n\t\t\t\tlet dest =\r\n\t\t\t\t\ttypeof state.conditionIndex !== \"undefined\"\r\n\t\t\t\t\t\t? // cannot move a section with a condition before the condition's field\r\n\t\t\t\t\t\t Math.max(state.conditionIndex + 1, destination.index)\r\n\t\t\t\t\t\t: destination.index\r\n\r\n\t\t\t\t// check if this section contains another section's condition\r\n\t\t\t\tfor (const section of Object.values(dropState)) {\r\n\t\t\t\t\tif (section.conditionIndex === source.index) {\r\n\t\t\t\t\t\t// ensure condition field is above the section referencing it\r\n\t\t\t\t\t\tdest = Math.min(dest, section.index - 1)\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (dest != destination.index) {\r\n\t\t\t\t\t// TODO: change to a warning toast\r\n\t\t\t\t\tshowInfo({\r\n\t\t\t\t\t\ttitle: \"Reordered sections\",\r\n\t\t\t\t\t\tdescription: \"Sections with conditions must be below the fields they reference.\",\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn setFieldValue(\"fields\", reorder(values.fields, source.index, dest))\r\n\t\t\t}\r\n\r\n\t\t\tif (type !== \"SECTION\") throw new Error(\"Unexpected droppable type.\")\r\n\r\n\t\t\tconst [sourceSection, srcIndex] = findSection(values.fields, source.droppableId) ?? []\r\n\t\t\tconst [destinationSection, destIndex] = findSection(values.fields, destination.droppableId) ?? []\r\n\r\n\t\t\tif (!sourceSection?.fields || !destinationSection) throw new Error(\"Could not find section with fields.\")\r\n\r\n\t\t\tif (sourceSection.identifier === destinationSection.identifier) {\r\n\t\t\t\tsetFieldValue(\r\n\t\t\t\t\t`fields.${srcIndex}.fields`,\r\n\t\t\t\t\treorder(sourceSection.fields, source.index, destination.index),\r\n\t\t\t\t).then()\r\n\t\t\t} else {\r\n\t\t\t\tconst removed = sourceSection.fields[source.index]\r\n\t\t\t\tif (!removed) throw new Error(\"Could not find field to reorder.\")\r\n\r\n\t\t\t\tsetFieldValue(`fields.${srcIndex}.fields`, remove(sourceSection.fields, source.index)).then()\r\n\t\t\t\tsetFieldValue(\r\n\t\t\t\t\t`fields.${destIndex}.fields`,\r\n\t\t\t\t\tinsert(destinationSection.fields, destination.index, removed),\r\n\t\t\t\t).then()\r\n\t\t\t}\r\n\t\t},\r\n\t\t[values.fields, setFieldValue, dropState, showInfo],\r\n\t)\r\n\r\n\tconst makeFieldSectionProps: FieldBuilderArgs = useMemo(\r\n\t\t() => ({\r\n\t\t\tindex: values.fields.length,\r\n\t\t\tparentPath: \"fields\",\r\n\t\t\tinitial: emptySection(),\r\n\t\t\tconditionalSourceFields: makeConditionalSourceFields(values.fields, values.fields.length),\r\n\t\t}),\r\n\t\t[values.fields],\r\n\t)\r\n\r\n\treturn (\r\n\t\t<DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\r\n\t\t\t<Droppable droppableId=\"droppable\" type=\"ROOT\">\r\n\t\t\t\t{(droppableProvided) => (\r\n\t\t\t\t\t<Flex\r\n\t\t\t\t\t\tref={droppableProvided.innerRef}\r\n\t\t\t\t\t\t{...droppableProvided.droppableProps}\r\n\t\t\t\t\t\tdirection=\"column\"\r\n\t\t\t\t\t\tgap=\"0\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{values.fields.map((field, index) => (\r\n\t\t\t\t\t\t\t<FieldSectionWithActions\r\n\t\t\t\t\t\t\t\tkey={field.label}\r\n\t\t\t\t\t\t\t\tfield={field}\r\n\t\t\t\t\t\t\t\tindex={index}\r\n\t\t\t\t\t\t\t\tdropState={dropState}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t))}\r\n\t\t\t\t\t\t{droppableProvided.placeholder}\r\n\r\n\t\t\t\t\t\t<FieldBuilder {...makeFieldSectionProps}>\r\n\t\t\t\t\t\t\t<Button type=\"button\" variant=\"outline\">\r\n\t\t\t\t\t\t\t\t<PlusIcon /> Add a section\r\n\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t</FieldBuilder>\r\n\t\t\t\t\t</Flex>\r\n\t\t\t\t)}\r\n\t\t\t</Droppable>\r\n\t\t</DragDropContext>\r\n\t)\r\n})\r\n","import { formRevisionToSchema, StringField, TextField, useFieldInput } from \"../fields\"\r\nimport { FormikErrors, FormikProvider, useFormik } from \"formik\"\r\nimport { FormRenderer } from \"../renderer\"\r\nimport { Button, Flex, Heading, Tabs, Text } from \"@overmap-ai/blocks\"\r\nimport { FormBuilderSaveHandler, FormikUserFormRevision, NewForm } from \"./typings\"\r\nimport { FieldsEditor } from \"./FieldsEditor\"\r\nimport { hasKeys } from \"utils\"\r\nimport { forwardRef, memo, ReactNode, useCallback, useMemo } from \"react\"\r\nimport { ISchema } from \"fields/typings\"\r\nimport { wrapRootFieldsWithFieldSection } from \"./utils\"\r\nimport { formId } from \"./constants\"\r\nimport { UserFormRevision } from \"@overmap-ai/core\"\r\n\r\nconst initialValues: NewForm = {\r\n\ttitle: \"\",\r\n\tdescription: \"\",\r\n\tfields: [],\r\n}\r\n\r\nconst title = new StringField({\r\n\tlabel: \"Title\",\r\n\tminLength: 0,\r\n\tmaxLength: 100,\r\n\trequired: true,\r\n\tidentifier: \"title\",\r\n})\r\n\r\nconst titleProps = { formId, placeholder: \"Give your form a title.\" }\r\n\r\nconst description = new TextField({\r\n\tlabel: \"Description\",\r\n\tminLength: 0,\r\n\tmaxLength: 1000,\r\n\trequired: false,\r\n\tidentifier: \"description\",\r\n})\r\n\r\nconst descriptionProps = { formId, placeholder: \"Explain the purpose of this form.\" }\r\n\r\nconst previewSubmit = () => {\r\n\talert(\"This is a form preview, your data will not be saved.\")\r\n}\r\n\r\ninterface FormBuilderProps {\r\n\tonCancel?: () => void\r\n\tonSave: FormBuilderSaveHandler\r\n\t/** A revision of an existing form to edit. To create a new form, pass `undefined`. */\r\n\trevision?: UserFormRevision\r\n\t/** A heading for the `FormBuilder`\r\n\t * @default \"Create a new form\" or \"Edit form\" if `revision` is passed\r\n\t */\r\n\theading?: ReactNode\r\n}\r\n\r\nexport const FormBuilder = memo(\r\n\tforwardRef<HTMLDivElement, FormBuilderProps>((props, ref) => {\r\n\t\tconst { onCancel, onSave, revision } = props\r\n\t\tconst defaultHeading = revision ? \"Edit form\" : \"Create a new form\"\r\n\t\tconst { heading = defaultHeading } = props\r\n\r\n\t\tconst validate = useCallback((form: FormikUserFormRevision) => {\r\n\t\t\tconst errors: FormikErrors<FormikUserFormRevision> = {}\r\n\t\t\tif (!form.title) {\r\n\t\t\t\terrors.title = \"Title is required.\"\r\n\t\t\t}\r\n\t\t\tif (!form.fields || form.fields.length === 0) {\r\n\t\t\t\terrors.fields = \"At least one field is required.\"\r\n\t\t\t}\r\n\t\t\tif (hasKeys(errors)) {\r\n\t\t\t\treturn errors\r\n\t\t\t}\r\n\t\t}, [])\r\n\r\n\t\tconst formik = useFormik<FormikUserFormRevision>({\r\n\t\t\tinitialValues: wrapRootFieldsWithFieldSection(revision) ?? initialValues,\r\n\t\t\tvalidate,\r\n\t\t\tonSubmit: (form) => onSave(form),\r\n\t\t\t// only validate the entire for on submit\r\n\t\t\tvalidateOnChange: false,\r\n\t\t\tvalidateOnBlur: false,\r\n\t\t})\r\n\r\n\t\tconst previewSchema: ISchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values])\r\n\r\n\t\tconst titleInput = useFieldInput(title, titleProps)\r\n\t\tconst descriptionInput = useFieldInput(description, descriptionProps)\r\n\t\tconst FormBuilderHeading = useMemo(\r\n\t\t\t() => (typeof heading === \"object\" ? heading : <Heading>{heading}</Heading>),\r\n\t\t\t[heading],\r\n\t\t)\r\n\r\n\t\treturn (\r\n\t\t\t<Tabs.Root ref={ref} defaultValue=\"edit\">\r\n\t\t\t\t<Flex direction=\"column\" gap=\"2\">\r\n\t\t\t\t\t<Tabs.List>\r\n\t\t\t\t\t\t<Tabs.Trigger value=\"edit\">Edit</Tabs.Trigger>\r\n\t\t\t\t\t\t<Tabs.Trigger value=\"preview\">Preview</Tabs.Trigger>\r\n\t\t\t\t\t</Tabs.List>\r\n\r\n\t\t\t\t\t<Tabs.Content value=\"edit\">\r\n\t\t\t\t\t\t{FormBuilderHeading}\r\n\t\t\t\t\t\t<Text>\r\n\t\t\t\t\t\t\tAdd a new form field by clicking a + button. Specify options for each field, then drag and\r\n\t\t\t\t\t\t\tdrop to rearrange them. You can see what a submitted form might look like in the{\" \"}\r\n\t\t\t\t\t\t\t<em>Preview</em> tab, but{\" \"}\r\n\t\t\t\t\t\t\t<strong>field values entered on this page will not be saved.</strong>\r\n\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t<Flex asChild direction=\"column\" gap=\"2\" mt=\"3\">\r\n\t\t\t\t\t\t\t<form id={formId} onSubmit={formik.handleSubmit}>\r\n\t\t\t\t\t\t\t\t<FormikProvider value={formik}>\r\n\t\t\t\t\t\t\t\t\t{titleInput}\r\n\t\t\t\t\t\t\t\t\t{descriptionInput}\r\n\t\t\t\t\t\t\t\t\t<FieldsEditor />\r\n\t\t\t\t\t\t\t\t\t<Text severity=\"danger\" size=\"1\">\r\n\t\t\t\t\t\t\t\t\t\t{typeof formik.errors.fields === \"string\" && formik.errors.fields}\r\n\t\t\t\t\t\t\t\t\t</Text>\r\n\t\t\t\t\t\t\t\t</FormikProvider>\r\n\t\t\t\t\t\t\t\t<Flex justify=\"end\" gap=\"2\">\r\n\t\t\t\t\t\t\t\t\t<Button type=\"button\" variant=\"soft\" onClick={onCancel}>\r\n\t\t\t\t\t\t\t\t\t\tCancel\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t\t<Button type=\"submit\" disabled={!formik.isValid}>\r\n\t\t\t\t\t\t\t\t\t\tSave\r\n\t\t\t\t\t\t\t\t\t</Button>\r\n\t\t\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t\t\t</form>\r\n\t\t\t\t\t\t</Flex>\r\n\t\t\t\t\t</Tabs.Content>\r\n\r\n\t\t\t\t\t<Tabs.Content value=\"preview\">\r\n\t\t\t\t\t\t<FormRenderer schema={previewSchema} onSubmit={previewSubmit} />\r\n\t\t\t\t\t</Tabs.Content>\r\n\t\t\t\t</Flex>\r\n\t\t\t</Tabs.Root>\r\n\t\t)\r\n\t}),\r\n)\r\n"],"names":["description","styles","formId","BooleanInput","NumberInput","TextField","DateInput","StringInput","TextInput","SelectInput","MultiStringInput","MultiSelectInput","value","FieldInputCloner","FieldSectionLayout","option","_a","DisplayFile","url","name","size","v","FormSubmissionBrowserEntry","FormSubmissionBrowser","PatchField","initialValues","values","FieldToChoose","ChooseFieldToAdd","FieldOptionsForm","FieldBuilder","title","FieldActions","remove","props","FieldWithActions","field","FieldSectionWithActions","sectionIndex","_b","FieldsEditor"],"mappings":"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"}
|