Coverage for src/fastapi_cloud_cli/commands/integrations/providers/list.py: 100%
55 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
1from typing import Annotated, Any, Literal 1abcdefg
3import typer 1abcdefg
4from pydantic import BaseModel 1abcdefg
5from rich.table import Table 1abcdefg
6from rich.text import Text 1abcdefg
7from rich_toolkit import RichToolkit 1abcdefg
9from fastapi_cloud_cli.api import APIClient 1abcdefg
10from fastapi_cloud_cli.commands._auth import UserCommand, get_user_command_context 1abcdefg
11from fastapi_cloud_cli.commands.integrations.providers._app import providers_app 1abcdefg
12from fastapi_cloud_cli.utils.execution import JsonOutputOption 1abcdefg
13from fastapi_cloud_cli.utils.teams import resolve_team_id 1abcdefg
15ProviderStatus = Literal["available", "coming_soon", "connected"] 1abcdefg
17STATUS_LABELS: dict[ProviderStatus, str] = { 1abcdefg
18 "available": "not connected",
19 "coming_soon": "coming soon",
20 "connected": "connected",
21}
24class ConnectedIntegration(BaseModel): 1abcdefg
25 id: str 1abcdefg
28class IntegrationProvider(BaseModel): 1abcdefg
29 id: str 1abcdefg
30 name: str 1abcdefg
31 status: ProviderStatus 1abcdefg
32 connected_integration: ConnectedIntegration | None = None 1abcdefg
35class ProvidersListAPIResponse(BaseModel): 1abcdefg
36 data: list[IntegrationProvider] 1abcdefg
39class ProvidersListOutput(BaseModel): 1abcdefg
40 team_id: str 1abcdefg
41 providers: list[IntegrationProvider] 1abcdefg
44def _get_providers(client: APIClient, *, team_id: str) -> list[IntegrationProvider]: 1abcdefg
45 response = client.get(f"/teams/{team_id}/integrations") 1voJhwzqLiABrMmCDsNjExpKkyFtOnGHuPlI
46 response.raise_for_status() 1voJhwzqLiABrMmCDsNjExpKkyFtOnGHuPlI
48 return ProvidersListAPIResponse.model_validate(response.json()).data 1vohwzqiABrmCDsjExpkyFtnGHulI
51def _get_providers_table(providers: list[IntegrationProvider]) -> Table: 1abcdefg
52 table = Table.grid(padding=(0, 2), pad_edge=False) 1himjknl
53 table.add_column("Name", no_wrap=True) 1himjknl
54 table.add_column("Status", no_wrap=True) 1himjknl
55 table.add_column("Integration ID", no_wrap=True, overflow="ignore") 1himjknl
56 table.add_row( 1himjknl
57 Text("Name", style="bold"),
58 Text("Status", style="bold"),
59 Text("Integration ID", style="bold"),
60 )
61 table.add_row("", "", "") 1himjknl
63 for provider in providers: 1himjknl
64 connected_integration = provider.connected_integration 1himjknl
65 table.add_row( 1himjknl
66 Text(provider.name),
67 Text(
68 STATUS_LABELS[provider.status],
69 style="green" if provider.status == "connected" else "dim",
70 ),
71 Text(connected_integration.id if connected_integration else "-"),
72 )
74 return table 1himjknl
77def _render_providers_list_output( 1abicdjefgl
78 data: ProvidersListOutput,
79 toolkit: RichToolkit,
80) -> None:
81 toolkit.print_title("integrations") 1ohqirmsjpktnul
82 toolkit.print_line() 1ohqirmsjpktnul
84 if not data.providers: 1ohqirmsjpktnul
85 toolkit.print("No integration providers available.", bullet=False) 1oqrsptu
86 return 1oqrsptu
88 toolkit.print(_get_providers_table(data.providers), bullet=False) 1himjknl
91@providers_app.command("list", cls=UserCommand) 1abcdefg
92def list_providers( 1ab4cd5efg6
93 ctx: typer.Context,
94 team_id: Annotated[
95 str | None,
96 typer.Option(
97 "--team-id",
98 help=(
99 "ID of the team whose integration providers should be listed. "
100 "Defaults to the linked app's team."
101 ),
102 ),
103 ] = None,
104 json_output: JsonOutputOption = False,
105) -> Any:
106 """
107 List integration providers and their connection status for a team.
108 """
110 toolkit = get_user_command_context(ctx).toolkit 1voQJhRwzqSLiTABrUMmVCDsWNjXExpYKkZyFt0On1GHu2Pl3I
112 with APIClient() as client: 1voQJhRwzqSLiTABrUMmVCDsWNjXExpYKkZyFt0On1GHu2Pl3I
113 team_id = resolve_team_id( 1voQJhRwzqSLiTABrUMmVCDsWNjXExpYKkZyFt0On1GHu2Pl3I
114 toolkit,
115 client,
116 team_id=team_id,
117 empty_hint="Create a team before listing integration providers.",
118 )
120 with ( 1voJhwxpKky
121 toolkit.progress(
122 title="Fetching integration providers",
123 transient=True,
124 ) as progress,
125 client.handle_http_errors(
126 progress,
127 default_message=(
128 "Error fetching integration providers. Please try again later."
129 ),
130 not_found_message="Team not found.",
131 toolkit=toolkit,
132 ),
133 ):
134 providers = _get_providers(client, team_id=team_id) 1voJhwzqLiABrMmCDsNjExpKkyFtOnGHuPlI
136 toolkit.success( 1vohwzqiABrmCDsjExpkyFtnGHulI
137 ProvidersListOutput(team_id=team_id, providers=providers),
138 render_output=_render_providers_list_output,
139 )