use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
use crate::client::{ProjectFleetView, fleet_state_glyph};
use super::{callback_fits, html_escape, short_id};
pub fn format_fleet_by_project(fleet: &[ProjectFleetView]) -> String {
if fleet.is_empty() {
return "No registered projects.".to_string();
}
let mut text = String::from("<b>fleet by project</b>");
for pf in fleet {
text.push_str(&format!(
"\n\n<b>{}</b> — <code>{}</code>",
html_escape(&pf.project_name),
html_escape(&pf.repo_url),
));
if pf.sessions.is_empty() {
text.push_str("\n —");
} else {
for s in &pf.sessions {
let dot = fleet_state_glyph(&s.state);
let flag = if s.pending_decision.is_some() {
" ⚠️"
} else {
""
};
text.push_str(&format!(
"\n {dot} <code>{}</code> {} [{}]{flag}",
short_id(&s.id),
html_escape(&s.name),
html_escape(&s.state),
));
}
}
}
text
}
pub fn focus_keyboard(fleet: &[ProjectFleetView]) -> Option<InlineKeyboardMarkup> {
let rows: Vec<Vec<InlineKeyboardButton>> = fleet
.iter()
.flat_map(|pf| pf.sessions.iter())
.filter(|s| callback_fits(&s.id))
.map(|s| {
vec![InlineKeyboardButton::callback(
format!("🎯 Focus — {}", s.name),
format!("focus:{}", s.id),
)]
})
.collect();
if rows.is_empty() {
None
} else {
Some(InlineKeyboardMarkup::new(rows))
}
}
pub fn session_focus_keyboard(id: &str, name: &str) -> Option<InlineKeyboardMarkup> {
if !callback_fits(id) {
return None;
}
Some(InlineKeyboardMarkup::new(vec![vec![
InlineKeyboardButton::callback(format!("🎯 Focus — {name}"), format!("focus:{id}")),
]]))
}