from core.models import ProgressReport, Task class MarkdownBuilder: @staticmethod def _parse_progress(p_val: str) -> int: if p_val == "1": return 100 try: return int(p_val.replace("%", "")) except: return 0 @staticmethod def _get_status_badge(status: str) -> str: s = status.upper().strip() if "COMPLETED" in s: return "![Completed](https://img.shields.io/badge/-COMPLETED-2ea44f?style=flat-square)" if "DURING" in s or "PROCESS" in s: return "![In Progress](https://img.shields.io/badge/-IN_PROGRESS-005cc5?style=flat-square)" if "NOT STARTED" in s: return "![Not Started](https://img.shields.io/badge/-NOT_STARTED-6a737d?style=flat-square)" return f"`{status}`" @staticmethod def build_table(report: ProgressReport) -> str: if not report.tasks: return "_No tasks found._" header = "| Phase | ID | Task | Assignee | Timeline | Progress | Status |\n" separator = "| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n" rows = [] current_phase = "" for task in report.tasks: phase_display = f"**{task.phase}**" if task.phase != current_phase else "" current_phase = task.phase badge = MarkdownBuilder._get_status_badge(task.status) prog_val = MarkdownBuilder._parse_progress(task.progress_val) filled = prog_val // 10 bar = "█" * filled + "░" * (10 - filled) rows.append( f"| {phase_display} | `{task.task_id}` | {task.task_name} | `{task.assignee}` | {task.start_date} - {task.end_date} | `{bar} {prog_val}%` | {badge} |" ) return header + separator + "\n".join(rows) @staticmethod def build_team_progress(report: ProgressReport) -> str: if not report.tasks: return "" phases = {} for t in report.tasks: if t.phase not in phases: phases[t.phase] = [] phases[t.phase].append(t) total_tasks = len(report.tasks) completed = len([t for t in report.tasks if "COMPLETED" in t.status.upper()]) in_progress = len([t for t in report.tasks if "DURING" in t.status.upper()]) avg_progress = sum(MarkdownBuilder._parse_progress(t.progress_val) for t in report.tasks) / total_tasks # Build phase rows — NO leading spaces (prevents GitHub treating them as code blocks) phase_rows_html = "" colors = ["#B026FF", "#33CCFF", "#FF3333", "#FFD700"] for i, (name, t_list) in enumerate(phases.items()): p_total = len(t_list) p_done = len([t for t in t_list if "COMPLETED" in t.status.upper()]) p_avg = sum(MarkdownBuilder._parse_progress(t.progress_val) for t in t_list) / p_total color = colors[i % len(colors)] # Key fix: use textwrap.dedent-style — keep lines flush left, no indentation phase_rows_html += ( f'' f'' f'' f'' f'
{name}{p_avg:.0f}% ({p_done}/{p_total})
' f'
' f'
' f'
' f'' f'' ) # Entire dashboard on as few lines as possible — no indented lines dashboard = ( '
' '' '' '' '' '' '
' '' f'
SYSTEM READINESS
' f'
{avg_progress:.1f}%
' '' '' f'' f'' f'' '' '
{completed}
DONE
{in_progress}
ACTIVE
{total_tasks - completed - in_progress}
BACKLOG
' '
' '
Phase Breakdown
' f'{phase_rows_html}
' '
' '
' ) return dashboard