From ebded03ecf1a9887ecad33d7359be963974e597a Mon Sep 17 00:00:00 2001 From: Mikhail Date: Thu, 21 May 2026 05:08:03 +0300 Subject: [PATCH] Update legacy form designer UI --- .../project-setup/project-setup-client.tsx | 279 ++++++++++++++++-- 1 file changed, 247 insertions(+), 32 deletions(-) diff --git a/frontend/sfera-web/src/components/project-setup/project-setup-client.tsx b/frontend/sfera-web/src/components/project-setup/project-setup-client.tsx index e966807..f130702 100644 --- a/frontend/sfera-web/src/components/project-setup/project-setup-client.tsx +++ b/frontend/sfera-web/src/components/project-setup/project-setup-client.tsx @@ -5500,7 +5500,7 @@ function ObjectWorkbench({ - + ) { +type FormDesignerElementDraft = { + id: string; + name: string; + caption: string; + kind: "input" | "date" | "checkbox" | "table" | "group" | "text"; + binding: string; + width: "stretch" | "half" | "third"; +}; + +function FormDesignerPanel({ projectId, object }: Readonly<{ projectId: string; object: NormalizedMetadataObject }>) { const [activeFormName, setActiveFormName] = useState(null); const activeForm = object.forms.find((form) => form.name === activeFormName) ?? object.forms[0] ?? null; - const formFields = [...object.attributes, ...object.tabular_sections]; + const activeFormKey = activeForm?.name ?? ""; + const [titleByForm, setTitleByForm] = useState>({}); + const [layoutByForm, setLayoutByForm] = useState>({}); + const [elementOverrides, setElementOverrides] = useState>>({}); + const [extraElementsByForm, setExtraElementsByForm] = useState>({}); + const [newElementName, setNewElementName] = useState(""); + const [newElementKind, setNewElementKind] = useState("input"); + const baseElements = activeForm ? buildFormDesignerElements(object, activeForm) : []; + const elements = [...baseElements, ...(extraElementsByForm[activeFormKey] ?? [])].map((element) => ({ + ...element, + ...(elementOverrides[element.id] ?? {}) + })); + const formTitle = titleByForm[activeFormKey] ?? activeForm?.name ?? "Форма"; + const layout = layoutByForm[activeFormKey] ?? "auto"; + const html5EditorHref = activeForm + ? `/html5/projects/${encodeURIComponent(projectId)}/forms/editor?form=${encodeURIComponent(formQualifiedName(object, activeForm))}` + : `/html5/projects/${encodeURIComponent(projectId)}/forms/editor`; + + const updateElement = (id: string, patch: Partial) => { + setElementOverrides((current) => ({ ...current, [id]: { ...(current[id] ?? {}), ...patch } })); + }; + + const addElement = () => { + const name = newElementName.trim(); + if (!name || !activeFormKey) { + return; + } + const next: FormDesignerElementDraft = { + id: `draft-${activeFormKey}-${Date.now()}`, + name, + caption: name, + kind: newElementKind, + binding: name, + width: "stretch" + }; + setExtraElementsByForm((current) => ({ ...current, [activeFormKey]: [...(current[activeFormKey] ?? []), next] })); + setNewElementName(""); + }; + return ( -
-
-
Form designer
- {object.forms.length} +
+
+
+
Редактор формы
+
Управляемая форма 1С 8.5: элементы, команды, реквизиты и модуль остаются частью объекта.
+
+
+ {activeForm ? ( + + HTML5 редактор + + ) : null} + {object.forms.length} +
{activeForm ? ( -
+
{object.forms.map((form) => ( ))}
-
-
-
-
{activeForm.name}
-
{object.qualified_name}
+
+
+
+ {formTitle} + 1C:Enterprise 8.5-style managed form +
+
+ {object.commands.length ? object.commands.map((command) => ( + + )) : Команды не описаны} +
+
+ {elements.map((element) => ( + + ))}
- {activeForm.kind} -
-
- {formFields.slice(0, 18).map((field) => ( -
-
{field.name}
-
{field.kind}
-
- ))} - {formFields.length === 0 ? ( -
Поля формы не найдены в structure-only metadata.
- ) : null}
-
-
Form context
-
- +
+
+
Свойства формы
+
+ + +
+
+
+
- - `${key}: ${String(value)}`)} /> +
+
Добавить элемент
+
+ setNewElementName(event.target.value)} + placeholder="Новый реквизит" + className="h-8 border border-border bg-background px-2 text-sm text-foreground" + /> + +
+ +
+
+ {elements.map((element) => ( +
+
{element.name}
+ updateElement(element.id, { caption: event.target.value })} + className="h-8 border border-border bg-background px-2 text-sm text-foreground" + /> +
+ + +
+ updateElement(element.id, { binding: event.target.value })} + className="h-8 border border-border bg-background px-2 text-sm text-foreground" + /> +
+ ))} +
+ `${key}: ${String(value)}`)} />
) : ( @@ -5578,6 +5731,68 @@ function FormDesignerPanel({ object }: Readonly<{ object: NormalizedMetadataObje ); } +function LegacyFormControl({ element, forceHalf }: Readonly<{ element: FormDesignerElementDraft; forceHalf: boolean }>) { + const span = element.kind === "table" || element.kind === "group" ? "col-span-12" : forceHalf || element.width === "half" ? "col-span-6" : element.width === "third" ? "col-span-4" : "col-span-12"; + return ( +
+ + {legacyFormControlInput(element)} +
+ ); +} + +function legacyFormControlInput(element: FormDesignerElementDraft): ReactNode { + if (element.kind === "table") { + return ( +
+
+ {element.binding} + Количество + Сумма +
+
+
+ ); + } + if (element.kind === "checkbox") { + return ; + } + if (element.kind === "group") { + return
{element.binding}
; + } + if (element.kind === "text") { + return