1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
6pub enum Page {
7 #[default]
9 Jobs,
10 Models,
11 Worker,
13 Logs,
14 Config,
15}
16
17impl Page {
18 pub const ALL: [Page; 5] = [
20 Page::Jobs,
21 Page::Models,
22 Page::Worker,
23 Page::Logs,
24 Page::Config,
25 ];
26
27 pub fn label(self) -> &'static str {
28 match self {
29 Page::Jobs => "Jobs",
30 Page::Models => "Models",
31 Page::Worker => "Worker",
32 Page::Logs => "Logs",
33 Page::Config => "Config",
34 }
35 }
36
37 pub fn hint(self) -> &'static str {
39 match self {
40 Page::Jobs => "What runs now and what ran",
41 Page::Models => "Load and unload models",
42 Page::Worker => "State, registration, hardware and version",
43 Page::Logs => "Everything the daemon logs",
44 Page::Config => "Worker settings and this window",
45 }
46 }
47
48 pub fn from_digit(digit: u8) -> Option<Self> {
50 Self::ALL.get(usize::from(digit).checked_sub(1)?).copied()
51 }
52
53 pub fn digit(self) -> u8 {
55 Self::ALL.iter().position(|p| *p == self).unwrap_or(0) as u8 + 1
56 }
57
58 pub fn parse(name: &str) -> Option<Self> {
60 let name = name.trim();
61 Self::ALL
62 .into_iter()
63 .find(|p| p.label().eq_ignore_ascii_case(name))
64 }
65
66 pub fn initial() -> Self {
69 Self::initial_from(std::env::var("STUDIO_WORKER_UI_PAGE").ok().as_deref())
70 }
71
72 pub fn initial_from(env: Option<&str>) -> Self {
73 env.and_then(Self::parse).unwrap_or_default()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn the_rail_lists_every_page_in_order() {
83 let labels: Vec<&str> = Page::ALL.iter().map(|p| p.label()).collect();
84 assert_eq!(labels, ["Jobs", "Models", "Worker", "Logs", "Config"]);
85 }
86
87 #[test]
88 fn the_window_opens_on_jobs() {
89 assert_eq!(Page::default(), Page::Jobs);
90 assert_eq!(Page::initial_from(None), Page::Jobs);
91 assert_eq!(Page::initial_from(Some("nonsense")), Page::Jobs);
92 assert_eq!(Page::initial_from(Some("worker")), Page::Worker);
93 }
94
95 #[test]
96 fn names_parse_case_insensitively_and_old_tabs_are_gone() {
97 for page in Page::ALL {
98 assert_eq!(Page::parse(page.label()), Some(page));
99 assert_eq!(Page::parse(&page.label().to_uppercase()), Some(page));
100 assert!(!page.hint().is_empty());
101 }
102 assert_eq!(Page::parse(" logs "), Some(Page::Logs));
103 assert_eq!(Page::parse("status"), None);
104 assert_eq!(Page::parse("about"), None);
105 }
106
107 #[test]
108 fn digits_pick_pages_in_rail_order() {
109 for page in Page::ALL {
110 assert_eq!(Page::from_digit(page.digit()), Some(page));
111 }
112 assert_eq!(Page::from_digit(1), Some(Page::Jobs));
113 assert_eq!(Page::from_digit(0), None);
114 assert_eq!(Page::from_digit(6), None);
115 }
116}