Spaces:
Running
Running
File size: 5,783 Bytes
6252f54 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """Export & Handover tab — Jira JSON, CSV, Markdown download."""
import json
import csv
import io
import streamlit as st
from frontend.utils.terminology import label, ac_badge, subdomain_label
def _to_jira_json(result: dict) -> str:
issues: list[dict] = []
phases = result.get("phases") or []
for phase in phases:
for epic in (phase.get("epics") or []):
epic_issue = {
"externalId": epic.get("epic_id", ""),
"issueType": "Epic",
"summary": epic.get("title", ""),
"description": epic.get("description", ""),
"labels": [subdomain_label(epic.get("subdomain_group", ""))],
"customField_EpicName": epic.get("title", ""),
"priority": "High" if phase.get("phase_number") == 1 else "Medium",
}
issues.append(epic_issue)
for feat in (epic.get("features") or []):
for story in (feat.get("user_stories") or []):
role = story.get("role") or story.get("as_a") or "User"
want = story.get("want") or story.get("i_want") or ""
so_that = story.get("so_that") or ""
acs = story.get("acceptance_criteria") or []
story_issue = {
"externalId": f"{epic.get('epic_id', '')}-{feat.get('title', '')[:10]}-{role[:5]}",
"issueType": "Story",
"summary": f"As a {role}, I want {want}",
"description": f"As a {role}, I want {want}, so that {so_that}",
"acceptanceCriteria": "\n".join(f"- {ac}" for ac in acs),
"epicLink": epic.get("epic_id", ""),
}
issues.append(story_issue)
return json.dumps({"projects": [{"issues": issues}]}, indent=2)
def _to_csv(result: dict) -> str:
buf = io.StringIO()
writer = csv.writer(buf)
writer.writerow([
"Phase",
"Initiative ID",
"Initiative Title",
"Capability Area",
"Delivery Sprints",
"Regulatory Anchor",
"Innovation Driver",
"Delivery Standards Count",
])
for phase in (result.get("phases") or []):
for epic in (phase.get("epics") or []):
writer.writerow([
f"Phase {phase.get('phase_number', '')} — {phase.get('phase_name', '')}",
epic.get("epic_id", ""),
epic.get("title", ""),
subdomain_label(epic.get("subdomain_group", "")),
epic.get("estimated_sprints", ""),
epic.get("governance_reference", ""),
epic.get("trend_alignment", ""),
len(epic.get("acceptance_criteria") or []),
])
return buf.getvalue()
def _to_markdown(result: dict) -> str:
lines: list[str] = [
f"# Enterprise Architecture Strategic Roadmap — {result.get('org_type', '')}\n"
]
for phase in (result.get("phases") or []):
lines.append(f"\n## Phase {phase.get('phase_number')}: {phase.get('phase_name', '')}")
lines.append(f"Duration: {phase.get('duration_months', 0)} months\n")
for epic in (phase.get("epics") or []):
lines.append(f"### {epic.get('epic_id', '')} — {epic.get('title', '')}")
if epic.get("subdomain_group"):
lines.append(f"*{label('subdomain')}: {subdomain_label(epic['subdomain_group'])}*\n")
if epic.get("description"):
lines.append(epic["description"] + "\n")
if epic.get("governance_reference"):
lines.append(f"**{label('governance_reference')}:** {epic['governance_reference']}")
if epic.get("trend_alignment"):
lines.append(f"**{label('trend_alignment')}:** {epic['trend_alignment']}")
lines.append(f"**Delivery Sprints:** {epic.get('estimated_sprints', '—')}\n")
acs = epic.get("acceptance_criteria") or []
if acs:
lines.append(f"**{label('acceptance_criteria')}:**")
for ac in acs:
lines.append(f"- [ ] {ac_badge(ac)}")
lines.append("")
for feat in (epic.get("features") or []):
lines.append(f"#### {label('feature')}: {feat.get('title', '')}")
for story in (feat.get("user_stories") or []):
role = story.get("role") or "User"
want = story.get("want") or ""
so_that = story.get("so_that") or ""
lines.append(
f"- **{label('user_story')}** — "
f"As a **{role}**, I want {want}, so that {so_that}"
)
return "\n".join(lines)
def render_export_tab(result: dict) -> None:
st.subheader("Export & Handover")
fmt = st.radio("Format", ["Jira JSON", "CSV", "Markdown"], horizontal=True)
if fmt == "Jira JSON":
content = _to_jira_json(result)
mime = "application/json"
filename = "ea_roadmap_jira.json"
elif fmt == "CSV":
content = _to_csv(result)
mime = "text/csv"
filename = "ea_roadmap.csv"
else:
content = _to_markdown(result)
mime = "text/markdown"
filename = "ea_roadmap.md"
st.download_button(
label=f"Download {fmt}",
data=content,
file_name=filename,
mime=mime,
width='stretch',
type="primary",
)
st.divider()
st.caption("Preview (first 3000 characters):")
st.code(
content[:3000] + ("…" if len(content) > 3000 else ""),
language="json" if fmt == "Jira JSON" else "markdown",
)
|