Skip to content

Commit 0ffe711

Browse files
committed
feat(cli.py): add teams management commands to enhance team functionality in the CLI
feat(cli.py): implement JSON output option for teams listing to improve data accessibility refactor(cli.py): update project selection command to improve user experience and error handling
1 parent b5e1d3a commit 0ffe711

File tree

1 file changed

+152
-23
lines changed

1 file changed

+152
-23
lines changed

infactory_client/cli.py

Lines changed: 152 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
query_app = typer.Typer(help="Manage query programs", no_args_is_help=True)
3030
endpoints_app = typer.Typer(help="Manage endpoints", no_args_is_help=True)
3131
jobs_app = typer.Typer(help="Manage jobs", no_args_is_help=True)
32+
teams_app = typer.Typer(help="Manage teams", no_args_is_help=True)
3233

3334
# Add sub-apps to main app
3435
app.add_typer(organizations_app, name="orgs")
@@ -38,6 +39,7 @@
3839
app.add_typer(query_app, name="query")
3940
app.add_typer(endpoints_app, name="endpoints")
4041
app.add_typer(jobs_app, name="jobs")
42+
app.add_typer(teams_app, name="teams")
4143

4244
# Configure logging
4345
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
@@ -214,7 +216,7 @@ def show( # noqa: C901
214216
return
215217

216218
# Create a table for better formatting
217-
table = Table(title="Current State", show_header=False)
219+
table = Table(title="Infactory CLI", show_header=False)
218220
table.add_column("Setting")
219221
table.add_column("Value")
220222

@@ -406,7 +408,8 @@ def organizations_select():
406408

407409
@projects_app.command(name="list")
408410
def projects_list(
409-
team_id: str | None = typer.Option(None, help="Team ID to list projects for")
411+
team_id: str | None = typer.Option(None, help="Team ID to list projects for"),
412+
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
410413
):
411414
"""List projects."""
412415
client = get_client()
@@ -427,16 +430,31 @@ def projects_list(
427430
typer.echo("No projects found")
428431
return
429432

433+
if json_output:
434+
project_data = [
435+
{
436+
"id": project.id,
437+
"name": project.name,
438+
"description": project.description,
439+
"is_current": project.id == client.state.project_id,
440+
}
441+
for project in projects
442+
]
443+
print(json.dumps(project_data, indent=2))
444+
return
445+
430446
table = Table()
431447
table.add_column("ID")
432448
table.add_column("Name")
433449
table.add_column("Description")
450+
table.add_column("Current", justify="center")
434451

435452
for project in projects:
436453
description = project.description or ""
437454
if len(description) > 47:
438455
description = description[:47] + "..."
439-
table.add_row(project.id, project.name, description)
456+
is_current = "✓" if project.id == client.state.project_id else ""
457+
table.add_row(project.id, project.name, description, is_current)
440458

441459
console.print(table)
442460

@@ -445,36 +463,59 @@ def projects_list(
445463
raise typer.Exit(1)
446464

447465

448-
@projects_app.command(name="create")
449-
def project_create(
450-
name: str,
451-
team_id: str | None = typer.Option(None, help="Team ID to create project in"),
452-
description: str | None = typer.Option(None, help="Project description"),
453-
):
454-
"""Create a new project."""
466+
@projects_app.command(name="select")
467+
def projects_select():
468+
"""Interactively select a project to set as current."""
455469
client = get_client()
456470

457471
try:
458-
if not team_id and not client.state.team_id:
472+
if not client.state.team_id:
459473
typer.echo(
460-
"No team ID provided. Please specify --team-id or set a current team.",
461-
err=True,
474+
"No team selected. Please select a team first with 'nf teams select'"
462475
)
463-
raise typer.Exit(1)
476+
return
477+
478+
projects = client.projects.list(team_id=client.state.team_id)
479+
480+
if not projects:
481+
typer.echo("No projects found")
482+
return
483+
484+
# Create a list of choices
485+
choices = {str(i): project for i, project in enumerate(projects, 1)}
486+
487+
# Display projects with numbers
488+
table = Table()
489+
table.add_column("#")
490+
table.add_column("ID")
491+
table.add_column("Name")
492+
table.add_column("Description")
493+
table.add_column("Current", justify="center")
494+
495+
for num, project in choices.items():
496+
description = project.description or ""
497+
if len(description) > 47:
498+
description = description[:47] + "..."
499+
is_current = "✓" if project.id == client.state.project_id else ""
500+
table.add_row(num, project.id, project.name, description, is_current)
501+
502+
console.print(table)
464503

465-
team_id = team_id or client.state.team_id
466-
project = client.projects.create(
467-
name=name, team_id=team_id, description=description
504+
# Prompt for selection
505+
choice = Prompt.ask(
506+
"\nSelect project number",
507+
choices=list(choices.keys()),
508+
show_choices=False,
468509
)
469510

470-
typer.echo("Project created successfully!")
471-
typer.echo(f"ID: {project.id}")
472-
typer.echo(f"Name: {project.name}")
473-
if project.description:
474-
typer.echo(f"Description: {project.description}")
511+
selected_project = choices[choice]
512+
client.set_current_project(selected_project.id)
513+
typer.echo(
514+
f"\nCurrent project set to {selected_project.name} (ID: {selected_project.id})"
515+
)
475516

476517
except Exception as e:
477-
typer.echo(f"Failed to create project: {e}", err=True)
518+
typer.echo(f"Failed to select project: {e}", err=True)
478519
raise typer.Exit(1)
479520

480521

@@ -859,6 +900,94 @@ def jobs_subscribe(datasource_id: str):
859900
raise typer.Exit(1)
860901

861902

903+
@teams_app.command(name="list")
904+
def teams_list(
905+
json_output: bool = typer.Option(False, "--json", help="Output in JSON format")
906+
):
907+
"""List teams the user has access to."""
908+
client = get_client()
909+
910+
try:
911+
teams = client.teams.list()
912+
913+
if not teams:
914+
typer.echo("No teams found")
915+
return
916+
917+
if json_output:
918+
team_data = [
919+
{
920+
"id": team.id,
921+
"name": team.name,
922+
"is_current": team.id == client.state.team_id,
923+
}
924+
for team in teams
925+
]
926+
print(json.dumps(team_data, indent=2))
927+
return
928+
929+
table = Table()
930+
table.add_column("ID")
931+
table.add_column("Name")
932+
table.add_column("Current", justify="center")
933+
934+
for team in teams:
935+
is_current = "✓" if team.id == client.state.team_id else ""
936+
table.add_row(team.id, team.name, is_current)
937+
938+
console.print(table)
939+
940+
except Exception as e:
941+
typer.echo(f"Failed to list teams: {e}", err=True)
942+
raise typer.Exit(1)
943+
944+
945+
@teams_app.command(name="select")
946+
def teams_select():
947+
"""Interactively select a team to set as current."""
948+
client = get_client()
949+
950+
try:
951+
teams = client.teams.list()
952+
953+
if not teams:
954+
typer.echo("No teams found")
955+
return
956+
957+
# Create a list of choices
958+
choices = {str(i): team for i, team in enumerate(teams, 1)}
959+
960+
# Display teams with numbers
961+
table = Table()
962+
table.add_column("#")
963+
table.add_column("ID")
964+
table.add_column("Name")
965+
table.add_column("Current", justify="center")
966+
967+
for num, team in choices.items():
968+
is_current = "✓" if team.id == client.state.team_id else ""
969+
table.add_row(num, team.id, team.name, is_current)
970+
971+
console.print(table)
972+
973+
# Prompt for selection
974+
choice = Prompt.ask(
975+
"\nSelect team number",
976+
choices=list(choices.keys()),
977+
show_choices=False,
978+
)
979+
980+
selected_team = choices[choice]
981+
client.set_current_team(selected_team.id)
982+
typer.echo(
983+
f"\nCurrent team set to {selected_team.name} (ID: {selected_team.id})"
984+
)
985+
986+
except Exception as e:
987+
typer.echo(f"Failed to select team: {e}", err=True)
988+
raise typer.Exit(1)
989+
990+
862991
def main():
863992
"""Main entry point for the CLI."""
864993
try:

0 commit comments

Comments
 (0)