feat: include scratchpad in session export (markdown, text, HTML)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -273,6 +273,16 @@ def _generate_markdown_export(session: Session, options: SessionExport) -> str:
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
# Scratchpad / Evidence section
|
||||
scratchpad = getattr(session, 'scratchpad', '') or ''
|
||||
if scratchpad.strip():
|
||||
lines.append("## Evidence / Reference")
|
||||
lines.append("")
|
||||
lines.append(scratchpad)
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
lines.append("## Troubleshooting Steps")
|
||||
lines.append("")
|
||||
|
||||
@@ -311,6 +321,14 @@ def _generate_text_export(session: Session, options: SessionExport) -> str:
|
||||
lines.append(f"Completed: {session.completed_at.strftime('%Y-%m-%d %H:%M')}")
|
||||
lines.append("")
|
||||
|
||||
# Scratchpad / Evidence section
|
||||
scratchpad = getattr(session, 'scratchpad', '') or ''
|
||||
if scratchpad.strip():
|
||||
lines.append("EVIDENCE / REFERENCE")
|
||||
lines.append("-" * 20)
|
||||
lines.append(scratchpad)
|
||||
lines.append("")
|
||||
|
||||
lines.append("TROUBLESHOOTING STEPS")
|
||||
lines.append("-" * 20)
|
||||
|
||||
@@ -360,6 +378,12 @@ def _generate_html_export(session: Session, options: SessionExport) -> str:
|
||||
html.append(f'<p><strong>Completed:</strong> {session.completed_at.strftime("%Y-%m-%d %H:%M")}</p>')
|
||||
html.append('</div>')
|
||||
|
||||
# Scratchpad / Evidence section
|
||||
scratchpad = getattr(session, 'scratchpad', '') or ''
|
||||
if scratchpad.strip():
|
||||
html.append('<h2>Evidence / Reference</h2>')
|
||||
html.append(f'<div class="scratchpad" style="white-space: pre-wrap; background: #f9f9f9; padding: 12px; border-radius: 4px; margin-bottom: 20px;">{scratchpad}</div>')
|
||||
|
||||
html.append('<h2>Troubleshooting Steps</h2>')
|
||||
|
||||
for i, decision in enumerate(session.decisions, 1):
|
||||
|
||||
@@ -461,3 +461,145 @@ class TestSessions:
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["scratchpad"] == "post-resolution notes"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_export_includes_scratchpad_markdown(
|
||||
self, client: AsyncClient, auth_headers: dict, test_tree: dict
|
||||
):
|
||||
"""Test that markdown export includes scratchpad content."""
|
||||
# Create session with scratchpad
|
||||
create_response = await client.post(
|
||||
"/api/v1/sessions",
|
||||
json={"tree_id": test_tree["id"], "ticket_number": "SP-001"},
|
||||
headers=auth_headers
|
||||
)
|
||||
session_id = create_response.json()["id"]
|
||||
|
||||
# Add scratchpad content
|
||||
await client.patch(
|
||||
f"/api/v1/sessions/{session_id}/scratchpad",
|
||||
json={"scratchpad": "- Server IP: 192.168.1.50\n- Error: 0x80070005"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
# Export as markdown
|
||||
response = await client.post(
|
||||
f"/api/v1/sessions/{session_id}/export",
|
||||
json={"format": "markdown", "include_tree_info": True},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
assert "## Evidence / Reference" in content
|
||||
assert "192.168.1.50" in content
|
||||
assert "0x80070005" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_export_includes_scratchpad_text(
|
||||
self, client: AsyncClient, auth_headers: dict, test_tree: dict
|
||||
):
|
||||
"""Test that text export includes scratchpad content."""
|
||||
create_response = await client.post(
|
||||
"/api/v1/sessions",
|
||||
json={"tree_id": test_tree["id"]},
|
||||
headers=auth_headers
|
||||
)
|
||||
session_id = create_response.json()["id"]
|
||||
|
||||
await client.patch(
|
||||
f"/api/v1/sessions/{session_id}/scratchpad",
|
||||
json={"scratchpad": "Error code: 12345"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/sessions/{session_id}/export",
|
||||
json={"format": "text"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
assert "EVIDENCE / REFERENCE" in content
|
||||
assert "Error code: 12345" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_export_includes_scratchpad_html(
|
||||
self, client: AsyncClient, auth_headers: dict, test_tree: dict
|
||||
):
|
||||
"""Test that HTML export includes scratchpad content."""
|
||||
create_response = await client.post(
|
||||
"/api/v1/sessions",
|
||||
json={"tree_id": test_tree["id"]},
|
||||
headers=auth_headers
|
||||
)
|
||||
session_id = create_response.json()["id"]
|
||||
|
||||
await client.patch(
|
||||
f"/api/v1/sessions/{session_id}/scratchpad",
|
||||
json={"scratchpad": "DNS server: 10.0.0.5"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/sessions/{session_id}/export",
|
||||
json={"format": "html"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
assert "Evidence / Reference" in content
|
||||
assert "DNS server: 10.0.0.5" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_export_excludes_empty_scratchpad(
|
||||
self, client: AsyncClient, auth_headers: dict, test_tree: dict
|
||||
):
|
||||
"""Test that export omits scratchpad section when empty."""
|
||||
create_response = await client.post(
|
||||
"/api/v1/sessions",
|
||||
json={"tree_id": test_tree["id"]},
|
||||
headers=auth_headers
|
||||
)
|
||||
session_id = create_response.json()["id"]
|
||||
|
||||
# Export without setting scratchpad
|
||||
response = await client.post(
|
||||
f"/api/v1/sessions/{session_id}/export",
|
||||
json={"format": "markdown"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
assert "Evidence / Reference" not in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_export_excludes_whitespace_only_scratchpad(
|
||||
self, client: AsyncClient, auth_headers: dict, test_tree: dict
|
||||
):
|
||||
"""Test that export omits scratchpad section when only whitespace."""
|
||||
create_response = await client.post(
|
||||
"/api/v1/sessions",
|
||||
json={"tree_id": test_tree["id"]},
|
||||
headers=auth_headers
|
||||
)
|
||||
session_id = create_response.json()["id"]
|
||||
|
||||
await client.patch(
|
||||
f"/api/v1/sessions/{session_id}/scratchpad",
|
||||
json={"scratchpad": " \n \n "},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/sessions/{session_id}/export",
|
||||
json={"format": "markdown"},
|
||||
headers=auth_headers
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.text
|
||||
assert "Evidence / Reference" not in content
|
||||
|
||||
Reference in New Issue
Block a user