Skip to main content

matrixcode_tui/workflow/
progress.rs

1//! Compact Progress View
2//!
3//! Alternative compact display for workflow execution progress
4
5use ratatui::{
6    buffer::Buffer,
7    layout::Rect,
8    style::{Style, Color},
9};
10use crate::workflow::types::{WorkflowViewState, node_type_icon};
11
12/// Render compact progress view
13pub fn render_progress_view(state: &WorkflowViewState, area: Rect, buf: &mut Buffer) {
14    if state.workflow_def.is_none() {
15        buf.set_string(area.x, area.y, "No workflow running", Style::default());
16        return;
17    }
18
19    let def = state.workflow_def.as_ref().unwrap();
20
21    // Title line
22    let status_label = if let Some(ctx) = &state.context {
23        match ctx.status {
24            matrixcode_core::workflow::WorkflowStatus::Running => "⟳ running",
25            matrixcode_core::workflow::WorkflowStatus::Completed => "✓ completed",
26            matrixcode_core::workflow::WorkflowStatus::Failed => "✗ failed",
27            matrixcode_core::workflow::WorkflowStatus::Paused => "⏸ paused",
28            _ => "○ pending",
29        }
30    } else {
31        "○ pending"
32    };
33
34    let title = format!("{} [{}]", def.name, status_label);
35    let title_len = title.chars().count() as u16;
36    buf.set_string(area.x, area.y, &title, Style::default().fg(Color::White).bold());
37
38    // Progress bar (if we have width)
39    if area.width > 30 {
40        let (completed, total) = state.progress();
41        let bar_start = area.x + title_len + 2;
42        let bar_width = area.width.saturating_sub(bar_start - area.x).saturating_sub(10);
43
44        if bar_width > 0 {
45            let filled = if total > 0 {
46                ((bar_width as usize) * completed) / total
47            } else {
48                0
49            };
50
51            buf.set_string(bar_start, area.y, " [", Style::default().fg(Color::Gray));
52            for i in 0..bar_width as usize {
53                let ch = if i < filled { "█" } else { "░" };
54                let color = if i < filled { Color::Green } else { Color::Gray };
55                buf.set_string(bar_start + 1 + i as u16, area.y, ch, Style::default().fg(color));
56            }
57            buf.set_string(bar_start + 1 + bar_width, area.y, "] ", Style::default().fg(Color::Gray));
58            buf.set_string(bar_start + 3 + bar_width, area.y, format!("{}/{}", completed, total), Style::default().fg(Color::Gray));
59        }
60    }
61
62    // Node status line
63    if area.height > 1 {
64        let node_y = area.y + 1;
65        let mut x = area.x;
66
67        buf.set_string(x, node_y, "Nodes: ", Style::default().fg(Color::Gray));
68        x += 7;
69
70        for node in &def.nodes {
71            if x >= area.right() {
72                break;
73            }
74            let status = state.get_node_status(&node.id);
75            let type_icon = node_type_icon(&node.node_type);
76            let status_icon = status.icon();
77
78            let color = match status.color() {
79                "gray" => Color::Gray,
80                "yellow" => Color::Yellow,
81                "green" => Color::Green,
82                "red" => Color::Red,
83                "blue" => Color::Blue,
84                _ => Color::Reset,
85            };
86
87            buf.set_string(x, node_y, format!("{}{}", type_icon, status_icon), Style::default().fg(color));
88            x += 3;
89        }
90    }
91}
92
93/// Render inline progress indicator (for status line)
94pub fn render_inline_progress(state: &WorkflowViewState, buf: &mut Buffer, x: u16, y: u16) -> u16 {
95    if state.workflow_def.is_none() {
96        return x;
97    }
98
99    let (completed, total) = state.progress();
100    let text = format!(" wf:{}/{:02}", completed, total);
101    let text_len = text.len() as u16;
102
103    let color = if completed == total && total > 0 {
104        Color::Green
105    } else if let Some(ctx) = &state.context {
106        match ctx.status {
107            matrixcode_core::workflow::WorkflowStatus::Failed => Color::Red,
108            matrixcode_core::workflow::WorkflowStatus::Running => Color::Yellow,
109            _ => Color::Gray,
110        }
111    } else {
112        Color::Gray
113    };
114
115    buf.set_string(x, y, &text, Style::default().fg(color));
116    x + text_len
117}