212 lines
6.0 KiB
TypeScript
212 lines
6.0 KiB
TypeScript
import { DateField, TextField } from "@refinedev/antd";
|
|
import { Field, FieldType } from "../utils/queryFields";
|
|
import { NumberFieldUnit, NumberFieldUnitRange } from "./numberField";
|
|
import { enrichText } from "../utils/parsing";
|
|
import dayjs from "dayjs";
|
|
import utc from "dayjs/plugin/utc";
|
|
import { Checkbox, Form, Input, InputNumber, Select, Typography } from "antd";
|
|
import { FormItemProps, Rule } from "antd/es/form";
|
|
import { DateTimePicker } from "./dateTimePicker";
|
|
import { InputNumberRange } from "./inputNumberRange";
|
|
|
|
dayjs.extend(utc);
|
|
|
|
const { Title } = Typography;
|
|
|
|
/**
|
|
* Title and value to display an extra field. Used for the show pages.
|
|
* @param props
|
|
* @returns
|
|
*/
|
|
export function ExtraFieldDisplay(props: { field: Field; value: string | undefined }) {
|
|
const { field, value } = props;
|
|
|
|
let item;
|
|
if (value !== undefined) {
|
|
const parsedValue = JSON.parse(value);
|
|
|
|
if (field.field_type === FieldType.integer) {
|
|
item = (
|
|
<NumberFieldUnit
|
|
value={parsedValue ?? ""}
|
|
unit={field.unit ?? ""}
|
|
options={{
|
|
maximumFractionDigits: 0,
|
|
minimumFractionDigits: 0,
|
|
}}
|
|
/>
|
|
);
|
|
} else if (field.field_type === FieldType.float) {
|
|
item = (
|
|
<NumberFieldUnit
|
|
value={parsedValue ?? ""}
|
|
unit={field.unit ?? ""}
|
|
options={{
|
|
maximumFractionDigits: 3,
|
|
minimumFractionDigits: 0,
|
|
}}
|
|
/>
|
|
);
|
|
} else if (field.field_type === FieldType.integer_range || field.field_type === FieldType.float_range) {
|
|
if (!Array.isArray(parsedValue) || parsedValue.length !== 2) {
|
|
return <TextField value={parsedValue} />;
|
|
}
|
|
item = (
|
|
<NumberFieldUnitRange
|
|
value={parsedValue}
|
|
unit={field.unit ?? ""}
|
|
options={{
|
|
maximumFractionDigits: field.field_type === FieldType.float_range ? 3 : 0,
|
|
minimumFractionDigits: 0,
|
|
}}
|
|
/>
|
|
);
|
|
} else if (field.field_type === FieldType.text) {
|
|
item = <TextField value={enrichText(parsedValue)} />;
|
|
} else if (field.field_type === FieldType.datetime) {
|
|
item = (
|
|
<DateField
|
|
value={dayjs.utc(parsedValue).local()}
|
|
title={dayjs.utc(parsedValue).local().format()}
|
|
format="YYYY-MM-DD HH:mm:ss"
|
|
/>
|
|
);
|
|
} else if (field.field_type === FieldType.boolean) {
|
|
item = <TextField value={parsedValue ? "Yes" : "No"} />;
|
|
} else if (field.field_type === FieldType.choice && !field.multi_choice) {
|
|
item = <TextField value={parsedValue} />;
|
|
} else if (field.field_type === FieldType.choice && field.multi_choice) {
|
|
item = <TextField value={parsedValue.join(", ")} />;
|
|
} else {
|
|
throw new Error(`Unknown field type: ${field.field_type}`);
|
|
}
|
|
} else {
|
|
item = <></>;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Title level={5}>{field.name}</Title>
|
|
{item}
|
|
</>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Form item for an extra field. Used for the edit pages.
|
|
* @param props
|
|
* @returns
|
|
*/
|
|
export function ExtraFieldFormItem(props: { field: Field; setDefaultValue?: boolean }) {
|
|
const { field } = props;
|
|
|
|
let inputNode;
|
|
const rules: Rule[] = [
|
|
{
|
|
required: false,
|
|
},
|
|
];
|
|
const formItemProps: FormItemProps = {};
|
|
if (field.field_type === FieldType.integer) {
|
|
inputNode = <InputNumber addonAfter={field.unit} precision={0} />;
|
|
rules.push({
|
|
type: "integer",
|
|
});
|
|
} else if (field.field_type === FieldType.float) {
|
|
inputNode = <InputNumber addonAfter={field.unit} precision={3} />;
|
|
rules.push({
|
|
type: "number",
|
|
});
|
|
} else if (field.field_type === FieldType.integer_range) {
|
|
inputNode = <InputNumberRange unit={field.unit} precision={0} />;
|
|
} else if (field.field_type === FieldType.float_range) {
|
|
inputNode = <InputNumberRange unit={field.unit} precision={3} />;
|
|
} else if (field.field_type === FieldType.text) {
|
|
inputNode = <Input />;
|
|
rules.push({
|
|
type: "string",
|
|
});
|
|
} else if (field.field_type === FieldType.datetime) {
|
|
inputNode = <DateTimePicker />;
|
|
} else if (field.field_type === FieldType.boolean) {
|
|
inputNode = <Checkbox />;
|
|
formItemProps.valuePropName = "checked";
|
|
rules.push({
|
|
type: "boolean",
|
|
});
|
|
} else if (field.field_type === FieldType.choice) {
|
|
inputNode = (
|
|
<Select
|
|
mode={field.multi_choice ? "multiple" : undefined}
|
|
options={field.choices?.map((choice) => ({ label: choice, value: choice }))}
|
|
/>
|
|
);
|
|
rules.push({
|
|
type: field.multi_choice ? "array" : "string",
|
|
});
|
|
} else {
|
|
throw new Error(`Unknown field type: ${field.field_type}`);
|
|
}
|
|
|
|
if (props.setDefaultValue) {
|
|
formItemProps.initialValue = field.default_value;
|
|
}
|
|
|
|
return (
|
|
<Form.Item label={field.name} name={["extra", field.key]} rules={rules} {...formItemProps}>
|
|
{inputNode}
|
|
</Form.Item>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Convert the string-based value extra key-values of an entity to their JSON-parsed values.
|
|
* @param obj
|
|
* @returns
|
|
*/
|
|
export function ParsedExtras<T extends { extra?: { [key: string]: string } }>(
|
|
obj: T
|
|
): Omit<T, "extra"> & { extra?: { [key: string]: unknown } } {
|
|
if (obj.extra) {
|
|
const newExtra: { [key: string]: unknown } = {};
|
|
Object.entries(obj.extra).forEach(([key, value]) => {
|
|
try {
|
|
newExtra[key] = JSON.parse(value);
|
|
} catch (e) {
|
|
newExtra[key] = value;
|
|
}
|
|
});
|
|
return {
|
|
...obj,
|
|
extra: newExtra,
|
|
};
|
|
} else {
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert the JSON-parsed value extra key-values of an entity to their string values.
|
|
* @param obj
|
|
* @returns
|
|
*/
|
|
export function StringifiedExtras<T extends { extra?: { [key: string]: unknown } }>(
|
|
obj: T
|
|
): Omit<T, "extra"> & { extra?: { [key: string]: string } } {
|
|
if (obj.extra) {
|
|
const newExtra: { [key: string]: string } = {};
|
|
Object.entries(obj.extra).forEach(([key, value]) => {
|
|
newExtra[key] = JSON.stringify(value);
|
|
});
|
|
return {
|
|
...obj,
|
|
extra: newExtra,
|
|
};
|
|
} else {
|
|
return {
|
|
...obj,
|
|
extra: undefined,
|
|
};
|
|
}
|
|
}
|