mod ai_readiness;
mod algorithms;
mod certificates;
mod compliance;
mod crypto;
mod datasets;
mod dependencies;
mod keys;
mod licenses;
mod models;
mod overview;
mod pqc_compliance;
mod protocols;
mod quality;
mod source;
mod tree;
mod vulnerabilities;
pub use ai_readiness::render_ai_readiness;
pub use algorithms::render_algorithms;
pub use certificates::render_certificates;
pub(crate) use compliance::build_groups;
pub use compliance::{StandardComplianceState, compute_compliance_results, render_compliance};
pub use crypto::render_crypto;
pub use datasets::render_datasets;
pub(crate) use dependencies::DependencyGraph;
pub use dependencies::{FlatDepNode, render_dependencies};
pub use keys::render_keys;
pub use licenses::render_licenses;
pub(crate) use licenses::{build_license_data_from_app, get_first_component_id_for_license};
pub use models::render_models;
pub use overview::render_overview;
pub use pqc_compliance::render_pqc_compliance;
pub use protocols::render_protocols;
pub use quality::render_quality;
pub use source::render_source;
pub(crate) use source::{SourceLink, resolve_source_reference};
pub use tree::render_tree;
pub(crate) use vulnerabilities::build_vuln_cache;
pub use vulnerabilities::{
VulnCache, VulnCacheRef, VulnDisplayItem, VulnRow, build_display_items, render_vulnerabilities,
};
pub(crate) fn relabel_ml_section_header(lines: &mut [ratatui::text::Line<'static>], title: &str) {
use ratatui::style::Style;
use ratatui::text::{Line, Span};
let scheme = crate::tui::theme::colors();
if lines.len() >= 2 {
lines[1] = Line::from(vec![
Span::styled(
"\u{2501}\u{2501}\u{2501} ",
Style::default().fg(scheme.border),
),
Span::styled(title.to_string(), Style::default().fg(scheme.accent).bold()),
Span::styled(
" \u{2501}\u{2501}\u{2501}",
Style::default().fg(scheme.border),
),
]);
}
}
pub(crate) fn without_generic_dataset_type(
ds: &crate::model::DatasetInfo,
) -> crate::model::DatasetInfo {
let mut ds = ds.clone();
if ds
.dataset_type
.as_deref()
.is_some_and(|t| t.eq_ignore_ascii_case("dataset"))
{
ds.dataset_type = None;
}
ds
}
pub(crate) fn spans_width(spans: &[ratatui::text::Span<'_>]) -> usize {
use unicode_width::UnicodeWidthStr;
spans
.iter()
.map(|s| UnicodeWidthStr::width(s.content.as_ref()))
.sum()
}
pub(crate) fn push_fitted_hints(
spans: &mut Vec<ratatui::text::Span<'static>>,
hints: &[(&'static str, &'static str)],
max_width: usize,
) {
use ratatui::style::Style;
use ratatui::text::Span;
let scheme = crate::tui::theme::colors();
let mut used = spans_width(spans);
let mut first = true;
let mut dropped = false;
for (keycap, label) in hints {
let gap = if first { 0 } else { 2 };
let w = gap + keycap.len() + 1 + label.len();
if used + w > max_width {
dropped = true;
break;
}
if gap > 0 {
spans.push(Span::raw(" "));
}
spans.push(Span::styled(
(*keycap).to_string(),
Style::default().fg(scheme.accent),
));
spans.push(Span::raw(format!(" {label}")));
used += w;
first = false;
}
if dropped && used + 2 <= max_width {
spans.push(Span::styled(" \u{2026}", Style::default().fg(scheme.muted)));
}
}