storkit: merge 430_bug_status_command_traffic_light_dots_not_coloured_in_matrix
This commit is contained in:
@@ -122,6 +122,34 @@ fn read_stage_items(
|
||||
items
|
||||
}
|
||||
|
||||
/// Build the HTML `formatted_body` for the pipeline status with Matrix colour
|
||||
/// tags on the traffic-light dots.
|
||||
///
|
||||
/// Converts the plain-text pipeline status (Markdown) to HTML via
|
||||
/// pulldown-cmark and wraps each traffic-light character in a
|
||||
/// `<font data-mx-color="#rrggbb">` tag so Matrix clients display them in
|
||||
/// colour.
|
||||
pub(super) fn build_pipeline_status_html(project_root: &std::path::Path, agents: &AgentPool) -> String {
|
||||
use pulldown_cmark::{Options, Parser, html};
|
||||
|
||||
let plain = build_pipeline_status(project_root, agents);
|
||||
let normalized = crate::chat::util::normalize_line_breaks(&plain);
|
||||
let options = Options::ENABLE_TABLES
|
||||
| Options::ENABLE_FOOTNOTES
|
||||
| Options::ENABLE_STRIKETHROUGH
|
||||
| Options::ENABLE_TASKLISTS;
|
||||
let parser = Parser::new_ext(&normalized, options);
|
||||
let mut html_out = String::new();
|
||||
html::push_html(&mut html_out, parser);
|
||||
|
||||
// Wrap each traffic-light character with a Matrix colour tag.
|
||||
html_out
|
||||
.replace('\u{2717}', "<font data-mx-color=\"#cc0000\">\u{2717}</font>") // ✗ blocked
|
||||
.replace('\u{25D1}', "<font data-mx-color=\"#ffaa00\">\u{25D1}</font>") // ◑ throttled
|
||||
.replace('\u{25CF}', "<font data-mx-color=\"#00cc00\">\u{25CF}</font>") // ● running
|
||||
.replace('\u{25CB}', "<font data-mx-color=\"#888888\">\u{25CB}</font>") // ○ idle
|
||||
}
|
||||
|
||||
/// Build the full pipeline status text formatted for Matrix (markdown).
|
||||
pub(super) fn build_pipeline_status(project_root: &std::path::Path, agents: &AgentPool) -> String {
|
||||
// Build a map from story_id → active AgentInfo for quick lookup.
|
||||
@@ -444,6 +472,81 @@ mod tests {
|
||||
|
||||
// -- traffic_light_dot --------------------------------------------------
|
||||
|
||||
// -- build_pipeline_status_html (colored dots) --------------------------
|
||||
|
||||
#[test]
|
||||
fn html_status_colors_idle_dot_grey() {
|
||||
use std::io::Write;
|
||||
use tempfile::TempDir;
|
||||
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let stage_dir = tmp.path().join(".storkit/work/2_current");
|
||||
std::fs::create_dir_all(&stage_dir).unwrap();
|
||||
|
||||
let story_path = stage_dir.join("42_story_idle.md");
|
||||
let mut f = std::fs::File::create(&story_path).unwrap();
|
||||
writeln!(f, "---\nname: Idle Story\n---\n").unwrap();
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let html = build_pipeline_status_html(tmp.path(), &agents);
|
||||
|
||||
assert!(
|
||||
html.contains("<font data-mx-color=\"#888888\">\u{25CB}</font>"),
|
||||
"idle dot should be grey (#888888): {html}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn html_status_colors_blocked_dot_red() {
|
||||
use std::io::Write;
|
||||
use tempfile::TempDir;
|
||||
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let stage_dir = tmp.path().join(".storkit/work/2_current");
|
||||
std::fs::create_dir_all(&stage_dir).unwrap();
|
||||
|
||||
let story_path = stage_dir.join("42_story_blocked.md");
|
||||
let mut f = std::fs::File::create(&story_path).unwrap();
|
||||
writeln!(f, "---\nname: Blocked Story\nblocked: true\n---\n").unwrap();
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let html = build_pipeline_status_html(tmp.path(), &agents);
|
||||
|
||||
assert!(
|
||||
html.contains("<font data-mx-color=\"#cc0000\">\u{2717}</font>"),
|
||||
"blocked dot should be red (#cc0000): {html}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn html_status_plain_text_body_unchanged() {
|
||||
use std::io::Write;
|
||||
use tempfile::TempDir;
|
||||
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let stage_dir = tmp.path().join(".storkit/work/2_current");
|
||||
std::fs::create_dir_all(&stage_dir).unwrap();
|
||||
|
||||
let story_path = stage_dir.join("42_story_idle.md");
|
||||
let mut f = std::fs::File::create(&story_path).unwrap();
|
||||
writeln!(f, "---\nname: Idle Story\n---\n").unwrap();
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let plain = build_pipeline_status(tmp.path(), &agents);
|
||||
|
||||
// Plain text must still use bare Unicode dots (no HTML tags).
|
||||
assert!(
|
||||
plain.contains('\u{25CB}'),
|
||||
"plain text should have bare Unicode idle dot: {plain}"
|
||||
);
|
||||
assert!(
|
||||
!plain.contains("data-mx-color"),
|
||||
"plain text must not contain HTML colour attributes: {plain}"
|
||||
);
|
||||
}
|
||||
|
||||
// -- traffic_light_dot --------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn dot_idle_when_no_agent() {
|
||||
assert_eq!(traffic_light_dot(false, false, false), "\u{25CB} "); // ○
|
||||
|
||||
Reference in New Issue
Block a user