- Fix toggle_mode to pass envelope context when reloading (preserves compression)
- Add CSS for header labels: single-line with text-overflow ellipsis
- Add 'full-headers' CSS class for toggling between compressed/full view
- Store full subject in header for proper refresh on toggle
- Update HelpScreen with missing shortcuts (o, b) and better descriptions
- Fix duplicate line in _refresh_display
- Add InviteCompressor for terminal-friendly calendar invite summaries
- Add test fixtures for large group invite and cancellation emails
- Compress To/CC headers to single line with '... (+N more)' truncation
- Add 'h' keybinding to toggle between compressed and full headers
- EnvelopeHeader now shows first 2 recipients by default
- Create CalendarInvitePanel widget showing event summary, time, location,
organizer, and attendees with accept/decline/tentative buttons
- Add is_calendar_email() to notification_detector for detecting invite emails
- Add get_raw_message() to himalaya client for exporting full MIME content
- Refactor calendar_parser.py with proper icalendar parsing (METHOD at
VCALENDAR level, not VEVENT)
- Integrate calendar panel into ContentContainer.display_content flow
- Update tests for new calendar parsing API
- Minor: fix today's header style in calendar WeekGrid
- Create calendar_parser.py module with ICS parsing support
- Add test_calendar_parsing.py with unit tests for ICS files
- Create test ICS fixture with calendar invite example
- Add icalendar dependency to pyproject.toml
- Add calendar detection to notification_detector.py
- Research and document best practices for ICS parsing libraries
- 4-week implementation roadmap:
- Week 1: Foundation (detection, parsing, basic display)
- Week 2: Mail App Integration (viewer, actions)
- Week 3: Advanced Features (Graph API sync)
- Week 4: Calendar Sync Integration (two-way sync)
Key capabilities:
- Parse ICS calendar files (text/calendar content type)
- Extract event details (summary, attendees, method, status)
- Detect cancellation vs invite vs update vs request
- Display calendar events in TUI with beautiful formatting
- Accept/Decline/Tentative/Remove actions
- Integration path with Microsoft Graph API (future)
Testing:
- Unit tests for parsing cancellations and invites
- Test fixture with real Outlook calendar example
- All tests passing
This addresses your need for handling calendar invites like:
"CANCELED: Technical Refinement"
with proper detection, parsing, and display capabilities.
- Research best ICS parsing libraries (icalendar, ics)
- Design CalendarEventViewer widget for displaying invites
- Add calendar detection to notification_detector.py
- Implement ICS parsing utilities in calendar_parser.py
- Plan integration with Microsoft Graph API for calendar actions
- Provide clear action flow (Accept/Decline/Tentative/Remove)
- 4-week implementation roadmap with success metrics
- Configuration options for parser library and display settings
Key features:
- Automatic calendar email detection (invites, cancellations, updates)
- ICS file parsing with proper timezone and attendee handling
- Beautiful TUI display of calendar events
- Integration path with Microsoft Graph API (future)
- Action buttons tied to Graph API for updating Outlook calendar
- Add unique IDs to all Static widgets (spacer_1, spacer_2, spacer_3)
- Fix MountError: 'Tried to insert 3 widgets with same ID'
- Help screen now displays correctly when pressing '?'
- Create HelpScreen with all keyboard shortcuts
- Add hardcoded sections for instructions
- Add binding for '?' key to show help
- Support ESC/q/? to close help screen
- Document notification compression feature in help
- Format help with colors and sections (Navigation, Actions, View, Search)
Features:
- Shows all keyboard shortcuts in organized sections
- Quick Actions section explains notification compression
- Configuration instructions for mail.toml
- Modal dialog with close button
- Extracts bindings automatically for display
- The 'm' key was repurposed for toggle view mode, causing conflict
- Removed Binding from ContentContainer to free up the key for other uses
- action_toggle_mode still exists for extensibility but has no keybinding
- Tests still passing
- Fix envelopes list access: use index with bounds checking instead of .get()
- Add missing 'Any' type import to ContentContainer
- App now starts successfully without NameError or AttributeError
- Update type annotations to modern syntax (dict, list, X | Y)
- Remove unnecessary elif after return
- Minor style improvements
Note: Some linting warnings remain (unused content param, inline conditions)
but these are minor style issues and do not affect functionality.
All tests pass with these changes.
- Add domain-specific matching for Atlassian services
- Fix Confluence being misclassified as Jira
- Add comprehensive test coverage for notification detection
- Add example configuration file with new options
- All 13 tests now passing
Files modified:
- src/mail/notification_detector.py: Better atlassian.net handling
- tests/test_notification_detector.py: Full test suite
- mail.toml.example: Config documentation with examples
- Add calendar_invite.py with detect/find/respond functions for calendar invites
- Keybindings: A (accept), D (decline), T (tentative)
- Searches Graph API calendarView to find matching event by subject
- Responds via Graph API POST to event/{id}/accept|decline|tentativelyAccept
- Add DatePickerModal using MonthCalendar widget from calendar app
- Detect when user types 'date ', 'before ', or 'after ' and show picker
- Insert selected date (YYYY-MM-DD format) into search input
- Support keyboard navigation (left/right for months, Enter to select)
- Today button for quick selection of current date
- Add SuggestFromList with Himalaya keywords for search input autocomplete
- Cache and restore metadata_by_id when cancelling search (fixes navigation)
- Set search_mode=True when opening panel for consistent Escape behavior
- Fix SearchPanel CSS vertical alignment with explicit heights
- Add bounds check in _mark_message_as_read to prevent IndexError
- Clear metadata_by_id when search returns no results
- Escape now focuses search input when in search mode instead of exiting
- Add focus_input() method to SearchPanel