use crate::contracts::TaskStatus;
use crate::queue::graph::{CriticalPathResult, DependencyGraph, TaskNode};
pub(super) fn is_completed_status(status: TaskStatus) -> bool {
matches!(status, TaskStatus::Done | TaskStatus::Rejected)
}
pub(super) fn should_include_node(node: &TaskNode, include_done: bool) -> bool {
include_done || !is_completed_status(node.task.status)
}
pub(super) fn visible_ids<'a>(
graph: &DependencyGraph,
ids: impl IntoIterator<Item = &'a String>,
include_done: bool,
) -> Vec<String> {
let mut visible = ids
.into_iter()
.filter(|id| {
graph
.get(id)
.is_some_and(|node| should_include_node(node, include_done))
})
.cloned()
.collect::<Vec<_>>();
visible.sort_unstable();
visible
}
pub(super) fn visible_roots(graph: &DependencyGraph, include_done: bool) -> Vec<String> {
visible_ids(graph, graph.roots().iter(), include_done)
}
pub(super) fn visible_task_ids(graph: &DependencyGraph, include_done: bool) -> Vec<String> {
let mut ids = graph
.task_ids()
.filter(|id| {
graph
.get(id)
.is_some_and(|node| should_include_node(node, include_done))
})
.cloned()
.collect::<Vec<_>>();
ids.sort_unstable();
ids
}
pub(super) fn filtered_chain(
graph: &DependencyGraph,
ids: impl IntoIterator<Item = String>,
include_done: bool,
) -> Vec<String> {
ids.into_iter()
.filter(|id| {
graph
.get(id)
.is_some_and(|node| should_include_node(node, include_done))
})
.collect()
}
pub(super) fn sort_and_dedup(ids: &mut Vec<String>) {
ids.sort_unstable();
ids.dedup();
}
pub(super) fn status_label(status: TaskStatus) -> &'static str {
match status {
TaskStatus::Todo => "todo",
TaskStatus::Doing => "doing",
TaskStatus::Done => "done",
TaskStatus::Rejected => "rejected",
TaskStatus::Draft => "draft",
}
}
pub(super) fn status_to_emoji(status: TaskStatus) -> &'static str {
match status {
TaskStatus::Todo => "⏳",
TaskStatus::Doing => "🔄",
TaskStatus::Done => "✅",
TaskStatus::Rejected => "❌",
TaskStatus::Draft => "📝",
}
}
pub(super) fn escape_label(value: &str) -> String {
value.replace('"', "\\\"").replace('\n', "\\n")
}
pub(super) fn is_on_critical_path(
graph: &DependencyGraph,
task_id: &str,
critical_paths: &[CriticalPathResult],
) -> bool {
graph.is_on_critical_path(task_id, critical_paths)
}
pub(super) fn critical_marker(
graph: &DependencyGraph,
task_id: &str,
critical_paths: &[CriticalPathResult],
) -> &'static str {
if is_on_critical_path(graph, task_id, critical_paths) {
"* "
} else {
" "
}
}
pub(super) fn critical_suffix(
graph: &DependencyGraph,
task_id: &str,
critical_paths: &[CriticalPathResult],
) -> &'static str {
if is_on_critical_path(graph, task_id, critical_paths) {
" *"
} else {
""
}
}