Add HTML5 authoring diff preview
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-16 23:24:42 +03:00
parent b7876db8ef
commit c14db34f14
3 changed files with 101 additions and 0 deletions
@@ -371,6 +371,25 @@ def render_html5_authoring_preview(project_id: str, preview: object | None, erro
<button type="submit">Preview</button>
</form>
{render_html5_authoring_preview_result(project_id)}
<form
class="authoring-preview-form"
data-html5-authoring-diff-form
method="post"
action="/html5/projects/{quote(project_id)}/authoring/semantic-diff-preview"
hx-post="/html5/projects/{quote(project_id)}/authoring/semantic-diff-preview"
hx-target="[data-html5-authoring-diff-result]"
hx-swap="outerHTML"
>
<input name="routine_name" placeholder="routine_name" />
<input name="source_path" placeholder="source_path" />
<input name="task_id" placeholder="task_id" />
<input name="session_id" placeholder="session_id" />
<input name="user_id" placeholder="user_id" />
<textarea name="original_text" placeholder="Original BSL"></textarea>
<textarea name="proposed_text" placeholder="Proposed BSL"></textarea>
<button type="submit">Diff preview</button>
</form>
{render_html5_authoring_diff_result(project_id)}
</div>
"""
return render_html5_authoring_preview_result(project_id, preview, error)
@@ -411,6 +430,41 @@ def render_html5_authoring_preview_result(project_id: str, preview: object | Non
"""
def render_html5_authoring_diff_result(project_id: str, preview: object | None = None, error: str | None = None) -> str:
if preview is None and error is None:
return '<div class="authoring-diff-result" data-html5-authoring-diff-result></div>'
if error:
return f"""
<div class="authoring-diff-result" data-html5-authoring-diff-result>
<div class="panel-title">Diff preview</div>
<p class="muted padded">{escape(error)}</p>
</div>
"""
changed = bool(getattr(preview, "changed", False))
added = getattr(preview, "added_lines", 0)
removed = getattr(preview, "removed_lines", 0)
target = getattr(preview, "target", None)
target_name = getattr(target, "qualified_name", None) or getattr(target, "name", None) or "target unavailable"
checks = getattr(preview, "checks", []) or []
diff = getattr(preview, "semantic_diff", []) or []
version_preview = getattr(preview, "version_preview", None)
next_version_id = str(getattr(version_preview, "next_version_id", ""))
check_rows = "".join(_authoring_check_item(check) for check in checks[:8])
diff_rows = "".join(_authoring_diff_item(line) for line in diff[:12]) or '<p class="muted padded">Diff пустой</p>'
return f"""
<div class="authoring-diff-result" data-html5-authoring-diff-result data-html5-project-id="{escape(project_id)}">
<div class="panel-title">Diff preview · {'changed' if changed else 'unchanged'}</div>
<article class="authoring-change">
<strong>{escape(str(target_name))}</strong>
<span>+{escape(str(added))} / -{escape(str(removed))}</span>
<small>{escape(next_version_id or "version preview unavailable")}</small>
</article>
<div class="check-list">{check_rows}</div>
<div class="diff-list">{diff_rows}</div>
</div>
"""
def render_html5_authoring_change_detail(project_id: str, preview: object | None) -> str:
if preview is None:
return f"""
@@ -38,6 +38,7 @@ from pydantic import BaseModel, Field
from api_server.html5 import (
render_html5_authoring_changes,
render_html5_authoring_change_detail,
render_html5_authoring_diff_result,
render_html5_authoring_preview_result,
render_html5_authoring_rollback_result,
render_html5_editor,
@@ -1794,6 +1795,26 @@ async def html5_project_authoring_completion_preview(project_id: str, request: R
return Response(html, media_type="text/html; charset=utf-8")
@app.post("/html5/projects/{project_id}/authoring/semantic-diff-preview")
async def html5_project_authoring_semantic_diff_preview(project_id: str, request: Request) -> Response:
form = await _html5_form_data(request)
payload = AuthoringSemanticDiffPreviewRequest(
routine_name=_form_value(form, "routine_name"),
source_path=_form_value(form, "source_path"),
original_text=_form_value(form, "original_text") or "",
proposed_text=_form_value(form, "proposed_text") or "",
task_id=_form_value(form, "task_id"),
session_id=_form_value(form, "session_id"),
user_id=_form_value(form, "user_id"),
)
try:
preview = _authoring_semantic_diff_preview(project_id, payload)
html = render_html5_authoring_diff_result(project_id, preview)
except HTTPException as error:
html = render_html5_authoring_diff_result(project_id, error=str(error.detail))
return Response(html, media_type="text/html; charset=utf-8")
@app.get("/html5/projects/{project_id}/setup")
async def html5_project_setup(project_id: str) -> Response:
setup = _project_setup_response(project_id)
+26
View File
@@ -115,6 +115,8 @@ def test_html5_server_rendered_project_editor(tmp_path: Path):
assert "data-html5-authoring-preview" in editor.text
assert "data-html5-authoring-preview-form" in editor.text
assert f'hx-post="/html5/projects/{project_id}/authoring/completion-preview"' in editor.text
assert "data-html5-authoring-diff-form" in editor.text
assert f'hx-post="/html5/projects/{project_id}/authoring/semantic-diff-preview"' in editor.text
assert "data-html5-authoring-changes" in editor.text
assert f'hx-get="/html5/projects/{project_id}/authoring/changes"' in editor.text
assert 'hx-get="/html5/projects/' in editor.text
@@ -2296,6 +2298,30 @@ def test_authoring_context_and_completion_preview(tmp_path: Path):
assert "ADD" in html5_preview.text
assert "<html" not in html5_preview.text
html5_diff_preview = client.post(
f"/html5/projects/{project_id}/authoring/semantic-diff-preview",
data={
"routine_name": "Проведение",
"source_path": str(module),
"original_text": source_text,
"proposed_text": source_text.replace(
" Сумма = 0;",
" Сумма = 0;\n Если Отказ Тогда\n Возврат;\n КонецЕсли;",
),
"task_id": "task.authoring",
"session_id": "session.authoring",
"user_id": "dev.ivan",
},
)
assert html5_diff_preview.status_code == 200
assert "text/html" in html5_diff_preview.headers["content-type"]
assert "data-html5-authoring-diff-result" in html5_diff_preview.text
assert "Diff preview" in html5_diff_preview.text
assert "Если Отказ Тогда" in html5_diff_preview.text
assert "task-session" in html5_diff_preview.text
assert "BLOCKED" in html5_diff_preview.text
assert "<html" not in html5_diff_preview.text
diff_preview = client.post(
f"/projects/{project_id}/authoring/semantic-diff-preview",
json={