summaryrefslogtreecommitdiffstats
path: root/girok/commands/category/command.py
diff options
context:
space:
mode:
Diffstat (limited to 'girok/commands/category/command.py')
-rw-r--r--girok/commands/category/command.py218
1 files changed, 178 insertions, 40 deletions
diff --git a/girok/commands/category/command.py b/girok/commands/category/command.py
index 8486587..a037ec0 100644
--- a/girok/commands/category/command.py
+++ b/girok/commands/category/command.py
@@ -1,17 +1,28 @@
import re
-from typing_extensions import Annotated
+
import typer
from rich import print
from rich.console import Console
from rich.markdown import Markdown
-from rich.tree import Tree
-from rich.text import Text
from rich.style import Style
+from rich.text import Text
+from rich.tree import Tree
+from typing_extensions import Annotated
import girok.api.category as category_api
-from girok.commands.category.util import display_categories_tree, get_next_category_color
-from girok.constants import DisplayBoxType, CATEGORY_COLOR_PALETTE, Emoji, DEFAULT_CATEGORY_TEXT_COLOR, DisplayArrowType
-from girok.utils.display import center_print, arrow_print
+from girok.commands.category.util import (
+ display_categories_tree,
+ display_category_color_palette,
+ get_next_category_color,
+)
+from girok.constants import (
+ CATEGORY_COLOR_PALETTE,
+ DEFAULT_CATEGORY_TEXT_COLOR,
+ DisplayArrowType,
+ DisplayBoxType,
+ Emoji,
+)
+from girok.utils.display import arrow_print, center_print
app = typer.Typer(rich_markup_mode="rich")
console = Console()
@@ -21,10 +32,11 @@ def category_callback(ctx: typer.Context, param: typer.CallbackParam, value: str
if value is None:
return None
+ if ctx.command.name == "mvcat" and param.name == "new_parent_path" and value == "/":
+ return value.rstrip("/")
+
if not re.match("^([a-zA-Z0-9]+/)*[a-zA-Z0-9]+/?$", value):
- raise typer.BadParameter(
- "[Invalid category path] Category path must be in 'xx/yy/zz format.'"
- )
+ raise typer.BadParameter("[Invalid category path] Category path must be in 'xx/yy/zz format.'")
if value.endswith("/"):
value = value[:-1]
@@ -56,48 +68,174 @@ def show_categories():
rich_help_panel=":file_folder: [bold yellow1]Category Commands[/bold yellow1]",
)
def add_category(
- category_path: Annotated[str, typer.Argument(
- ...,
- help="[yellow]Category path - xx/yy/zz..[/yellow]",
- callback=category_callback,
- )],
- color: Annotated[str, typer.Option(
- "-c", "--color",
- help="[yellow]Color[/yellow] for category"
- )] = None
+ category_path: Annotated[
+ str,
+ typer.Argument(
+ ...,
+ help="[yellow]Category path - xx/yy/zz..[/yellow]",
+ callback=category_callback,
+ ),
+ ],
+ color: Annotated[str, typer.Option("-c", "--color", help="[yellow]Color[/yellow] for category")] = None,
):
# Resolve color
if color:
+ if len(category_path.split("/")) != 1:
+ arrow_print("You cannot specify non top-level category color", DisplayArrowType.ERROR)
+ raise typer.Exit()
+
if color not in CATEGORY_COLOR_PALETTE:
arrow_print("Unsupported category color\n", DisplayArrowType.ERROR)
- tree = Tree("Supported category colors")
- for color_name, hex in CATEGORY_COLOR_PALETTE.items():
- circle_text = Text(text=Emoji.CIRCLE, style=Style(color=CATEGORY_COLOR_PALETTE[color_name]))
- category_name_text = Text(
- text=f"{color_name}",
- style=Style(color=DEFAULT_CATEGORY_TEXT_COLOR)
- )
- item_text = Text.assemble(circle_text, " ", category_name_text)
- tree.add(item_text)
- console.print(tree)
+ display_category_color_palette()
raise typer.Exit()
else:
- # If color is not passed, automatically assign the color from the palette
- color = get_next_category_color()
-
- print(category_path)
- print(color)
+ # If color is not passed and top-level category, automatically assign the color from the palette
+ if len(category_path.split("/")) == 1:
+ color = get_next_category_color()
+ # Create a new category
resp = category_api.create_category(category_path, color)
- print(resp.is_success)
- print(resp.error_message)
-
-
-
-
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ resp = category_api.get_all_categories()
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ center_print("Event Categories", DisplayBoxType.TITLE)
+ root_categories: list[dict] = resp.body["rootCategories"]
+ display_categories_tree(root_categories, category_path)
+
+
+@app.command(
+ "rmcat",
+ help="[red]Remove[/red] a category",
+ rich_help_panel=":file_folder: [bold yellow1]Category Commands[/bold yellow1]",
+)
+def remove_category(
+ category_path: Annotated[
+ str,
+ typer.Argument(
+ ...,
+ help="[yellow]Category path - xx/yy/zz..[/yellow]",
+ callback=category_callback,
+ ),
+ ],
+ force_yes: Annotated[bool, typer.Option("-y", "--yes", help="[yellow]Ignore confirm message[/yellow]")] = False,
+):
+ if not force_yes:
+ confirm_rm = typer.confirm(
+ f"[WARNING] Are you sure to delete '{category_path}'?\nAll the subcategories and tasks will also be deleted."
+ )
+ if not confirm_rm:
+ raise typer.Exit()
+
+ resp = category_api.remove_category(category_path)
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ resp = category_api.get_all_categories()
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ center_print("Event Categories", DisplayBoxType.TITLE)
+ root_categories: list[dict] = resp.body["rootCategories"]
+ display_categories_tree(root_categories, category_path)
+
+
+@app.command(
+ "upcat",
+ help="[green]Rename[/green] a category",
+ rich_help_panel=":file_folder: [bold yellow1]Category Commands[/bold yellow1]",
+)
+def rename_category(
+ category_path: Annotated[
+ str,
+ typer.Argument(
+ help="[yellow]Category path - xx/yy/zz..[/yellow]",
+ callback=category_callback,
+ ),
+ ],
+ new_name: Annotated[str, typer.Option("-n", "--name", help="[yellow]New category name[/yellow]")] = None,
+ new_color: Annotated[str, typer.Option("-c", "--color", help="[yellow]New category color[/yellow]")] = None,
+):
+ if new_name is None and new_color is None:
+ arrow_print("Please provide fields to update", DisplayArrowType.ERROR)
+ raise typer.Exit()
+
+ # Resolve color
+ if new_color:
+ if len(category_path.split("/")) != 1:
+ arrow_print("You cannot update non top-level category color", DisplayArrowType.ERROR)
+ raise typer.Exit()
+ if new_color not in CATEGORY_COLOR_PALETTE:
+ arrow_print("Unsupported category color\n", DisplayArrowType.ERROR)
+ display_category_color_palette()
+ raise typer.Exit()
-
+ resp = category_api.update_category(category_path, new_name, new_color)
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+ resp = category_api.get_all_categories()
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+ center_print("Event Categories", DisplayBoxType.TITLE)
+ root_categories: list[dict] = resp.body["rootCategories"]
+ name = new_name if new_name else category_path.split("/")[-1]
+ new_path = "/".join(category_path.split("/")[:-1] + [name])
+ display_categories_tree(root_categories, new_path)
+
+@app.command(
+ "mvcat",
+ help="[yellow]Move[/yellow] a category to under category",
+ rich_help_panel=":file_folder: [bold yellow1]Category Commands[/bold yellow1]",
+)
+def move_category(
+ path: Annotated[
+ str,
+ typer.Argument(
+ help="[yellow]Category path - xx/yy/zz..[/yellow]",
+ callback=category_callback,
+ ),
+ ],
+ new_parent_path: Annotated[
+ str,
+ typer.Argument(
+ help="[yellow]Category path - xx/yy/zz..[/yellow]",
+ callback=category_callback,
+ ),
+ ],
+):
+ resp = category_api.move_category(path, new_parent_path)
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ resp = category_api.get_all_categories()
+ if not resp.is_success:
+ center_print(resp.error_message, DisplayBoxType.ERROR)
+ raise typer.Exit()
+
+ center_print("Event Categories", DisplayBoxType.TITLE)
+ root_categories: list[dict] = resp.body["rootCategories"]
+ new_path = "/".join(new_parent_path.split("/") + [path.split("/")[-1]])
+ display_categories_tree(root_categories, new_path)
+
+
+@app.command(
+ "colors",
+ help="[yellow]Show[/yellow] category color palette",
+ rich_help_panel=":file_folder: [bold yellow1]Category Commands[/bold yellow1]",
+)
+def show_category_color_palette():
+ display_category_color_palette()