1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4impl App {
5 pub fn library_entries(
11 &self,
12 tab: crate::ui::library::LibraryTab,
13 ) -> Vec<crate::ui::library::LibraryEntry> {
14 use crate::ui::library::{LibraryEntry, LibraryTab};
15 match tab {
16 LibraryTab::Views => self
17 .view_rows()
18 .into_iter()
19 .map(|row| LibraryEntry {
20 title: row.name,
21 subtitle: row.scope,
22 active: row.active,
23 })
24 .collect(),
25 LibraryTab::Templates => self
26 .store
27 .config
28 .issue_templates
29 .iter()
30 .map(|(id, template)| LibraryEntry {
31 title: id.to_string(),
32 subtitle: template_subtitle(template),
33 active: false,
34 })
35 .collect(),
36 }
37 }
38
39 pub fn library_detail(
42 &self,
43 tab: crate::ui::library::LibraryTab,
44 index: usize,
45 ) -> Option<crate::ui::library::LibraryDetail> {
46 use crate::ui::library::{LibraryDetail, LibraryTab};
47 match tab {
48 LibraryTab::Views => {
49 let view = self.store.config.views.iter().nth(index)?;
50 let projects = Self::view_projects();
51 let resolution = view.scope.resolution(&projects);
52 let mut lines = vec![
53 ("name".to_string(), view.name.clone()),
54 ("id".to_string(), view.id.as_str().to_string()),
55 (
56 "scope".to_string(),
57 crate::ui::views::scope_summary(&view.scope, resolution),
58 ),
59 (
60 "active on the board".to_string(),
61 if self.active_view_id() == Some(&view.id) {
62 "yes".to_string()
63 } else {
64 "no".to_string()
65 },
66 ),
67 ];
68 lines.extend(plan_lines(&view.plan));
69 Some(LibraryDetail {
70 heading: "View".to_string(),
71 lines,
72 })
73 }
74 LibraryTab::Templates => {
75 let (id, template) = self.store.config.issue_templates.iter().nth(index)?;
76 let mut lines = vec![
77 ("id".to_string(), id.to_string()),
78 (
79 "name".to_string(),
80 template
81 .name
82 .clone()
83 .unwrap_or_else(|| "(unnamed)".to_string()),
84 ),
85 ("scope".to_string(), template.scope.to_string()),
86 ];
87 for (key, value) in template_default_lines(&template.defaults) {
88 lines.push((format!("default {key}"), value));
89 }
90 for prompt in &template.prompts {
91 lines.push((
92 format!("prompt {}", prompt.key),
93 format!(
94 "{}{}",
95 prompt.label.clone().unwrap_or_else(|| prompt.key.clone()),
96 if prompt.required { " (required)" } else { "" }
97 ),
98 ));
99 }
100 for reference in &template.references {
101 lines.push((
102 format!("reference {:?}", reference.kind),
103 format!(
104 "{}{}",
105 reference.value,
106 if reference.required {
107 " (required)"
108 } else {
109 ""
110 }
111 ),
112 ));
113 }
114 Some(LibraryDetail {
115 heading: "Template".to_string(),
116 lines,
117 })
118 }
119 }
120 }
121
122 pub(in crate::app) fn library_selected_view_id(
125 &self,
126 ) -> Option<crate::views::registry::ViewId> {
127 use crate::ui::library::LibraryTab;
128 let state = self.library.as_ref()?;
129 if state.tab != LibraryTab::Views {
130 return None;
131 }
132 self.store
133 .config
134 .views
135 .iter()
136 .nth(state.selected)
137 .map(|view| view.id.clone())
138 }
139
140 pub(in crate::app) fn library_switch_tab(&mut self, forward: bool) {
144 let Some(state) = self.library.as_mut() else {
145 return;
146 };
147 state.tab = if forward {
148 state.tab.next()
149 } else {
150 state.tab.prev()
151 };
152 state.selected = 0;
153 }
154
155 pub(in crate::app) fn handle_library_key(&mut self, key: KeyEvent) -> Result<Action> {
165 use crate::ui::library::LibraryTab;
166 if !matches!(self.mode, Mode::Library) {
167 return Ok(Action::None);
168 }
169 let tab = self.library_state().tab;
170 let rows = self.library_entries(tab).len();
171 if let Some(state) = self.library.as_mut() {
172 state.clamp_selected(rows);
173 }
174 match key.code {
175 KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('Q') => {
176 self.library = None;
180 self.mode = Mode::Board;
181 }
182 KeyCode::Tab => self.library_switch_tab(true),
186 KeyCode::BackTab => self.library_switch_tab(false),
187 KeyCode::Up | KeyCode::Char('k') => {
188 if let Some(state) = self.library.as_mut() {
189 state.move_selected(-1, rows);
190 }
191 }
192 KeyCode::Down | KeyCode::Char('j') => {
193 if let Some(state) = self.library.as_mut() {
194 state.move_selected(1, rows);
195 }
196 }
197 KeyCode::Enter => match self.library_selected_view_id() {
198 Some(id) => return self.apply_view(id.as_str()),
202 None => {
203 self.status_msg = Some(match tab {
204 LibraryTab::Views => "No view selected".to_string(),
205 LibraryTab::Templates => "Templates are read here; create one with \
206 `tix create --template <ID>`"
207 .to_string(),
208 });
209 }
210 },
211 KeyCode::Char('?') => self.open_help(Mode::Library),
212 _ => {}
213 }
214 Ok(Action::None)
215 }
216}