feat: include supporting data in all export formats
Query supporting data in the export endpoint and pass to markdown, text, HTML, and PSA export generators. Each format renders text snippets and screenshot placeholders in its native style. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -171,7 +171,7 @@ def _escape_markdown_table(value: str) -> str:
|
||||
return value.replace("|", "\\|").replace("\n", " ")
|
||||
|
||||
|
||||
def generate_markdown_export(session: Session, options: SessionExport) -> str:
|
||||
def generate_markdown_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str:
|
||||
"""Generate markdown export."""
|
||||
if _is_procedural_session(session):
|
||||
return _generate_procedural_markdown(session, options)
|
||||
@@ -261,6 +261,22 @@ def generate_markdown_export(session: Session, options: SessionExport) -> str:
|
||||
lines.append(f"*{decision['timestamp']}*")
|
||||
lines.append("")
|
||||
|
||||
# Supporting Data
|
||||
if supporting_data:
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
lines.append("## Supporting Data")
|
||||
lines.append("")
|
||||
for sd in supporting_data:
|
||||
lines.append(f"### {sd['label']}")
|
||||
if sd["data_type"] == "text_snippet":
|
||||
lines.append("```")
|
||||
lines.append(sd["content"])
|
||||
lines.append("```")
|
||||
else:
|
||||
lines.append(f"[Screenshot: {sd['label']}]")
|
||||
lines.append("")
|
||||
|
||||
# Resolution / Outcome Notes
|
||||
_raw_notes = getattr(session, 'outcome_notes', None)
|
||||
outcome_notes = _raw_notes if isinstance(_raw_notes, str) else ''
|
||||
@@ -286,7 +302,7 @@ def generate_markdown_export(session: Session, options: SessionExport) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def generate_text_export(session: Session, options: SessionExport) -> str:
|
||||
def generate_text_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str:
|
||||
"""Generate plain text export."""
|
||||
if _is_procedural_session(session):
|
||||
return _generate_procedural_text(session, options)
|
||||
@@ -361,6 +377,19 @@ def generate_text_export(session: Session, options: SessionExport) -> str:
|
||||
if duration_seconds is not None:
|
||||
lines.append(f" Duration: {_format_step_duration(duration_seconds)}")
|
||||
|
||||
# Supporting Data
|
||||
if supporting_data:
|
||||
lines.append("")
|
||||
lines.append("SUPPORTING DATA")
|
||||
lines.append("-" * 20)
|
||||
for sd in supporting_data:
|
||||
lines.append(f"\n {sd['label']}:")
|
||||
if sd["data_type"] == "text_snippet":
|
||||
for content_line in sd["content"].splitlines():
|
||||
lines.append(f" {content_line}")
|
||||
else:
|
||||
lines.append(f" [Screenshot: {sd['label']}]")
|
||||
|
||||
# Resolution
|
||||
_raw_notes = getattr(session, 'outcome_notes', None)
|
||||
outcome_notes = _raw_notes if isinstance(_raw_notes, str) else ''
|
||||
@@ -382,7 +411,7 @@ def generate_text_export(session: Session, options: SessionExport) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def generate_html_export(session: Session, options: SessionExport) -> str:
|
||||
def generate_html_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str:
|
||||
"""Generate HTML export."""
|
||||
if _is_procedural_session(session):
|
||||
return _generate_procedural_html(session, options)
|
||||
@@ -472,6 +501,15 @@ def generate_html_export(session: Session, options: SessionExport) -> str:
|
||||
html_parts.append(f'<p class="timestamp">{html.escape(str(decision["timestamp"]))}</p>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Supporting Data
|
||||
if supporting_data:
|
||||
html_parts.append('<h2>Supporting Data</h2>')
|
||||
for sd in supporting_data:
|
||||
if sd["data_type"] == "text_snippet":
|
||||
html_parts.append(f'<div class="supporting-item"><h3>{html.escape(sd["label"])}</h3><pre>{html.escape(sd["content"])}</pre></div>')
|
||||
else:
|
||||
html_parts.append(f'<div class="supporting-item"><h3>{html.escape(sd["label"])}</h3><img src="data:{html.escape(sd.get("content_type") or "image/png")};base64,{sd["content"]}" alt="{html.escape(sd["label"])}"></div>')
|
||||
|
||||
# Resolution
|
||||
_raw_notes = getattr(session, 'outcome_notes', None)
|
||||
outcome_notes = _raw_notes if isinstance(_raw_notes, str) else ''
|
||||
@@ -490,7 +528,7 @@ def generate_html_export(session: Session, options: SessionExport) -> str:
|
||||
return "\n".join(html_parts)
|
||||
|
||||
|
||||
def generate_psa_export(session: Session, options: SessionExport) -> str:
|
||||
def generate_psa_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str:
|
||||
"""Generate PSA/ticket note export optimized for ConnectWise and similar PSA tools."""
|
||||
if _is_procedural_session(session):
|
||||
return _generate_procedural_psa(session, options)
|
||||
@@ -561,6 +599,19 @@ def generate_psa_export(session: Session, options: SessionExport) -> str:
|
||||
lines.append("No steps recorded.")
|
||||
lines.append("")
|
||||
|
||||
# Supporting Data
|
||||
if supporting_data:
|
||||
lines.append("--- SUPPORTING DATA ---")
|
||||
for sd in supporting_data:
|
||||
if sd["data_type"] == "text_snippet":
|
||||
lines.append(f"## {sd['label']}")
|
||||
lines.append("```")
|
||||
lines.append(sd["content"])
|
||||
lines.append("```")
|
||||
else:
|
||||
lines.append(f"[Screenshot: {sd['label']}]")
|
||||
lines.append("")
|
||||
|
||||
# Resolution — only for completed sessions
|
||||
if session.completed_at:
|
||||
lines.append("--- RESOLUTION ---")
|
||||
|
||||
Reference in New Issue
Block a user