Skip to main content

systemprompt_cli/commands/cloud/tenant/
select.rs

1use anyhow::{anyhow, bail, Result};
2use dialoguer::theme::ColorfulTheme;
3use dialoguer::Select;
4use systemprompt_cloud::{
5    get_cloud_paths, CloudCredentials, CloudPath, CredentialsBootstrap, StoredTenant, TenantType,
6};
7use systemprompt_models::profile_bootstrap::ProfileBootstrap;
8
9pub fn get_credentials() -> Result<CloudCredentials> {
10    if CredentialsBootstrap::is_initialized() {
11        return CredentialsBootstrap::require()
12            .map_err(|e| {
13                anyhow!(
14                    "Credentials required. Run 'systemprompt cloud login': {}",
15                    e
16                )
17            })?
18            .clone()
19            .pipe(Ok);
20    }
21
22    let cloud_paths = get_cloud_paths()?;
23    let creds_path = cloud_paths.resolve(CloudPath::Credentials);
24
25    if creds_path.exists() {
26        CloudCredentials::load_from_path(&creds_path)
27    } else {
28        bail!("Not logged in. Run 'systemprompt cloud login' first.")
29    }
30}
31
32pub fn select_tenant(tenants: &[StoredTenant]) -> Result<&StoredTenant> {
33    let options: Vec<String> = tenants
34        .iter()
35        .map(|t| {
36            let type_str = match t.tenant_type {
37                TenantType::Local => "local",
38                TenantType::Cloud => "cloud",
39            };
40            format!("{} ({})", t.name, type_str)
41        })
42        .collect();
43
44    let selection = Select::with_theme(&ColorfulTheme::default())
45        .with_prompt("Select tenant")
46        .items(&options)
47        .default(0)
48        .interact()?;
49
50    Ok(&tenants[selection])
51}
52
53pub fn resolve_tenant_id(tenant_id: Option<String>) -> Result<String> {
54    if let Some(id) = tenant_id {
55        return Ok(id);
56    }
57
58    ProfileBootstrap::get()
59        .ok()
60        .and_then(|p| p.cloud.as_ref()?.tenant_id.clone())
61        .ok_or_else(|| {
62            anyhow!("No tenant specified. Use --tenant or configure a tenant in your profile.")
63        })
64}
65
66trait Pipe: Sized {
67    fn pipe<F, R>(self, f: F) -> R
68    where
69        F: FnOnce(Self) -> R,
70    {
71        f(self)
72    }
73}
74
75impl<T> Pipe for T {}