Files
gitlore/crates/lore-tui/src/state/bootstrap.rs
teernisse fb40fdc677 feat(tui): Phase 3 power features — Who, Search, Timeline, Trace, File History screens
Complete TUI Phase 3 implementation with all 5 power feature screens:

- Who screen: 5 modes (expert/workload/reviews/active/overlap) with
  mode tabs, input bar, result rendering, and hint bar
- Search screen: full-text search with result list and scoring display
- Timeline screen: chronological event feed with time-relative display
- Trace screen: file provenance chains with expand/collapse, rename
  tracking, and linked issues/discussions
- File History screen: per-file MR timeline with rename chain display
  and discussion snippets

Also includes:
- Command palette overlay (fuzzy search)
- Bootstrap screen (initial sync flow)
- Action layer split from monolithic action.rs to per-screen modules
- Entity and render cache infrastructure
- Shared who_types module in core crate
- All screens wired into view/mod.rs dispatch
- 597 tests passing, clippy clean (pedantic + nursery), fmt clean
2026-02-18 22:56:38 -05:00

161 lines
4.8 KiB
Rust

#![allow(dead_code)] // Phase 2.5: consumed by Bootstrap screen
//! Bootstrap screen state.
//!
//! Handles first-launch and empty-database scenarios. The schema
//! preflight runs before the TUI event loop; the bootstrap screen
//! guides users to sync when no data is available.
// ---------------------------------------------------------------------------
// DataReadiness
// ---------------------------------------------------------------------------
/// Result of checking whether the database has enough data to show the TUI.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DataReadiness {
/// Database has at least one issue.
pub has_issues: bool,
/// Database has at least one merge request.
pub has_mrs: bool,
/// Database has at least one search document.
pub has_documents: bool,
/// Current schema version from the schema_version table.
pub schema_version: i32,
}
impl DataReadiness {
/// Whether the database has any entity data at all.
#[must_use]
pub fn has_any_data(&self) -> bool {
self.has_issues || self.has_mrs
}
}
// ---------------------------------------------------------------------------
// SchemaCheck
// ---------------------------------------------------------------------------
/// Result of schema version validation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SchemaCheck {
/// Schema is at or above the minimum required version.
Compatible { version: i32 },
/// No database or no schema_version table found.
NoDB,
/// Schema exists but is too old for this TUI version.
Incompatible { found: i32, minimum: i32 },
}
// ---------------------------------------------------------------------------
// BootstrapState
// ---------------------------------------------------------------------------
/// State for the Bootstrap screen.
#[derive(Debug, Default)]
pub struct BootstrapState {
/// Whether a data readiness check has completed.
pub readiness: Option<DataReadiness>,
/// Whether the user has initiated a sync from the bootstrap screen.
pub sync_started: bool,
}
impl BootstrapState {
/// Apply a data readiness result.
pub fn apply_readiness(&mut self, readiness: DataReadiness) {
self.readiness = Some(readiness);
}
/// Whether we have data (and should auto-transition to Dashboard).
#[must_use]
pub fn should_transition_to_dashboard(&self) -> bool {
self.readiness
.as_ref()
.is_some_and(DataReadiness::has_any_data)
}
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_data_readiness_has_any_data() {
let empty = DataReadiness {
has_issues: false,
has_mrs: false,
has_documents: false,
schema_version: 26,
};
assert!(!empty.has_any_data());
let with_issues = DataReadiness {
has_issues: true,
..empty.clone()
};
assert!(with_issues.has_any_data());
let with_mrs = DataReadiness {
has_mrs: true,
..empty
};
assert!(with_mrs.has_any_data());
}
#[test]
fn test_schema_check_variants() {
let compat = SchemaCheck::Compatible { version: 26 };
assert!(matches!(compat, SchemaCheck::Compatible { version: 26 }));
let no_db = SchemaCheck::NoDB;
assert!(matches!(no_db, SchemaCheck::NoDB));
let incompat = SchemaCheck::Incompatible {
found: 10,
minimum: 20,
};
assert!(matches!(
incompat,
SchemaCheck::Incompatible {
found: 10,
minimum: 20
}
));
}
#[test]
fn test_bootstrap_state_default() {
let state = BootstrapState::default();
assert!(state.readiness.is_none());
assert!(!state.sync_started);
assert!(!state.should_transition_to_dashboard());
}
#[test]
fn test_bootstrap_state_apply_readiness_empty() {
let mut state = BootstrapState::default();
state.apply_readiness(DataReadiness {
has_issues: false,
has_mrs: false,
has_documents: false,
schema_version: 26,
});
assert!(!state.should_transition_to_dashboard());
}
#[test]
fn test_bootstrap_state_apply_readiness_with_data() {
let mut state = BootstrapState::default();
state.apply_readiness(DataReadiness {
has_issues: true,
has_mrs: false,
has_documents: false,
schema_version: 26,
});
assert!(state.should_transition_to_dashboard());
}
}