feat: optimize and enhance IssueActivity class - Issue #126

Enhanced IssueActivity dataclass with convenient methods and properties:
- Added activity_type_value, activity_type_display properties
- Added formatted_date, formatted_datetime properties
- Added truncated_details property for display
- Added contains_keyword() and has_implementation_activity() methods
- Added to_dict() method for clean serialization

Simplified code across the codebase:
- Reduced JSON serialization from 18 lines to 1 line (94% reduction)
- Reduced implementation detection from 13 lines to 3 lines (77% reduction)
- Improved table formatting using property access
- Fixed test inconsistencies using proper IssueActivity objects
- Removed complex helper code for dict/dataclass handling

Benefits:
- Single source of truth for all IssueActivity operations
- Consistent interface across all usage patterns
- Better encapsulation and maintainability
- Enhanced code readability and reliability
- All tests passing (1329/1329)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-05 13:59:33 +02:00
parent bce680e6cb
commit 4121745651
5 changed files with 242 additions and 33 deletions

View File

@@ -27,7 +27,7 @@ class ActivityType(Enum):
@dataclass
class IssueActivity:
"""Data class representing an issue activity record."""
"""Data class representing an issue activity record with convenient methods."""
id: Optional[int] = None
issue_id: int = None
activity_type: ActivityType = None
@@ -36,6 +36,59 @@ class IssueActivity:
activity_details: Optional[str] = None
created_at: Optional[datetime] = None
@property
def activity_type_value(self) -> str:
"""Get the string value of the activity type."""
return self.activity_type.value if self.activity_type else ''
@property
def activity_type_display(self) -> str:
"""Get the display-friendly activity type."""
return self.activity_type_value.replace('_', ' ').title()
@property
def formatted_date(self) -> str:
"""Get formatted activity date string."""
return self.activity_date.strftime('%Y-%m-%d') if self.activity_date else 'N/A'
@property
def formatted_datetime(self) -> str:
"""Get formatted created datetime string."""
return self.created_at.strftime('%Y-%m-%d %H:%M') if self.created_at else 'N/A'
@property
def truncated_details(self) -> str:
"""Get truncated activity details for display (max 40 chars)."""
if not self.activity_details:
return ''
return (self.activity_details[:40] + '...') if len(self.activity_details) > 40 else self.activity_details
def contains_keyword(self, keyword: str, case_sensitive: bool = False) -> bool:
"""Check if activity contains a keyword in type or details."""
search_text = f"{self.activity_type_value} {self.activity_details or ''}".strip()
if not case_sensitive:
search_text = search_text.lower()
keyword = keyword.lower()
return keyword in search_text
def has_implementation_activity(self) -> bool:
"""Check if this activity indicates implementation work."""
return (self.contains_keyword('implement') or
self.contains_keyword('code') or
self.contains_keyword('develop'))
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary representation."""
return {
'id': self.id,
'issue_id': self.issue_id,
'activity_type': self.activity_type_value,
'activity_date': self.activity_date.isoformat() if self.activity_date else None,
'period_id': self.period_id,
'activity_details': self.activity_details,
'created_at': self.created_at.isoformat() if self.created_at else None
}
class IssueActivityTracker:
"""