1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
5pub enum Tab {
6 #[default]
7 Status,
8 Jobs,
9 Config,
10 Logs,
11 About,
12}
13
14impl Tab {
15 pub const ALL: [Tab; 5] = [Tab::Status, Tab::Jobs, Tab::Config, Tab::Logs, Tab::About];
16
17 pub fn label(self) -> &'static str {
18 match self {
19 Tab::Status => "Status",
20 Tab::Jobs => "Jobs",
21 Tab::Config => "Config",
22 Tab::Logs => "Logs",
23 Tab::About => "About",
24 }
25 }
26
27 pub fn parse(name: &str) -> Option<Self> {
31 match name.trim().to_ascii_lowercase().as_str() {
32 "status" => Some(Self::Status),
33 "jobs" => Some(Self::Jobs),
34 "config" => Some(Self::Config),
35 "logs" => Some(Self::Logs),
36 "about" => Some(Self::About),
37 _ => None,
38 }
39 }
40
41 pub fn initial() -> Self {
43 std::env::var("STUDIO_WORKER_UI_TAB")
44 .ok()
45 .and_then(|s| Self::parse(&s))
46 .unwrap_or_default()
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn all_returns_five_tabs_in_render_order() {
56 let labels: Vec<&str> = Tab::ALL.iter().map(|t| t.label()).collect();
57 assert_eq!(
58 labels,
59 ["Status", "Jobs", "Config", "Logs", "About"],
60 "tab labels + order are part of the UI contract"
61 );
62 }
63
64 #[test]
65 fn default_is_status() {
66 assert_eq!(Tab::default(), Tab::Status);
67 }
68
69 #[test]
70 fn parse_round_trips_with_label_case_insensitively() {
71 for tab in Tab::ALL {
72 assert_eq!(Tab::parse(tab.label()), Some(tab));
73 assert_eq!(Tab::parse(&tab.label().to_uppercase()), Some(tab));
74 }
75 assert!(Tab::parse("").is_none());
76 assert!(Tab::parse("nope").is_none());
77 }
78
79 #[test]
80 fn initial_falls_back_to_default_when_env_unset() {
81 let prev = std::env::var("STUDIO_WORKER_UI_TAB").ok();
87 std::env::remove_var("STUDIO_WORKER_UI_TAB");
88 assert_eq!(Tab::initial(), Tab::default());
89 if let Some(v) = prev {
90 std::env::set_var("STUDIO_WORKER_UI_TAB", v);
91 }
92 }
93
94 #[test]
95 fn labels_are_unique() {
96 use std::collections::HashSet;
97 let unique: HashSet<&str> = Tab::ALL.iter().map(|t| t.label()).collect();
98 assert_eq!(unique.len(), Tab::ALL.len());
99 }
100}