steer_tui/tui/state/
setup.rs1use std::collections::HashMap;
2use std::sync::Arc;
3use steer_core::config::provider::ProviderId;
4
5#[derive(Debug, Clone)]
6pub struct SetupState {
7 pub current_step: SetupStep,
8 pub auth_providers: HashMap<ProviderId, AuthStatus>,
9 pub selected_provider: Option<ProviderId>,
10 pub oauth_state: Option<OAuthFlowState>,
11 pub api_key_input: String,
12 pub oauth_callback_input: String,
13 pub error_message: Option<String>,
14 pub provider_cursor: usize,
15 pub skip_setup: bool,
16 pub registry: Arc<RemoteProviderRegistry>,
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum SetupStep {
21 Welcome,
22 ProviderSelection,
23 Authentication(ProviderId),
24 Completion,
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum AuthStatus {
29 NotConfigured,
30 ApiKeySet,
31 OAuthConfigured,
32 InProgress,
33}
34
35#[derive(Debug, Clone)]
36pub struct OAuthFlowState {
37 pub auth_url: String,
38 pub state: String,
39 pub waiting_for_callback: bool,
40}
41
42#[derive(Debug, Clone)]
44pub struct RemoteProviderConfig {
45 pub id: String,
46 pub name: String,
47 pub auth_schemes: Vec<steer_grpc::proto::ProviderAuthScheme>,
48}
49
50#[derive(Debug, Clone)]
51pub struct RemoteProviderRegistry {
52 providers: Vec<RemoteProviderConfig>,
53}
54
55impl RemoteProviderRegistry {
56 pub fn from_proto(providers: Vec<steer_grpc::proto::ProviderInfo>) -> Self {
57 let providers = providers
58 .into_iter()
59 .map(|p| RemoteProviderConfig {
60 id: p.id,
61 name: p.name,
62 auth_schemes: p
63 .auth_schemes
64 .into_iter()
65 .filter_map(|v| steer_grpc::proto::ProviderAuthScheme::try_from(v).ok())
66 .collect(),
67 })
68 .collect();
69 Self { providers }
70 }
71
72 pub fn all(&self) -> impl Iterator<Item = &RemoteProviderConfig> {
73 self.providers.iter()
74 }
75
76 pub fn get(&self, id: &ProviderId) -> Option<&RemoteProviderConfig> {
77 self.providers.iter().find(|p| p.id == id.storage_key())
78 }
79}
80
81impl SetupState {
82 pub fn new(
83 registry: Arc<RemoteProviderRegistry>,
84 auth_providers: HashMap<ProviderId, AuthStatus>,
85 ) -> Self {
86 Self {
87 current_step: SetupStep::Welcome,
88 auth_providers,
89 selected_provider: None,
90 oauth_state: None,
91 api_key_input: String::new(),
92 oauth_callback_input: String::new(),
93 error_message: None,
94 provider_cursor: 0,
95 skip_setup: false,
96 registry,
97 }
98 }
99
100 pub fn new_for_auth_command(
102 registry: Arc<RemoteProviderRegistry>,
103 auth_providers: HashMap<ProviderId, AuthStatus>,
104 ) -> Self {
105 let mut state = Self::new(registry, auth_providers);
106 state.current_step = SetupStep::ProviderSelection;
107 state
108 }
109
110 pub fn next_step(&mut self) {
111 self.current_step = match &self.current_step {
112 SetupStep::Welcome => SetupStep::ProviderSelection,
113 SetupStep::ProviderSelection => {
114 if let Some(provider) = &self.selected_provider {
115 SetupStep::Authentication(provider.clone())
116 } else {
117 SetupStep::ProviderSelection
118 }
119 }
120 SetupStep::Authentication(_) => SetupStep::Completion,
121 SetupStep::Completion => SetupStep::Completion,
122 };
123 self.error_message = None;
124 }
125
126 pub fn previous_step(&mut self) {
127 self.current_step = match &self.current_step {
128 SetupStep::Welcome => SetupStep::Welcome,
129 SetupStep::ProviderSelection => SetupStep::Welcome,
130 SetupStep::Authentication(_) => SetupStep::ProviderSelection,
131 SetupStep::Completion => SetupStep::ProviderSelection,
132 };
133 self.error_message = None;
134 }
135
136 pub fn available_providers(&self) -> Vec<&RemoteProviderConfig> {
137 let mut providers: Vec<_> = self.registry.all().collect();
138 providers.sort_by_key(|p| p.name.clone());
140 providers
141 }
142}