diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index 166a062..1386cb4 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -264,12 +264,13 @@ }, "extra_fields": { "tab": "Extra Fields", - "description": "

Here you can add extra custom fields to your entities.

Once a field is added, you can not change its key or type, and for choice type fields you can not remove choices or change the multi select state. If you remove a field, the associated data for all entities will be deleted.

Extra fields can not be sorted or filtered in the table views.

", + "description": "

Here you can add extra custom fields to your entities.

Once a field is added, you can not change its key or type, and for choice type fields you can not remove choices or change the multi choice state. If you remove a field, the associated data for all entities will be deleted.

Default value is only applied to new items.

Extra fields can not be sorted or filtered in the table views.

", "params": { "key": "Key", "name": "Name", "field_type": "Type", "unit": "Unit", + "order": "Order", "default_value": "Default Value", "choices": "Choices", "multi_choice": "Multi Choice" @@ -288,7 +289,9 @@ "boolean_false": "No", "choices_missing_error": "You cannot remove choices. The following choices are missing: {{choices}}", "non_unique_key_error": "The key must be unique.", - "key_not_changed": "Please change the key to something else." + "key_not_changed": "Please change the key to something else.", + "delete_confirm": "Delete field {{name}}?", + "delete_confirm_description": "This will delete the field and all associated data for all entities." } }, "documentTitle": { diff --git a/client/src/pages/settings/ExtraFieldsSettings.tsx b/client/src/pages/settings/ExtraFieldsSettings.tsx index 10653b4..2efe9b3 100644 --- a/client/src/pages/settings/ExtraFieldsSettings.tsx +++ b/client/src/pages/settings/ExtraFieldsSettings.tsx @@ -7,12 +7,13 @@ import { FormInstance, Input, InputNumber, + Popconfirm, Select, + Space, Table, - Typography, message, } from "antd"; -import { EntityType, Field, FieldType, useGetFields, useSetField } from "./queryFields"; +import { EntityType, Field, FieldType, useDeleteField, useGetFields, useSetField } from "./queryFields"; import { useTranslate } from "@refinedev/core"; import { useState } from "react"; import { ColumnType } from "antd/es/table"; @@ -20,6 +21,17 @@ import { Trans } from "react-i18next"; import { useParams } from "react-router-dom"; import { FormItemProps, Rule } from "antd/es/form"; import { PlusOutlined } from "@ant-design/icons"; +import dayjs from "dayjs"; +import utc from "dayjs/plugin/utc"; +import timezone from "dayjs/plugin/timezone"; +import advancedFormat from "dayjs/plugin/advancedFormat"; + +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(advancedFormat); + +// Localized date time format with timezone +const dateTimeFormat = "YYYY-MM-DD HH:mm:ss z"; interface EditableCellProps extends React.HTMLAttributes { record: FieldHolder; @@ -29,22 +41,33 @@ interface EditableCellProps extends React.HTMLAttributes { children: React.ReactNode; } -interface ColumnProps extends ColumnType { - editable: boolean; - required: boolean; -} - interface FieldHolder { key: string; field: Field; is_new: boolean; } +const canEditField = (dataIndex: string, isNew: boolean) => { + if (isNew) { + return true; + } + return dataIndex !== "key" && dataIndex !== "field_type" && dataIndex !== "multi_choice"; +}; + const EditableCell: React.FC = ({ record, editing, dataIndex, children, form, ...restProps }) => { const t = useTranslate(); - if (!editing) { - return {children}; + if (!editing || !canEditField(dataIndex, record.is_new)) { + return ( + + {children} + + ); } const fieldType = form.getFieldValue("field_type") as FieldType; @@ -60,6 +83,7 @@ const EditableCell: React.FC = ({ record, editing, dataIndex, rules.push({ required: true, min: 1, + max: 64, pattern: /^[a-z0-9_]+$/, }); rules.push({ @@ -123,6 +147,14 @@ const EditableCell: React.FC = ({ record, editing, dataIndex, rules.push({ required: true, min: 1, + max: 128, + }); + } else if (dataIndex === "order") { + inputNode = ; + rules.push({ + required: true, + min: 0, + type: "integer", }); } else if (dataIndex === "unit") { if ( @@ -131,12 +163,13 @@ const EditableCell: React.FC = ({ record, editing, dataIndex, fieldType === FieldType.float || fieldType === FieldType.float_range ) { - inputNode = ; + inputNode = ; } else { inputNode = null; } rules.push({ required: false, + max: 16, }); } else if (dataIndex === "default_value") { if (fieldType === FieldType.boolean) { @@ -158,7 +191,7 @@ const EditableCell: React.FC = ({ record, editing, dataIndex, } else if (fieldType === FieldType.float) { inputNode = ; rules.push({ - type: "float", + type: "number", }); } else if (fieldType === FieldType.integer_range) { inputNode = ; @@ -173,7 +206,7 @@ const EditableCell: React.FC = ({ record, editing, dataIndex, pattern: /^-?\d+([.,]\d+)?\s*-\s*-?\d+([.,]\d+)?$/, }); } else if (fieldType === FieldType.datetime) { - inputNode = ; + inputNode = ; } else if (fieldType === FieldType.choice) { inputNode = (