Add HTML5 authoring change apply form
This commit is contained in:
@@ -430,7 +430,12 @@ 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:
|
def render_html5_authoring_diff_result(
|
||||||
|
project_id: str,
|
||||||
|
preview: object | None = None,
|
||||||
|
error: str | None = None,
|
||||||
|
request_payload: dict | None = None,
|
||||||
|
) -> str:
|
||||||
if preview is None and error is None:
|
if preview is None and error is None:
|
||||||
return '<div class="authoring-diff-result" data-html5-authoring-diff-result></div>'
|
return '<div class="authoring-diff-result" data-html5-authoring-diff-result></div>'
|
||||||
if error:
|
if error:
|
||||||
@@ -451,6 +456,11 @@ def render_html5_authoring_diff_result(project_id: str, preview: object | None =
|
|||||||
next_version_id = str(getattr(version_preview, "next_version_id", ""))
|
next_version_id = str(getattr(version_preview, "next_version_id", ""))
|
||||||
check_rows = "".join(_authoring_check_item(check) for check in checks[:8])
|
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>'
|
diff_rows = "".join(_authoring_diff_item(line) for line in diff[:12]) or '<p class="muted padded">Diff пустой</p>'
|
||||||
|
apply_form = (
|
||||||
|
_authoring_apply_change_set_form(project_id, request_payload or {}, next_version_id)
|
||||||
|
if changed and next_version_id
|
||||||
|
else ""
|
||||||
|
)
|
||||||
return f"""
|
return f"""
|
||||||
<div class="authoring-diff-result" data-html5-authoring-diff-result data-html5-project-id="{escape(project_id)}">
|
<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>
|
<div class="panel-title">Diff preview · {'changed' if changed else 'unchanged'}</div>
|
||||||
@@ -461,6 +471,39 @@ def render_html5_authoring_diff_result(project_id: str, preview: object | None =
|
|||||||
</article>
|
</article>
|
||||||
<div class="check-list">{check_rows}</div>
|
<div class="check-list">{check_rows}</div>
|
||||||
<div class="diff-list">{diff_rows}</div>
|
<div class="diff-list">{diff_rows}</div>
|
||||||
|
{apply_form}
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_html5_authoring_apply_result(project_id: str, result: object | None = None, error: str | None = None) -> str:
|
||||||
|
if result is None and error is None:
|
||||||
|
return '<div class="authoring-apply-result" data-html5-authoring-apply-result></div>'
|
||||||
|
if error:
|
||||||
|
return f"""
|
||||||
|
<div class="authoring-apply-result" data-html5-authoring-apply-result>
|
||||||
|
<div class="panel-title">Apply change-set</div>
|
||||||
|
<p class="muted padded">{escape(error)}</p>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
status = str(getattr(result, "status", "UNKNOWN"))
|
||||||
|
change_id = str(getattr(result, "change_id", ""))
|
||||||
|
version = getattr(result, "version", None)
|
||||||
|
version_id = str(getattr(version, "version_id", ""))
|
||||||
|
return f"""
|
||||||
|
<div
|
||||||
|
class="authoring-apply-result"
|
||||||
|
data-html5-authoring-apply-result
|
||||||
|
data-html5-authoring-change="{escape(change_id)}"
|
||||||
|
data-html5-version-id="{escape(version_id)}"
|
||||||
|
>
|
||||||
|
<div class="panel-title">Apply change-set</div>
|
||||||
|
<article class="authoring-change">
|
||||||
|
<strong>{escape(status)}</strong>
|
||||||
|
<span>{escape(change_id)}</span>
|
||||||
|
<small>{escape(version_id)}</small>
|
||||||
|
</article>
|
||||||
|
<p class="muted padded">Change-set применен в workspace для проекта {escape(project_id)}.</p>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1178,6 +1221,33 @@ def _authoring_rollback_form(project_id: str, change_id: str, rollback_version_i
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _authoring_apply_change_set_form(project_id: str, payload: dict, next_version_id: str) -> str:
|
||||||
|
return f"""
|
||||||
|
<form
|
||||||
|
class="authoring-preview-form"
|
||||||
|
data-html5-authoring-apply-form
|
||||||
|
method="post"
|
||||||
|
action="/html5/projects/{quote(project_id)}/authoring/apply-change-set"
|
||||||
|
hx-post="/html5/projects/{quote(project_id)}/authoring/apply-change-set"
|
||||||
|
hx-target="[data-html5-authoring-apply-result]"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="routine_name" value="{escape(str(payload.get("routine_name") or ""))}" />
|
||||||
|
<input type="hidden" name="source_path" value="{escape(str(payload.get("source_path") or ""))}" />
|
||||||
|
<textarea hidden name="original_text">{escape(str(payload.get("original_text") or ""))}</textarea>
|
||||||
|
<textarea hidden name="proposed_text">{escape(str(payload.get("proposed_text") or ""))}</textarea>
|
||||||
|
<input type="hidden" name="task_id" value="{escape(str(payload.get("task_id") or ""))}" />
|
||||||
|
<input type="hidden" name="session_id" value="{escape(str(payload.get("session_id") or ""))}" />
|
||||||
|
<input type="hidden" name="user_id" value="{escape(str(payload.get("user_id") or ""))}" />
|
||||||
|
<input type="hidden" name="expected_next_version_id" value="{escape(next_version_id)}" />
|
||||||
|
<input name="approved_by" placeholder="approved_by" required />
|
||||||
|
<input name="approval_note" placeholder="Комментарий" />
|
||||||
|
<button type="submit">Apply change-set</button>
|
||||||
|
</form>
|
||||||
|
{render_html5_authoring_apply_result(project_id)}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _node_source_text(node: object | None) -> str:
|
def _node_source_text(node: object | None) -> str:
|
||||||
if node is None:
|
if node is None:
|
||||||
return "// Модуль не найден в snapshot.\n// HTML5 IDE показывает серверный fallback без клиентского JS."
|
return "// Модуль не найден в snapshot.\n// HTML5 IDE показывает серверный fallback без клиентского JS."
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ from neo4j import AsyncGraphDatabase
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from api_server.html5 import (
|
from api_server.html5 import (
|
||||||
|
render_html5_authoring_apply_result,
|
||||||
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_diff_result,
|
||||||
@@ -1809,12 +1810,47 @@ async def html5_project_authoring_semantic_diff_preview(project_id: str, request
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
preview = _authoring_semantic_diff_preview(project_id, payload)
|
preview = _authoring_semantic_diff_preview(project_id, payload)
|
||||||
html = render_html5_authoring_diff_result(project_id, preview)
|
html = render_html5_authoring_diff_result(
|
||||||
|
project_id,
|
||||||
|
preview,
|
||||||
|
request_payload={
|
||||||
|
"routine_name": payload.routine_name,
|
||||||
|
"source_path": payload.source_path,
|
||||||
|
"original_text": payload.original_text,
|
||||||
|
"proposed_text": payload.proposed_text,
|
||||||
|
"task_id": payload.task_id,
|
||||||
|
"session_id": payload.session_id,
|
||||||
|
"user_id": payload.user_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
except HTTPException as error:
|
except HTTPException as error:
|
||||||
html = render_html5_authoring_diff_result(project_id, error=str(error.detail))
|
html = render_html5_authoring_diff_result(project_id, error=str(error.detail))
|
||||||
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/apply-change-set")
|
||||||
|
async def html5_project_authoring_apply_change_set(project_id: str, request: Request) -> Response:
|
||||||
|
form = await _html5_form_data(request)
|
||||||
|
payload = AuthoringApplyChangeSetRequest(
|
||||||
|
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"),
|
||||||
|
expected_next_version_id=_form_value(form, "expected_next_version_id") or "",
|
||||||
|
approved_by=_form_value(form, "approved_by") or "",
|
||||||
|
approval_note=_form_value(form, "approval_note"),
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
result = await authoring_apply_change_set(project_id, payload)
|
||||||
|
html = render_html5_authoring_apply_result(project_id, result)
|
||||||
|
except HTTPException as error:
|
||||||
|
html = render_html5_authoring_apply_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)
|
||||||
|
|||||||
@@ -2316,12 +2316,37 @@ def test_authoring_context_and_completion_preview(tmp_path: Path):
|
|||||||
assert html5_diff_preview.status_code == 200
|
assert html5_diff_preview.status_code == 200
|
||||||
assert "text/html" in html5_diff_preview.headers["content-type"]
|
assert "text/html" in html5_diff_preview.headers["content-type"]
|
||||||
assert "data-html5-authoring-diff-result" in html5_diff_preview.text
|
assert "data-html5-authoring-diff-result" in html5_diff_preview.text
|
||||||
|
assert "data-html5-authoring-apply-form" in html5_diff_preview.text
|
||||||
|
assert f'hx-post="/html5/projects/{project_id}/authoring/apply-change-set"' in html5_diff_preview.text
|
||||||
|
assert "data-html5-authoring-apply-result" in html5_diff_preview.text
|
||||||
assert "Diff preview" in html5_diff_preview.text
|
assert "Diff preview" in html5_diff_preview.text
|
||||||
assert "Если Отказ Тогда" in html5_diff_preview.text
|
assert "Если Отказ Тогда" in html5_diff_preview.text
|
||||||
assert "task-session" in html5_diff_preview.text
|
assert "task-session" in html5_diff_preview.text
|
||||||
assert "BLOCKED" in html5_diff_preview.text
|
assert "BLOCKED" in html5_diff_preview.text
|
||||||
assert "<html" not in html5_diff_preview.text
|
assert "<html" not in html5_diff_preview.text
|
||||||
|
|
||||||
|
html5_blocked_change_apply = client.post(
|
||||||
|
f"/html5/projects/{project_id}/authoring/apply-change-set",
|
||||||
|
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",
|
||||||
|
"expected_next_version_id": "wrong-version",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert html5_blocked_change_apply.status_code == 200
|
||||||
|
assert "text/html" in html5_blocked_change_apply.headers["content-type"]
|
||||||
|
assert "data-html5-authoring-apply-result" in html5_blocked_change_apply.text
|
||||||
|
assert "Expected version id does not match current preview" in html5_blocked_change_apply.text
|
||||||
|
assert "<html" not in html5_blocked_change_apply.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