Files
nimbusflow/backend/cli/interactive.py

330 lines
14 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Interactive CLI interface for NimbusFlow.
"""
import sys
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .base import NimbusFlowCLI
from .commands import (
cmd_members_list, cmd_members_show,
cmd_schedules_list, cmd_schedules_show, cmd_schedules_accept, cmd_schedules_decline, cmd_schedules_schedule,
cmd_services_list,
)
def load_ascii_art() -> str:
"""Load ASCII art from file."""
ascii_file = Path(__file__).parent / "ascii.txt"
if ascii_file.exists():
with open(ascii_file, 'r', encoding='utf-8') as f:
content = f.read()
# Use only the cloud portion (middle section) for better display
lines = content.strip().split('\n')
if len(lines) > 30:
# Take a smaller portion of the cloud art
start = len(lines) // 3
end = start + 15
return '\n'.join(lines[start:end])
return content
return "🎵 NimbusFlow 🎵" # Fallback if file doesn't exist
def display_welcome():
"""Display welcome screen with ASCII art."""
print("\033[2J\033[H") # Clear screen and move cursor to top
# Display the cloud ASCII art
ascii_art = load_ascii_art()
print(ascii_art)
print()
# Add the NimbusFlow branding
welcome_text = """
╔═══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ███╗ ██╗██╗███╗ ███╗██████╗ ██╗ ██╗███████╗ ███████╗██╗ ██████╗ ██╗ ██╗ ║
║ ████╗ ██║██║████╗ ████║██╔══██╗██║ ██║██╔════╝ ██╔════╝██║ ██╔═══██╗██║ ██║ ║
║ ██╔██╗ ██║██║██╔████╔██║██████╔╝██║ ██║███████╗ █████╗ ██║ ██║ ██║██║ █╗ ██║ ║
║ ██║╚██╗██║██║██║╚██╔╝██║██╔══██╗██║ ██║╚════██║ ██╔══╝ ██║ ██║ ██║██║███╗██║ ║
║ ██║ ╚████║██║██║ ╚═╝ ██║██████╔╝╚██████╔╝███████║ ██║ ███████╗╚██████╔╝╚███╔███╔╝ ║
║ ╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚══════╝ ╚═════╝ ╚══╝╚══╝ ║
║ ║
║ 🎵 Choir Scheduling System 🎵 ║
╚═══════════════════════════════════════════════════════════════════════════════╝
"""
print(welcome_text)
print()
def display_main_menu():
"""Display the main menu options."""
print("🎯 " + "="*60)
print(" MAIN MENU - What would you like to manage?")
print("🎯 " + "="*60)
print()
print(" 1⃣ 👥 Members - Manage choir members")
print(" 2⃣ 📅 Schedules - View and manage schedules")
print(" 3⃣ 🎼 Services - Manage services and events")
print(" 4⃣ ❌ Exit - Close NimbusFlow CLI")
print()
def display_members_menu():
"""Display members submenu."""
print("\n👥 " + "="*50)
print(" MEMBERS MENU")
print("👥 " + "="*50)
print()
print(" 1⃣ 📋 List all members")
print(" 2⃣ ✅ List active members only")
print(" 3⃣ 🎵 List by classification")
print(" 4⃣ 👤 Show member details")
print(" 5⃣ 🔙 Back to main menu")
print()
def display_schedules_menu():
"""Display schedules submenu."""
print("\n📅 " + "="*50)
print(" SCHEDULES MENU")
print("📅 " + "="*50)
print()
print(" 1⃣ 📋 List all schedules")
print(" 2⃣ ⏳ List pending schedules")
print(" 3⃣ ✅ List accepted schedules")
print(" 4⃣ ❌ List declined schedules")
print(" 5⃣ 👤 Show schedule details")
print(" 6⃣ ✨ Accept a schedule (interactive)")
print(" 7⃣ 🚫 Decline a schedule (interactive)")
print(" 8⃣ 📅 Schedule next member for service")
print(" 9⃣ 🔙 Back to main menu")
print()
def display_services_menu():
"""Display services submenu."""
print("\n🎼 " + "="*50)
print(" SERVICES MENU")
print("🎼 " + "="*50)
print()
print(" 1⃣ 📋 List all services")
print(" 2⃣ 🔮 List upcoming services")
print(" 3⃣ 📅 List services by date")
print(" 4⃣ 🔙 Back to main menu")
print()
def get_user_choice(max_options: int) -> int:
"""Get user menu choice with validation."""
while True:
try:
choice = input(f"🎯 Enter your choice (1-{max_options}): ").strip()
if not choice:
continue
choice_int = int(choice)
if 1 <= choice_int <= max_options:
return choice_int
else:
print(f"❌ Please enter a number between 1 and {max_options}")
except ValueError:
print("❌ Please enter a valid number")
except (KeyboardInterrupt, EOFError):
print("\n🛑 Goodbye!")
sys.exit(0)
def get_text_input(prompt: str, required: bool = True) -> str:
"""Get text input from user."""
while True:
try:
value = input(f"📝 {prompt}: ").strip()
if value or not required:
return value
print("❌ This field is required")
except (KeyboardInterrupt, EOFError):
print("\n🛑 Operation cancelled")
return ""
def get_date_input(prompt: str = "Enter date (YYYY-MM-DD)") -> str:
"""Get date input from user."""
while True:
try:
date_str = input(f"📅 {prompt}: ").strip()
if not date_str:
print("❌ Date is required")
continue
# Basic date format validation
if len(date_str) == 10 and date_str.count('-') == 2:
parts = date_str.split('-')
if len(parts[0]) == 4 and len(parts[1]) == 2 and len(parts[2]) == 2:
return date_str
print("❌ Please use format YYYY-MM-DD (e.g., 2025-09-07)")
except (KeyboardInterrupt, EOFError):
print("\n🛑 Operation cancelled")
return ""
class MockArgs:
"""Mock args object for interactive commands."""
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
def handle_members_menu(cli: "NimbusFlowCLI"):
"""Handle members menu interactions."""
while True:
display_members_menu()
choice = get_user_choice(5)
if choice == 1: # List all members
print("\n🔍 Listing all members...")
cmd_members_list(cli, MockArgs(active=False, classification=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 2: # List active members
print("\n🔍 Listing active members...")
cmd_members_list(cli, MockArgs(active=True, classification=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 3: # List by classification
classification = get_text_input("Enter classification (Soprano, Alto / Mezzo, Tenor, Baritone)", True)
if classification:
print(f"\n🔍 Listing {classification} members...")
cmd_members_list(cli, MockArgs(active=False, classification=classification))
input("\n⏸️ Press Enter to continue...")
elif choice == 4: # Show member details
member_id = get_text_input("Enter member ID", True)
if member_id.isdigit():
print(f"\n🔍 Showing details for member {member_id}...")
cmd_members_show(cli, MockArgs(member_id=int(member_id)))
else:
print("❌ Invalid member ID")
input("\n⏸️ Press Enter to continue...")
elif choice == 5: # Back to main menu
break
def handle_schedules_menu(cli: "NimbusFlowCLI"):
"""Handle schedules menu interactions."""
while True:
display_schedules_menu()
choice = get_user_choice(9)
if choice == 1: # List all schedules
print("\n🔍 Listing all schedules...")
cmd_schedules_list(cli, MockArgs(service_id=None, status=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 2: # List pending schedules
print("\n🔍 Listing pending schedules...")
cmd_schedules_list(cli, MockArgs(service_id=None, status="pending"))
input("\n⏸️ Press Enter to continue...")
elif choice == 3: # List accepted schedules
print("\n🔍 Listing accepted schedules...")
cmd_schedules_list(cli, MockArgs(service_id=None, status="accepted"))
input("\n⏸️ Press Enter to continue...")
elif choice == 4: # List declined schedules
print("\n🔍 Listing declined schedules...")
cmd_schedules_list(cli, MockArgs(service_id=None, status="declined"))
input("\n⏸️ Press Enter to continue...")
elif choice == 5: # Show schedule details
schedule_id = get_text_input("Enter schedule ID", True)
if schedule_id.isdigit():
print(f"\n🔍 Showing details for schedule {schedule_id}...")
cmd_schedules_show(cli, MockArgs(schedule_id=int(schedule_id)))
else:
print("❌ Invalid schedule ID")
input("\n⏸️ Press Enter to continue...")
elif choice == 6: # Accept schedule
date = get_date_input("Enter date for interactive accept")
if date:
print(f"\n✨ Starting interactive accept for {date}...")
cmd_schedules_accept(cli, MockArgs(date=date, schedule_id=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 7: # Decline schedule
date = get_date_input("Enter date for interactive decline")
if date:
reason = get_text_input("Enter decline reason (optional)", False)
print(f"\n🚫 Starting interactive decline for {date}...")
cmd_schedules_decline(cli, MockArgs(date=date, schedule_id=None, reason=reason))
input("\n⏸️ Press Enter to continue...")
elif choice == 8: # Schedule next member
date = get_date_input("Enter date to schedule for")
if date:
print(f"\n📅 Starting scheduling for {date}...")
cmd_schedules_schedule(cli, MockArgs(service_id=None, date=date, classifications=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 9: # Back to main menu
break
def handle_services_menu(cli: "NimbusFlowCLI"):
"""Handle services menu interactions."""
while True:
display_services_menu()
choice = get_user_choice(4)
if choice == 1: # List all services
print("\n🔍 Listing all services...")
cmd_services_list(cli, MockArgs(date=None, upcoming=False, limit=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 2: # List upcoming services
print("\n🔍 Listing upcoming services...")
cmd_services_list(cli, MockArgs(date=None, upcoming=True, limit=20))
input("\n⏸️ Press Enter to continue...")
elif choice == 3: # List by date
date = get_date_input("Enter date to filter services")
if date:
print(f"\n🔍 Listing services for {date}...")
cmd_services_list(cli, MockArgs(date=date, upcoming=False, limit=None))
input("\n⏸️ Press Enter to continue...")
elif choice == 4: # Back to main menu
break
def run_interactive_mode(cli: "NimbusFlowCLI"):
"""Run the main interactive CLI mode."""
display_welcome()
print("🎉 Welcome to the NimbusFlow Interactive CLI!")
print(" Navigate through menus to manage your choir scheduling system.")
print()
input("⏸️ Press Enter to continue...")
while True:
print("\033[2J\033[H") # Clear screen
display_main_menu()
choice = get_user_choice(4)
if choice == 1: # Members
handle_members_menu(cli)
elif choice == 2: # Schedules
handle_schedules_menu(cli)
elif choice == 3: # Services
handle_services_menu(cli)
elif choice == 4: # Exit
print("\n🎵 Thank you for using NimbusFlow!")
print(" Have a wonderful day! 🌟")
break