feat(tui): tambah dan pasang sidebar dashboard permanen
Sidebar kanan permanen (Workflow/Tasks/Usage) menggantikan panel todo ad-hoc yang lama. Widget baca state yang sudah ada, tidak ada perubahan skema AppStateRest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
aa2b6acb95
commit
31c01cdf1d
+46
-1
@@ -14,7 +14,7 @@ use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
|
||||
use ratatui::Frame;
|
||||
use super::theme::Theme;
|
||||
use crate::app::workflow::engine::AgentState;
|
||||
use crate::app::workflow::engine::{AgentState, WorkflowAgent};
|
||||
|
||||
/// Icons for agent states.
|
||||
fn state_icon(state: AgentState) -> &'static str {
|
||||
@@ -208,4 +208,49 @@ fn build_session_lines(state: &crate::app::state::rest::AppStateRest) -> Vec<Lin
|
||||
lines
|
||||
}
|
||||
|
||||
/// Render the compact Workflow widget for the persistent sidebar: one
|
||||
/// line per agent (icon + name), truncated to whatever fits with a
|
||||
/// trailing "+N more" hint pointing at `/workflow` for the full view.
|
||||
///
|
||||
/// Flow: bordered `Block` titled "Workflow" → empty state if no agents →
|
||||
/// else `split_for_display` caps the list to the inner height (minus one
|
||||
/// row for the hint line, if needed) → one line per visible agent.
|
||||
pub fn draw_workflow_widget(frame: &mut Frame, area: Rect, state: &crate::app::state::rest::AppStateRest) {
|
||||
let block = Block::default()
|
||||
.title(Span::styled(" Workflow ", Style::default().fg(Theme::PRIMARY).add_modifier(Modifier::BOLD)))
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::default().fg(Theme::BORDER));
|
||||
let budget = (block.inner(area).height as usize).max(1);
|
||||
|
||||
let agents = &state.workflow_engine.agents;
|
||||
let lines: Vec<Line> = if agents.is_empty() {
|
||||
vec![Line::from(Span::styled(
|
||||
" No workflow running.",
|
||||
Style::default().fg(Theme::TEXT_DIM),
|
||||
))]
|
||||
} else {
|
||||
let show_hint = agents.len() > budget;
|
||||
let item_budget = if show_hint { budget.saturating_sub(1).max(1) } else { budget };
|
||||
let (visible, hidden) = super::split_for_display(agents.as_slice(), item_budget);
|
||||
let mut lines: Vec<Line> = visible.iter().map(workflow_agent_line).collect();
|
||||
if show_hint {
|
||||
lines.push(super::overflow_hint_line(hidden, "/workflow"));
|
||||
}
|
||||
lines
|
||||
};
|
||||
|
||||
let paragraph = Paragraph::new(lines).block(block);
|
||||
frame.render_widget(paragraph, area);
|
||||
}
|
||||
|
||||
/// One compact line for a single agent: state icon + name, state-colored.
|
||||
fn workflow_agent_line(agent: &WorkflowAgent) -> Line<'static> {
|
||||
let color = state_color(agent.status.state);
|
||||
let icon = state_icon(agent.status.state);
|
||||
Line::from(vec![
|
||||
Span::styled(format!(" {icon} "), Style::default().fg(color).add_modifier(Modifier::BOLD)),
|
||||
Span::styled(agent.name.clone(), Style::default().fg(Theme::TEXT)),
|
||||
])
|
||||
}
|
||||
|
||||
use ratatui::style::Color;
|
||||
|
||||
Reference in New Issue
Block a user