1use crate::i18n::Locale;
9use orbok_models::SearchCapability;
10use orbok_search::SearchMode;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ViewId {
15 Search,
16 Sources,
17 Indexing,
18 Storage,
19 Models,
20 Settings,
21}
22
23impl ViewId {
24 pub const ALL: &'static [ViewId] = &[
25 ViewId::Search,
26 ViewId::Sources,
27 ViewId::Indexing,
28 ViewId::Storage,
29 ViewId::Models,
30 ViewId::Settings,
31 ];
32}
33
34#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
36pub struct IndexHealth {
37 pub indexed: u64,
38 pub stale: u64,
39 pub failed: u64,
40 pub queued: u64,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct SourceCard {
46 pub display_name: String,
47 pub display_path: String,
48 pub indexed: u64,
49 pub stale: u64,
50 pub failed: u64,
51 pub active: bool,
52}
53
54#[derive(Debug, Clone, PartialEq)]
57pub struct SearchResultDisplay {
58 pub display_path: String,
59 pub title: Option<String>,
60 pub heading_path: Option<String>,
61 pub snippet: Option<String>,
62 pub keyword_rank: u32,
63 pub badges: Vec<String>,
64}
65
66#[derive(Debug, Clone)]
68pub struct AppState {
69 pub active_view: ViewId,
70 pub locale: Locale,
71 pub query: String,
72 pub last_query: Option<String>,
73 pub search_mode: SearchMode,
74 pub search_results: Vec<SearchResultDisplay>,
75 pub search_running: bool,
76 pub selected_result: Option<usize>,
77 pub storage_rows: Vec<(String, u64, u64)>,
78 pub health: IndexHealth,
79 pub sources: Vec<SourceCard>,
80 pub capability: SearchCapability,
81 pub storage_total_bytes: u64,
82}
83
84impl Default for AppState {
85 fn default() -> Self {
86 Self {
87 active_view: ViewId::Search,
88 locale: Locale::default(),
89 query: String::new(),
90 last_query: None,
91 search_mode: SearchMode::Auto,
92 search_results: Vec::new(),
93 search_running: false,
94 selected_result: None,
95 storage_rows: Vec::new(),
96 health: IndexHealth::default(),
97 sources: Vec::new(),
98 capability: SearchCapability::KeywordOnly,
99 storage_total_bytes: 0,
100 }
101 }
102}
103
104#[derive(Debug, Clone)]
106pub enum Message {
107 Switch(ViewId),
108 QueryChanged(String),
109 SubmitSearch,
110 SearchResultsReady(Vec<SearchResultDisplay>),
111 SearchError(String),
112 SelectResult(usize),
113 OpenSourceFile(String),
114 SetSearchMode(SearchMode),
115 PersistLocale(Locale),
116 SetLocale(Locale),
117 StorageDataReady(Vec<(String, u64, u64)>),
118}
119
120impl AppState {
121 pub fn update(&mut self, message: &Message) {
122 match message {
123 Message::Switch(view) => self.active_view = *view,
124 Message::QueryChanged(query) => self.query = query.clone(),
125 Message::SubmitSearch => {
126 let trimmed = self.query.trim();
127 if !trimmed.is_empty() {
128 self.last_query = Some(trimmed.to_string());
129 self.search_running = true;
130 self.search_results.clear();
131 self.selected_result = None;
132 }
133 }
134 Message::SearchResultsReady(results) => {
135 self.search_results = results.clone();
136 self.search_running = false;
137 self.selected_result = None;
138 }
139 Message::SearchError(_) => {
140 self.search_running = false;
141 }
142 Message::SelectResult(idx) => self.selected_result = Some(*idx),
143 Message::OpenSourceFile(_) => {} Message::SetSearchMode(mode) => self.search_mode = *mode,
145 Message::PersistLocale(locale) | Message::SetLocale(locale) => self.locale = *locale,
146 Message::StorageDataReady(rows) => self.storage_rows = rows.clone(),
147 }
148 }
149}