Replace @media (prefers-color-scheme: dark) with :host-context(.isDarkTheme)
so heatmap labels adapt to app-level theme switching, not just OS preference.
- Use var(--text-color-muted) for label text colors (auto-adapts to theme)
- Use CSS variables for backgrounds, scrollbars, and outlines
- Remove hardcoded rgba() colors in favor of theme-aware variables
Fixes#5883
When using Pomodoro with "Manually start breaks" and "Start focus sessions
with banner only", pressing the play button after session completion now
correctly starts a break instead of a new session.
Fixes#5889
The fill() method on time combobox wasn't triggering proper change events.
Use clear() + pressSequentially() + Tab to properly commit the time change
before clicking Save.
The debounceTime(1000) added in 871ee354c delayed ALL emissions by 1 second,
including the initial value. When sync.effects.ts used withLatestFrom(isOnline$)
and the app initialized faster than 1 second, the observable chain hung forever
because withLatestFrom requires the other observable to have already emitted.
Add startWith(navigator.onLine) after debounceTime to provide an immediate
initial value while still debouncing subsequent online/offline events.
Fixes#5868, #5877
Add Docker setup for running E2E tests with the Angular dev server
containerized while Playwright runs on the host. Supports multiple
instances via configurable ports.
New files:
- Dockerfile.e2e.dev: Dev server image
- docker-compose.e2e.yaml: E2E orchestration config
- scripts/wait-for-app.sh: Health check script
New npm scripts:
- e2e:docker: Run E2E with containerized app
- e2e:docker:webdav: Same but includes WebDAV for sync tests
Usage: APP_PORT=4343 npm run e2e:docker
When a user clicked on a task in the Schedule view and pressed Y to start
time tracking, a different task was being tracked instead. This happened
because Schedule view only sets selectedTaskId (for the detail panel) but
not focusedTaskId (used by keyboard shortcuts).
The fix modifies TaskShortcutService to use selectedTaskId as a fallback
when focusedTaskId is null, specifically for the togglePlay (Y) shortcut.
Priority order:
1. If focusedTaskId exists → delegate to TaskComponent (existing behavior)
2. If no focusedTaskId but selectedTaskId exists → toggle tracking for selected task
3. If neither exists → use global toggle behavior
Fixes#5884
When a task was scheduled for today with a time-based reminder, clicking
the "today" quick access button in the context menu was creating a new
reminder instead of clearing it. This was because the _schedule method
detected dueWithTime and called scheduleTask() which creates a reminder.
Now the method first checks if the task is already scheduled for today
with time and we're planning for today - in that case, it calls
addToMyDay() which properly clears the reminder via planTasksForToday.
Fixes#5872
The tests assumed 12-hour AM/PM format, but the app defaults to en_gb
locale which uses 24-hour format. Changed to increment hour instead
of flipping AM/PM, which works with both formats.
The icalEvents$ observable now refreshes periodically using a timer-based
approach. This ensures calendar events update in planner and scheduler
views without requiring an app restart.
Key changes:
- Add LOCAL_FILE_CHECK_INTERVAL (5 min) for file:// URLs
- Add getEffectiveCheckInterval() to determine poll interval per provider
- Refactor icalEvents$ to use timer(0, minInterval) for periodic refresh
- Move shareReplay to outer observable to prevent memory leaks
- Add comprehensive test coverage (84 tests)
Fixes#4474
When sync is enabled and the device is offline, show the skip sync
button immediately (~1 second) instead of waiting 3 seconds. This
improves startup UX when network is unavailable.
Fixes#5877
Fixes race condition where loadAll() could access the database before
initialization completes, causing "database connection is closing" errors.
Fixes#5734
Use default alarm ringtone with USAGE_ALARM audio attributes so
reminders play even when phone is on silent. Add vibration pattern
and change notification category from REMINDER to ALARM.
Fixes#5603
Adds a "Skip waiting for sync" button that appears after 3 seconds on
the loading screen. This allows users to proceed with local data while
sync continues in the background.
Fixes#5868
Remove the `!action.isManual` check from shouldAutoStartBreak condition,
so manually ending a Pomodoro session now triggers a break (or shows
"Start Break" button if isManualBreakStart is enabled).
Fixes#5876
- Skip break when user starts time tracking during break (syncs state)
- Stop time tracking when session is manually ended via "End Session"
Fixes#5875
- Add all page objects to fixtures (plannerPage, syncPage, tagPage, notePage, sideNavPage)
- Create assertion helpers (expectTaskCount, expectTaskVisible, etc.)
- Enhance CLAUDE.md with patterns, import paths, and all fixtures
- Add const assertion to selectors for better TypeScript support
Remove tests that were skipped with no clear path to fix:
- project-note.spec.ts: Both tests broken (createAndGoToTestProject fails)
- planner-navigation: Remove broken project planner test
- project.spec.ts: Remove broken create second project test
Remaining skips are intentional:
- perf2.spec.ts: Slow performance test
- work-view.spec.ts: Documents known persistence bug
- Fix plugin toggle flakiness by using helper functions with proper
state verification (enablePluginWithVerification, disablePluginWithVerification)
- Fix WebDAV sync tests by handling loading screen in waitForAppReady
and waitForTaskList (app shows loading while syncing/importing)
- Remove unreliable/empty test files: webdav-sync-recurring,
webdav-sync-reminders, webdav-sync-time-tracking
- Remove networkidle waits from work-view.page.ts, project.page.ts
- Remove unnecessary waitForTimeout calls in work-view.page.ts
- Remove add-task input wait from test fixture
These waits were either redundant (Angular stability checks already
handle them) or ineffective (networkidle doesn't work well with
Angular apps). Expected improvement: 20-40% faster test runs.
- Add e2e/CLAUDE.md with concise reference for writing E2E tests
- Test commands, template, fixtures, key methods, selectors
- Focused on what Claude Code needs to write tests quickly
- Add e2e/pages/index.ts barrel export for all page objects
- Remove Angular testability API checks from waitForAngularStability
Experiment showed Playwright's auto-waiting is sufficient for most tests
- Fix time-tracking-feature test: add missing await, replace hardcoded
waitForTimeout with proper toHaveClass assertions
- Refactor plugin-simple-enable test to use SettingsPage methods
instead of brittle page.evaluate() DOM manipulation (106 -> 33 lines)
- Change trace config to 'retain-on-failure' for better debugging
Add comprehensive improvements to make e2e test development faster and easier:
1. **New Page Objects** - Reduce code duplication and improve maintainability:
- task.page.ts: Task operations (get, mark done, edit, subtasks, etc.)
- settings.page.ts: Settings navigation and plugin management
- dialog.page.ts: Dialog interactions (save, close, date editing, etc.)
- All page objects integrated into test.fixture.ts for easy access
2. **Centralized Selectors** - Single source of truth:
- Expanded constants/selectors.ts with 50+ selectors
- Organized by category (Navigation, Tasks, Dialogs, Settings, etc.)
- Makes selector updates easier when UI changes
3. **Comprehensive Documentation** - Complete e2e/README.md guide:
- Page object usage examples
- Common test patterns
- Best practices and anti-patterns
- Troubleshooting guide
- Step-by-step instructions for writing new tests
These improvements provide a better foundation for AI-assisted test development
and make it faster to add new e2e tests.
Optimized e2e test utilities to significantly reduce execution time:
**waitForAngularStability():**
- Reduced default timeout from 5s to 3s
- Removed redundant ng.getComponent checks
- Removed non-fatal catch that swallowed errors
- Simplified fallback to only check route-wrapper presence
**waitForAppReady():**
- Removed slow networkidle wait (saves ~2-5s per call)
- Removed redundant checks (body, magic-side-nav)
- Removed 200ms fixed buffer at the end
- Reduced timeouts across the board
- Streamlined to essential waits only
**waitForStatePersistence():**
- Removed networkidle wait (replaced with 100ms buffer)
- Now relies on Angular stability for state persistence
**BasePage.addTask():**
- Removed 3-attempt retry loop with 500ms delays
- Removed all fixed timeouts (50ms, 100ms, 300ms, 500ms, 1000ms)
- Simplified input filling - rely on Playwright's auto-waiting
- Removed redundant initial stability checks
- Removed Promise.race with multiple strategies
- Removed unused waitForAngularStability import
- Reduced from ~170 lines to ~70 lines
These changes speed up e2e tests by removing ~1-3 seconds per test
from unnecessary waits while maintaining reliability through Playwright's
built-in auto-waiting and retry mechanisms.
- Add waitForAppReady and tour dismissal after page reload in
webdav-sync-tags test to prevent task-list timeout
- Use existing providerSelect locator instead of role-based combobox
selector in sync.page.ts for more reliable dropdown interaction
- Add graceful error handling for scrollIntoViewIfNeeded with fallback
- fix(focus-mode): prevent double startFocusSession dispatch in Pomodoro
when clicking Start after break time is up (check shouldAutoStartNextSession)
- fix(task-repeat): gracefully fall back to CUSTOM quickSetting when
startDate is missing instead of throwing error
- fix(work-context): also validate TAG context after sync, not just PROJECT
- fix(android): add error handling for cancelNativeReminder calls
- fix(android): add error handling for immediate save operations
- fix(reminder): use type guard in Promise.all filter for better type safety
- docs(audio): add comment explaining fire-and-forget pattern for resume()
* origin/master:
use Log.warn instead of console.warn added more warning output if board reference is not found
adjusted css so that right click on the whole tab label works to open the context menu removed import of no longer required ContextMenuComponent
chore(deps): bump actions/upload-artifact from 5 to 6
chore(deps): bump actions/cache from 4 to 5
chore(deps-dev): bump @typescript-eslint/utils from 8.41.0 to 8.51.0
Disable play button and show tooltip when no tasks available
use translations for board actions
updated boards context menu to include delete and edit actions
- fix(android): await async _syncElapsedTimeForTask in notification handlers
to ensure time is synced before saving/pausing
- fix(notes): prevent duplicate emit in fullscreen markdown editor by
tracking last emitted content
Repeat configs with date-dependent quickSettings (WEEKLY_CURRENT_WEEKDAY,
YEARLY_CURRENT_DATE, MONTHLY_CURRENT_DATE) require a startDate to derive
the correct weekday/date. This repair changes invalid configs to CUSTOM
to prevent crashes.
Fixes#5802
When returning to the app after tracking time in the background, the app
would show less time than the notification because the sync from the
native Android foreground service was unreliable.
Root causes:
1. The _syncElapsedTimeForTask method used .subscribe().unsubscribe()
anti-pattern which could fail to execute the callback
2. No protection against double-counting when both native sync and
the app's tick$ added time for the same period
This fix:
- Refactors _syncElapsedTimeForTask to use async/await with firstValueFrom()
- Adds resetTrackingStart() to prevent double-counting after native sync
- Adds immediate save to IndexedDB when notification buttons are clicked
- Adds comprehensive unit tests for sync logic (10 new tests)
Fixes#5840
Related to #5842
Show only one error alert when IndexedDB fails (e.g., disk full) instead
of spamming the user with dozens of confirm dialogs. The app now blocks
completely and restarts after the user dismisses the alert, preventing
potential data loss from retry attempts.
Fixes#5845
Fix race condition where dismissed reminders could reappear every few
seconds. The issue occurred because the worker's 10-second interval
could fire before the async DB save completed, sending stale reminder
data back to the dialog.
Two-part fix:
1. Update worker immediately when reminders change (before DB save)
2. Track dismissed reminder IDs in dialog and filter them from incoming
worker data
Fixes#5826
Add isLoading signal to disable Save button while async data loads.
This prevents the "Initial task repeat cfg missing" error when users
click Save before the repeat config finishes loading.
Fixes#5828