Add HTML5 object UI context
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-17 00:07:30 +03:00
parent a8baa2aa49
commit 1da745c52e
3 changed files with 44 additions and 2 deletions
+33 -1
View File
@@ -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"""
<div class="object-context" data-html5-object-context data-html5-object-name="{escape(str(name))}">
<div class="panel-title">Object context</div>
@@ -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))}
</dl>
<div class="compact-list">
{''.join(_named_node_item("attr", item) for item in attributes[:6]) or '<p class="muted padded">Реквизиты не найдены</p>'}
{''.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"""
<article class="object-context-item" data-html5-object-context-item="ui-form">
<strong>{escape(str(form_name))}</strong>
<small>{escape(" · ".join(details) or "UI metadata")}</small>
</article>
"""
def _authoring_diff_item(line: object) -> str:
kind = str(getattr(line, "kind", ""))
text = str(getattr(line, "text", ""))
+2 -1
View File
@@ -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",
)
+9
View File
@@ -237,6 +237,9 @@ def test_html5_object_context_fragment(tmp_path: Path):
<TabularSection name="Товары" qualifiedName="Документ.ЗаказПокупателя.Товары">
<Attribute name="Количество" qualifiedName="Документ.ЗаказПокупателя.Товары.Количество" />
</TabularSection>
<Form name="ФормаДокумента" qualifiedName="Документ.ЗаказПокупателя.ФормаДокумента">
<Command name="Провести" qualifiedName="Документ.ЗаказПокупателя.ФормаДокумента.Провести" action="ПровестиКоманда" />
</Form>
</Document>
<Role name="Менеджер" qualifiedName="Роль.Менеджер">
<Right object="Документ.ЗаказПокупателя" read="true" write="true" post="true" />
@@ -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 "<html" not in context.text