Files
iistwin/shared/field-types.ts
Ильяс Султанов 1f5ecb6da4 fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric,
  чтобы браузер не округлял значения через input type=number
- пробелы при вставке в number-поля удаляются
- бэкенд нормализует значения number-полей в строку перед сохранением
- добавлен хелпер normalizeFieldValueForStorage

Closes: искажение расчётного счёта и других длинных числовых полей
2026-07-07 21:03:40 +03:00

67 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Unified field type registry.
* Used by backend (MCP, API validation) and frontend (form/table editors).
* Add a type here once — it becomes available everywhere.
*/
export interface FieldTypeDef {
id: string;
label: string;
iconName: string; // lucide icon name, resolved on the frontend
supportsOptions: boolean;
allowedIn: Array<"form" | "global" | "table" | "user">;
}
export const FIELD_TYPE_DEFINITIONS: FieldTypeDef[] = [
{ id: "text", label: "Текстовое поле", iconName: "Type", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "number", label: "Числовое поле", iconName: "Hash", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "date", label: "Дата", iconName: "Calendar", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "datetime", label: "Дата и время", iconName: "Clock", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "select", label: "Выпадающий список", iconName: "ChevronDown", supportsOptions: true, allowedIn: ["form", "global", "table", "user"] },
{ id: "checkbox", label: "Чекбокс", iconName: "CheckSquare", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "checklist", label: "Чек-лист", iconName: "ListChecks", supportsOptions: true, allowedIn: ["form", "global", "table", "user"] },
{ id: "toggle", label: "Переключатель", iconName: "ToggleLeft", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "button", label: "Кнопка", iconName: "MousePointer", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "user", label: "Пользователь/Роль", iconName: "Users", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "file", label: "Загрузка файлов", iconName: "Paperclip", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "textarea", label: "Многострочный текст", iconName: "AlignLeft", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "rich-text", label: "Богатый текстовый редактор", iconName: "FileText", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "history-number", label: "Числовое поле с историей", iconName: "History", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "table", label: "Выбор из таблицы", iconName: "Table", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "task", label: "Связь с задачей", iconName: "Link2", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "company", label: "Организация (DaData)", iconName: "Building2", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "geo", label: "Адрес с координатами", iconName: "MapPin", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "formula", label: "Формула", iconName: "Calculator", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "contract-number", label: "Номер договора", iconName: "FileSignature", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
{ id: "contact", label: "Контакт", iconName: "User", supportsOptions: false, allowedIn: ["form", "global", "table", "user"] },
];
export const ALL_FIELD_TYPES = FIELD_TYPE_DEFINITIONS.map((t) => t.id);
export type GanttFieldRole = "start" | "end" | "milestone" | null;
export const GANTT_FIELD_ROLES: { value: GanttFieldRole; label: string }[] = [
{ value: "start", label: "Начало" },
{ value: "end", label: "Конец" },
{ value: "milestone", label: "Веха" },
];
export function isValidGanttFieldRole(value: unknown): value is GanttFieldRole {
return value === null || value === "start" || value === "end" || value === "milestone";
}
export const FORM_FIELD_TYPES = FIELD_TYPE_DEFINITIONS.filter((t) => t.allowedIn.includes("form")).map((t) => t.id);
export const GLOBAL_FIELD_TYPES = FIELD_TYPE_DEFINITIONS.filter((t) => t.allowedIn.includes("global")).map((t) => t.id);
export const TABLE_FIELD_TYPES = FIELD_TYPE_DEFINITIONS.filter((t) => t.allowedIn.includes("table")).map((t) => t.id);
export const USER_FIELD_TYPES = FIELD_TYPE_DEFINITIONS.filter((t) => t.allowedIn.includes("user")).map((t) => t.id);
/** Quick lookup helpers */
export function getFieldTypeDef(id: string): FieldTypeDef | undefined {
return FIELD_TYPE_DEFINITIONS.find((t) => t.id === id);
}
export function isValidFieldType(id: string, context: "form" | "global" | "table" | "user"): boolean {
const def = getFieldTypeDef(id);
return def ? def.allowedIn.includes(context) : false;
}