major-domo-v2/views
Cal Corum c01f88e7e3 CLAUDE: Comprehensive bot improvements and test infrastructure
This commit includes various enhancements across the bot architecture:

**New Infrastructure:**
- Added tests/factories.py - Factory classes for creating test data objects
- Added PRE_LAUNCH_ROADMAP.md - Project planning and roadmap documentation

**Model Enhancements:**
- Updated models/roster.py - Enhanced roster data structures
- Updated models/team.py - Improved team model definitions

**Service Layer Improvements:**
- Enhanced services/player_service.py - Better player data handling
- Updated services/roster_service.py - Roster management improvements
- Enhanced services/team_service.py - Team data service refinements
- Updated services/transaction_service.py - Transaction processing enhancements

**Command Updates:**
- Updated commands/teams/info.py - Team information command improvements
- Enhanced commands/voice/tracker.py - Voice channel tracking refinements

**Background Tasks:**
- Updated tasks/custom_command_cleanup.py - Automated cleanup improvements

**View Components:**
- Enhanced views/transaction_embed.py - Transaction embed UI improvements

**Test Coverage Enhancements:**
- Updated tests/test_commands_voice.py - Voice command test improvements
- Enhanced tests/test_dropadd_integration.py - Integration test coverage
- Updated tests/test_services_player_service.py - Player service test coverage
- Enhanced tests/test_services_transaction_builder.py - Transaction builder tests
- Updated tests/test_transactions_integration.py - Transaction integration tests
- Enhanced tests/test_views_transaction_embed.py - UI component test coverage

These changes collectively improve the bot's reliability, maintainability, and test coverage while adding essential infrastructure for continued development.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 11:35:26 -05:00
..
__init__.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
base.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
common.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
custom_commands.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
embeds.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
modals.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
README.md CLAUDE: Implement voice channel management system 2025-09-24 23:17:39 -05:00
transaction_embed.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00

Views Directory

The views directory contains Discord UI components for Discord Bot v2.0, providing consistent visual interfaces and interactive elements. This includes embeds, modals, buttons, select menus, and other Discord UI components.

Architecture

Component-Based UI Design

Views in Discord Bot v2.0 follow these principles:

  • Consistent styling via centralized templates
  • Reusable components for common UI patterns
  • Error handling with graceful degradation
  • User interaction tracking and validation
  • Accessibility with proper labeling and feedback

Base Components

All view components inherit from Discord.py base classes with enhanced functionality:

  • BaseView - Enhanced discord.ui.View with logging and user validation
  • BaseModal - Enhanced discord.ui.Modal with error handling
  • EmbedTemplate - Centralized embed creation with consistent styling

View Components

Base View System (base.py)

BaseView Class

Foundation for all interactive views:

class BaseView(discord.ui.View):
    def __init__(self, timeout=180.0, user_id=None):
        super().__init__(timeout=timeout)
        self.user_id = user_id
        self.logger = get_contextual_logger(f'{__name__}.BaseView')

    async def interaction_check(self, interaction) -> bool:
        """Validate user permissions for interaction."""

    async def on_timeout(self) -> None:
        """Handle view timeout gracefully."""

    async def on_error(self, interaction, error, item) -> None:
        """Handle view errors with user feedback."""

ConfirmationView Class

Standard Yes/No confirmation dialogs:

confirmation = ConfirmationView(
    user_id=interaction.user.id,
    confirm_callback=handle_confirm,
    cancel_callback=handle_cancel
)
await interaction.followup.send("Confirm action?", view=confirmation)

PaginationView Class

Multi-page navigation for large datasets:

pages = [embed1, embed2, embed3]
pagination = PaginationView(
    pages=pages,
    user_id=interaction.user.id,
    show_page_numbers=True
)
await interaction.followup.send(embed=pagination.get_current_embed(), view=pagination)

Embed Templates (embeds.py)

EmbedTemplate Class

Centralized embed creation with consistent styling:

# Success embed
embed = EmbedTemplate.success(
    title="Operation Completed",
    description="Your request was processed successfully."
)

# Error embed
embed = EmbedTemplate.error(
    title="Operation Failed",
    description="Please check your input and try again."
)

# Warning embed
embed = EmbedTemplate.warning(
    title="Careful!",
    description="This action cannot be undone."
)

# Info embed
embed = EmbedTemplate.info(
    title="Information",
    description="Here's what you need to know."
)

EmbedColors Dataclass

Consistent color scheme across all embeds:

@dataclass(frozen=True)
class EmbedColors:
    PRIMARY: int = 0xa6ce39      # SBA green
    SUCCESS: int = 0x28a745      # Green
    WARNING: int = 0xffc107      # Yellow
    ERROR: int = 0xdc3545        # Red
    INFO: int = 0x17a2b8         # Blue
    SECONDARY: int = 0x6c757d    # Gray

Modal Forms (modals.py)

BaseModal Class

Foundation for interactive forms:

class BaseModal(discord.ui.Modal):
    def __init__(self, title: str, timeout=300.0):
        super().__init__(title=title, timeout=timeout)
        self.logger = get_contextual_logger(f'{__name__}.BaseModal')
        self.result = None

    async def on_submit(self, interaction):
        """Handle form submission."""

    async def on_error(self, interaction, error):
        """Handle form errors."""

Usage Pattern

class CustomCommandModal(BaseModal):
    def __init__(self):
        super().__init__(title="Create Custom Command")

    name = discord.ui.TextInput(
        label="Command Name",
        placeholder="Enter command name...",
        required=True,
        max_length=50
    )

    response = discord.ui.TextInput(
        label="Response",
        placeholder="Enter command response...",
        style=discord.TextStyle.paragraph,
        required=True,
        max_length=2000
    )

    async def on_submit(self, interaction):
        # Process form data
        command_data = {
            "name": self.name.value,
            "response": self.response.value
        }
        # Handle creation logic

Common UI Elements (common.py)

Shared Components

  • Loading indicators for async operations
  • Status messages for operation feedback
  • Navigation elements for multi-step processes
  • Validation displays for form errors

Specialized Views

Custom Commands (custom_commands.py)

Views specific to custom command management:

  • Command creation forms
  • Command listing with actions
  • Bulk management interfaces

Transaction Management (transaction_embed.py)

Views for player transaction interfaces:

  • Transaction proposal forms
  • Approval/rejection workflows
  • Transaction history displays

Styling Guidelines

Embed Consistency

All embeds should use EmbedTemplate methods:

# ✅ Consistent styling
embed = EmbedTemplate.success("Player Added", "Player successfully added to roster")

# ❌ Inconsistent styling
embed = discord.Embed(title="Player Added", color=0x00ff00)

Color Usage

Use the standard color palette:

  • PRIMARY (SBA Green) - Default for neutral information
  • SUCCESS (Green) - Successful operations
  • ERROR (Red) - Errors and failures
  • WARNING (Yellow) - Warnings and cautions
  • INFO (Blue) - General information
  • SECONDARY (Gray) - Less important information

User Feedback

Provide clear feedback for all user interactions:

# Loading state
embed = EmbedTemplate.info("Processing", "Please wait while we process your request...")

# Success state
embed = EmbedTemplate.success("Complete", "Your request has been processed successfully.")

# Error state with helpful information
embed = EmbedTemplate.error(
    "Request Failed",
    "The player name was not found. Please check your spelling and try again."
)

Interactive Components

Button Patterns

Action Buttons

@discord.ui.button(label="Confirm", style=discord.ButtonStyle.success, emoji="✅")
async def confirm_button(self, interaction, button):
    self.increment_interaction_count()
    # Handle confirmation
    await interaction.response.edit_message(content="Confirmed!", view=None)

Navigation Buttons

@discord.ui.button(emoji="◀️", style=discord.ButtonStyle.primary)
async def previous_page(self, interaction, button):
    self.current_page = max(0, self.current_page - 1)
    await interaction.response.edit_message(embed=self.get_current_embed(), view=self)

Select Menu Patterns

Option Selection

@discord.ui.select(placeholder="Choose an option...")
async def select_option(self, interaction, select):
    selected_value = select.values[0]
    # Handle selection
    await interaction.response.send_message(f"You selected: {selected_value}")

Dynamic Options

class PlayerSelectMenu(discord.ui.Select):
    def __init__(self, players: List[Player]):
        options = [
            discord.SelectOption(
                label=player.name,
                value=str(player.id),
                description=f"{player.position} - {player.team.abbrev}"
            )
            for player in players[:25]  # Discord limit
        ]
        super().__init__(placeholder="Select a player...", options=options)

Error Handling

View Error Handling

All views implement comprehensive error handling:

async def on_error(self, interaction, error, item):
    """Handle view errors gracefully."""
    self.logger.error("View error", error=error, item_type=type(item).__name__)

    try:
        embed = EmbedTemplate.error(
            "Interaction Error",
            "Something went wrong. Please try again."
        )

        if not interaction.response.is_done():
            await interaction.response.send_message(embed=embed, ephemeral=True)
        else:
            await interaction.followup.send(embed=embed, ephemeral=True)
    except Exception as e:
        self.logger.error("Failed to send error message", error=e)

User Input Validation

Forms validate user input before processing:

async def on_submit(self, interaction):
    # Validate input
    if len(self.name.value) < 2:
        embed = EmbedTemplate.error(
            "Invalid Input",
            "Command name must be at least 2 characters long."
        )
        await interaction.response.send_message(embed=embed, ephemeral=True)
        return

    # Process valid input
    await self.create_command(interaction)

Accessibility Features

User-Friendly Labels

  • Clear button labels with descriptive text
  • Helpful placeholders in form fields
  • Descriptive error messages with actionable guidance
  • Consistent emoji usage for visual recognition

Permission Validation

Views respect user permissions and provide appropriate feedback:

async def interaction_check(self, interaction) -> bool:
    """Check if user can interact with this view."""
    if self.user_id and interaction.user.id != self.user_id:
        await interaction.response.send_message(
            "❌ You cannot interact with this menu.",
            ephemeral=True
        )
        return False
    return True

Performance Considerations

View Lifecycle Management

  • Timeout handling prevents orphaned views
  • Resource cleanup in view destructors
  • Interaction tracking for usage analytics
  • Memory management for large datasets

Efficient Updates

# ✅ Efficient - Only update what changed
await interaction.response.edit_message(embed=new_embed, view=self)

# ❌ Inefficient - Sends new message
await interaction.response.send_message(embed=new_embed, view=new_view)

Testing Strategies

View Testing

@pytest.mark.asyncio
async def test_confirmation_view():
    view = ConfirmationView(user_id=123)

    # Mock interaction
    interaction = Mock()
    interaction.user.id = 123

    # Test button click
    await view.confirm_button.callback(interaction)

    assert view.result is True

Modal Testing

@pytest.mark.asyncio
async def test_custom_command_modal():
    modal = CustomCommandModal()

    # Set form values
    modal.name.value = "test"
    modal.response.value = "Test response"

    # Mock interaction
    interaction = Mock()

    # Test form submission
    await modal.on_submit(interaction)

    # Verify processing
    assert modal.result is not None

Development Guidelines

Creating New Views

  1. Inherit from base classes for consistency
  2. Use EmbedTemplate for all embed creation
  3. Implement proper error handling in all interactions
  4. Add user permission checks where appropriate
  5. Include comprehensive logging with context
  6. Follow timeout patterns to prevent resource leaks

View Composition

  • Keep views focused on single responsibilities
  • Use composition over complex inheritance
  • Separate business logic from UI logic
  • Make views testable with dependency injection

UI Guidelines

  • Follow Discord design patterns for familiarity
  • Use consistent colors from EmbedColors
  • Provide clear user feedback for all actions
  • Handle edge cases gracefully
  • Consider mobile users in layout design

Next Steps for AI Agents:

  1. Review existing view implementations for patterns
  2. Understand the Discord UI component system
  3. Follow the EmbedTemplate system for consistent styling
  4. Implement proper error handling and user validation
  5. Test interactive components thoroughly
  6. Consider accessibility and user experience in design