Skip to content

Commit

Permalink
Merge pull request #66 from lcfd/issue-62
Browse files Browse the repository at this point in the history
[projects] Add trak projects archive <project-id> command #62
  • Loading branch information
lcfd authored Apr 17, 2024
2 parents 63bc837 + 38bf498 commit 6ad8709
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 53 deletions.
3 changes: 2 additions & 1 deletion cli/trakcli/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ def version_callback(value: bool) -> None:
Print the application version.
"""
if value:
rprint("")
rprint(
Panel(
Panel.fit(
renderable=Align.center(f"{__app_name__} v{__version__}"),
title=__app_name__,
padding=(2),
Expand Down
2 changes: 2 additions & 0 deletions cli/trakcli/create/commands/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def create_project(
tags = typer.prompt("Tags (CSV format)", default="")
customer = typer.prompt("Customer", default="")
hour_rate = typer.prompt("Hour rate", default=1, show_default=True)
archived = typer.prompt("Archived", default=False, show_default=True)

if project_id:
new_project = Project(
Expand All @@ -51,6 +52,7 @@ def create_project(
tags=[t.strip() for t in tags.split(",")] if tags != "" else [],
customer=customer,
rate=hour_rate,
archived=archived,
)

with open(details_path, "w") as details_file:
Expand Down
4 changes: 2 additions & 2 deletions cli/trakcli/create/commands/work.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from rich import print as rprint
from rich.panel import Panel

from trakcli.projects.database import get_project_from_config, get_projects_from_config
from trakcli.projects.database import db_get_project_details, get_projects_from_config
from trakcli.projects.utils.print_missing_project import print_missing_project
from trakcli.utils.print_with_padding import print_with_padding
from trakcli.works.database import (
Expand Down Expand Up @@ -88,7 +88,7 @@ def create_work(
projects_in_config = get_projects_from_config(archived)

if project_id in projects_in_config:
details = get_project_from_config(project_id)
details = db_get_project_details(project_id)

# Check if project esists
if details:
Expand Down
2 changes: 1 addition & 1 deletion cli/trakcli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from trakcli.create import app as create_app
from trakcli.dev.commands import app as dev_app
from trakcli.initialize import initialize_trak
from trakcli.projects.commands import app as projects_app
from trakcli.projects import app as projects_app
from trakcli.report import app as report_app
from trakcli.tracker.commands.get_current_session_status import (
get_current_session_status,
Expand Down
12 changes: 12 additions & 0 deletions cli/trakcli/projects/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import typer

from trakcli.projects.commands.archive import command_project_archive
from trakcli.projects.commands.delete import command_project_delete
from trakcli.projects.commands.list import command_project_list

app = typer.Typer()


app.command(name="list", help="List your projects.")(command_project_list)
app.command(name="delete", help="Delete a project.")(command_project_delete)
app.command(name="archive", help="Archive a project.")(command_project_archive)
Empty file.
70 changes: 70 additions & 0 deletions cli/trakcli/projects/commands/archive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import json
from typing import Annotated, Optional

import questionary
import typer

from trakcli.config.models import Project
from trakcli.projects.database import (
db_get_project_details,
db_get_project_details_path,
get_projects_from_config,
)
from trakcli.projects.messages.print_project_archived_toggle import (
print_project_archived_toggle,
)
from trakcli.projects.messages.print_project_broken_configuration import (
print_project_broken_configuration,
)
from trakcli.projects.utils.print_missing_project import print_missing_project
from trakcli.projects.utils.print_no_projects import print_no_projects
from trakcli.utils.styles_questionary import questionary_style_select
from rich import print as rprint


def command_project_archive(project: Annotated[Optional[str], typer.Argument()] = None):
"""Archive a project."""

projects_in_config = get_projects_from_config(True)

# Check if there are configured projects
if not len(projects_in_config):
print_no_projects()
return

# Provide the list of prjects to the user
if not project:
project = questionary.select(
"Select a project:",
choices=projects_in_config,
pointer="• ",
show_selected=True,
style=questionary_style_select,
).ask()

if not project:
return

# Check if the project exists
if not project or project not in projects_in_config:
print_missing_project(projects_in_config)
return

details_path = db_get_project_details_path(project)
details = db_get_project_details(project)

if details_path and details:
# Toggle the value of archived
details = details._replace(archived=not details.archived)

with open(details_path, "w") as details_file:
json.dump(
details._asdict(),
details_file,
indent=2,
separators=(",", ": "),
)
print_project_archived_toggle(project, details.archived)
else:
print_project_broken_configuration(project)
return
Original file line number Diff line number Diff line change
@@ -1,57 +1,15 @@
import pathlib
import shutil
from typing import Annotated, Optional

import typer
from rich import print as rprint
from rich.panel import Panel
from rich.table import Table

from trakcli.config.main import (
TRAK_FOLDER,
)
from trakcli.projects.database import (
get_projects_from_config,
)
from trakcli.config.main import TRAK_FOLDER
from trakcli.utils.print_with_padding import print_with_padding

app = typer.Typer()


@app.command(help="List your projects.")
def list(
archived: Annotated[
Optional[bool],
typer.Option(
"--archived",
"-a",
help="Show archived projects in lists.",
),
] = False,
):
"""List the projects."""

projects_in_config = get_projects_from_config(archived)
combined = {*projects_in_config}

number_of_projects = len(combined)

table = Table(
title=f"{number_of_projects} Projects",
)

table.add_column("id", style="green", no_wrap=True)
table.add_column("from", style="cyan", no_wrap=True)

for project in projects_in_config:
table.add_row(project, "config")

rprint("")
rprint(table)


@app.command(help="Delete a project.")
def delete(project_id: str):
def command_project_delete(project_id: str):
"""Delete a project."""

project_path = pathlib.Path(TRAK_FOLDER / "projects" / project_id)
Expand Down
38 changes: 38 additions & 0 deletions cli/trakcli/projects/commands/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import Annotated, Optional

import typer
from rich import print as rprint
from rich.table import Table

from trakcli.projects.database import get_projects_from_config


def command_project_list(
archived: Annotated[
Optional[bool],
typer.Option(
"--archived",
"-a",
help="Show archived projects in lists.",
),
] = False,
):
"""List the projects."""

projects_in_config = get_projects_from_config(archived)
combined = {*projects_in_config}

number_of_projects = len(combined)

table = Table(
title=f"{number_of_projects} Projects",
)

table.add_column("id", style="green", no_wrap=True)
table.add_column("from", style="cyan", no_wrap=True)

for project in projects_in_config:
table.add_row(project, "config")

rprint("")
rprint(table)
28 changes: 26 additions & 2 deletions cli/trakcli/projects/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
import pathlib

from trakcli.config.main import TRAK_FOLDER
from trakcli.config.models import Project

from rich import print as rprint

from trakcli.projects.messages.print_project_broken_configuration import (
print_project_broken_configuration,
)


def get_projects_from_db(db_path: Path):
Expand Down Expand Up @@ -35,7 +42,7 @@ def get_projects_from_config(archived: bool | None = False):
return projects


def get_project_from_config(project_id: str):
def db_get_project_details(project_id: str) -> Project | None:
"""Get a project in the config by id."""

project_path = pathlib.Path(TRAK_FOLDER / "projects" / project_id)
Expand All @@ -44,6 +51,23 @@ def get_project_from_config(project_id: str):
details_path = project_path / "details.json"
with open(details_path, "r") as f:
details = json.load(f)
return details
try:
project = Project(**details)
except Exception:
print_project_broken_configuration(project_id)
return None

return project
else:
return None


def db_get_project_details_path(project_id: str):
"""Get project config path."""

project_path = pathlib.Path(TRAK_FOLDER / "projects" / project_id)

if project_path.exists() and project_path.is_dir():
return project_path / "details.json"
else:
return None
34 changes: 34 additions & 0 deletions cli/trakcli/projects/messages/print_project_archived_toggle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from rich import print as rprint
from rich.panel import Panel

from trakcli.utils.print_with_padding import print_with_padding


def print_project_archived_toggle(project_id: str, archived: bool):
rprint("")
if archived:
rprint(
Panel.fit(
title=f"[green] The project {project_id} has been archived",
renderable=print_with_padding(
(
"From now on this project won't be accessible from lists.\n\n"
"[orange3]⭐Tip:[/orange3]\n"
f"You can run trak [orange3]project archive {project_id}[/orange3] to unarchive it."
)
),
)
)
else:
rprint(
Panel.fit(
title=f"[green]󱝢 The project {project_id} has been unarchived",
renderable=print_with_padding(
(
"From now on this project will be accessible from lists.\n\n"
"[orange3]⭐Tip:[/orange3]\n"
f"You can run trak [orange3]project archive {project_id}[/orange3] to archive it."
)
),
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from rich import print as rprint
from rich.panel import Panel

from trakcli.utils.print_with_padding import print_with_padding


def print_project_broken_configuration(project_id: str):
rprint("")
rprint(
Panel.fit(
title=f"[red]The project {project_id} has broken configuration",
renderable=print_with_padding(
("Please, check the details.json file in your project folder.")
),
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def print_session_already_started(record: Record):
formatted_start_time = start_datetime.strftime("%Y-%m-%d, %H:%M")

msg = (
f"Tracking on [bold green]{record.project}[/bold green] "
f"Tracking on [bold green]{record.project}[/bold green]"
f"already started at {formatted_start_time}.\n\n"
f"It's been going for [bold green]{h}h {m}m[/bold green]."
)
Expand Down
4 changes: 2 additions & 2 deletions cli/trakcli/works/commands/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from rich import print as rprint
from rich.table import Table

from trakcli.projects.database import get_project_from_config, get_projects_from_config
from trakcli.projects.database import db_get_project_details, get_projects_from_config
from trakcli.works.database import get_project_works_from_config

ALL_PROJECTS = "all"
Expand Down Expand Up @@ -99,7 +99,7 @@ def list_works(
"""List the works in a project or all of them."""

if project_id != ALL_PROJECTS:
details = get_project_from_config(project_id)
details = db_get_project_details(project_id)

# Check if project esists
if details:
Expand Down

0 comments on commit 6ad8709

Please sign in to comment.