Add HTML5 authoring diff preview
This commit is contained in:
@@ -371,6 +371,25 @@ def render_html5_authoring_preview(project_id: str, preview: object | None, erro
|
|||||||
<button type="submit">Preview</button>
|
<button type="submit">Preview</button>
|
||||||
</form>
|
</form>
|
||||||
{render_html5_authoring_preview_result(project_id)}
|
{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>
|
</div>
|
||||||
"""
|
"""
|
||||||
return render_html5_authoring_preview_result(project_id, preview, error)
|
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:
|
def render_html5_authoring_change_detail(project_id: str, preview: object | None) -> str:
|
||||||
if preview is None:
|
if preview is None:
|
||||||
return f"""
|
return f"""
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ from pydantic import BaseModel, Field
|
|||||||
from api_server.html5 import (
|
from api_server.html5 import (
|
||||||
render_html5_authoring_changes,
|
render_html5_authoring_changes,
|
||||||
render_html5_authoring_change_detail,
|
render_html5_authoring_change_detail,
|
||||||
|
render_html5_authoring_diff_result,
|
||||||
render_html5_authoring_preview_result,
|
render_html5_authoring_preview_result,
|
||||||
render_html5_authoring_rollback_result,
|
render_html5_authoring_rollback_result,
|
||||||
render_html5_editor,
|
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")
|
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")
|
@app.get("/html5/projects/{project_id}/setup")
|
||||||
async def html5_project_setup(project_id: str) -> Response:
|
async def html5_project_setup(project_id: str) -> Response:
|
||||||
setup = _project_setup_response(project_id)
|
setup = _project_setup_response(project_id)
|
||||||
|
|||||||
@@ -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" in editor.text
|
||||||
assert "data-html5-authoring-preview-form" 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 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 "data-html5-authoring-changes" in editor.text
|
||||||
assert f'hx-get="/html5/projects/{project_id}/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
|
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 "ADD" in html5_preview.text
|
||||||
assert "<html" not 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(
|
diff_preview = client.post(
|
||||||
f"/projects/{project_id}/authoring/semantic-diff-preview",
|
f"/projects/{project_id}/authoring/semantic-diff-preview",
|
||||||
json={
|
json={
|
||||||
|
|||||||
Reference in New Issue
Block a user