From 1da745c52ed4f2ad1637bf2cc975b55ac0936bcc Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sun, 17 May 2026 00:07:30 +0300 Subject: [PATCH] Add HTML5 object UI context --- services/api-server/src/api_server/html5.py | 34 ++++++++++++++++++++- services/api-server/src/api_server/main.py | 3 +- services/api-server/tests/test_api.py | 9 ++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py index 52bc319..812e992 100644 --- a/services/api-server/src/api_server/html5.py +++ b/services/api-server/src/api_server/html5.py @@ -321,6 +321,7 @@ def render_html5_object_context( schema: object | None, impact: object | None, access: object | None = None, + ui: object | None = None, ) -> str: if schema is None or impact is None: return f""" @@ -339,6 +340,7 @@ def render_html5_object_context( roles = getattr(impact, "roles", []) or [] jobs = getattr(impact, "jobs", []) or [] grants = getattr(access, "grants", []) if access is not None else [] + ui_forms = getattr(ui, "forms", []) if ui is not None else [] return f"""
Object context
@@ -351,12 +353,13 @@ def render_html5_object_context( {_metric("Tables", len(sections))} {_metric("Modules", len(modules))} {_metric("Routines", len(routines))} - {_metric("Forms", len(forms))} + {_metric("Forms", len(ui_forms) or len(forms))} {_metric("Roles", len(grants) or len(roles))}
{''.join(_named_node_item("attr", item) for item in attributes[:6]) or '

Реквизиты не найдены

'} {''.join(_tabular_section_item(item) for item in sections[:4])} + {''.join(_ui_form_item(item) for item in ui_forms[:4])} {''.join(_role_access_item(item) for item in grants[:6])} {''.join(_named_node_item("routine", item) for item in routines[:6])} {''.join(_named_node_item("job", item) for item in jobs[:4])} @@ -1391,6 +1394,35 @@ def _role_access_item(grant: object) -> str: """ +def _ui_form_item(form_semantics: object) -> str: + form = getattr(form_semantics, "form", None) + commands = getattr(form_semantics, "commands", []) or [] + elements = getattr(form_semantics, "elements", []) or [] + handlers = getattr(form_semantics, "command_handlers", {}) or {} + form_name = getattr(form, "qualified_name", None) or getattr(form, "name", "form") + command_names = [ + str(getattr(command, "name", getattr(command, "qualified_name", ""))) + for command in commands[:3] + ] + handler_names = [ + str(getattr(handler, "name", getattr(handler, "qualified_name", ""))) + for handler in list(handlers.values())[:3] + ] + details = [] + if command_names: + details.append("cmd: " + ", ".join(command_names)) + if handler_names: + details.append("handler: " + ", ".join(handler_names)) + if elements: + details.append(f"{len(elements)} elements") + return f""" +
+ {escape(str(form_name))} + {escape(" · ".join(details) or "UI metadata")} +
+ """ + + def _authoring_diff_item(line: object) -> str: kind = str(getattr(line, "kind", "")) text = str(getattr(line, "text", "")) diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py index 6a841f6..3884e83 100644 --- a/services/api-server/src/api_server/main.py +++ b/services/api-server/src/api_server/main.py @@ -1746,8 +1746,9 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res schema = await get_object_schema(project_id, object_name) impact = await get_object_impact(project_id, object_name) access = await get_object_access(project_id, object_name) + ui = await get_object_ui(project_id, object_name) return Response( - render_html5_object_context(project_id, schema, impact, access), + render_html5_object_context(project_id, schema, impact, access, ui), media_type="text/html; charset=utf-8", ) diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py index df4e3a0..41ac53b 100644 --- a/services/api-server/tests/test_api.py +++ b/services/api-server/tests/test_api.py @@ -237,6 +237,9 @@ def test_html5_object_context_fragment(tmp_path: Path): +
+ + @@ -245,6 +248,9 @@ def test_html5_object_context_fragment(tmp_path: Path): """, encoding="utf-8", ) + module = tmp_path / "Documents" / "ЗаказПокупателя" / "Ext" / "ObjectModule.bsl" + module.parent.mkdir(parents=True) + module.write_text("Процедура ПровестиКоманда()\nКонецПроцедуры\n", encoding="utf-8") client = TestClient(app) indexed = client.post("/projects/index", json={"path": str(tmp_path), "project_id": project_id}) assert indexed.status_code == 200 @@ -262,6 +268,9 @@ def test_html5_object_context_fragment(tmp_path: Path): assert "Документ.ЗаказПокупателя" in context.text assert "Контрагент" in context.text assert "Товары" in context.text + assert "ФормаДокумента" in context.text + assert "Провести" in context.text + assert "ПровестиКоманда" in context.text assert "Роль.Менеджер" in context.text assert "read, write, post" in context.text or "post, read, write" in context.text assert "