Users can now add URL attachments when creating tasks using short syntax.
URLs are automatically detected and extracted as attachments, with the URL
removed from the task title.
Supported URL types:
- https:// and http:// URLs → LINK type
- file:// URLs → FILE type for local documents
- www. URLs → LINK type (auto-adds // protocol)
- Image URLs (.png, .jpg, .gif, .jpeg) → IMG type
Example usage:
"Review PR https://github.com/org/repo/pull/123 @tomorrow #urgent t30m"
Creates task with title "Review PR", URL attachment, date, tag, and estimate
Features:
- Configurable via isEnableUrl setting (defaults to true)
- Works alongside existing short syntax (@date, #tag, +project, t30m)
- Handles multiple URLs in one task
- Properly syncs via operation log
Tests added:
- 14 unit tests for URL parsing logic
- 11 integration tests for parser service
- 10 integration tests for state service
- All 232 tests passing
Closes#6067
- Fix issue where overdue reminders were invisible on Android
- Worker correctly detected overdue reminders but dialog was skipped
- Native AlarmManager only schedules future reminders, not overdue ones
- Now checks if reminders are overdue and shows dialog appropriately
- Future reminders: skip dialog (native notification handles them)
- Overdue reminders: show dialog (no native notification exists)
- Add comprehensive diagnostic logging to reminder scheduling/cancellation
- Add logging to track reminder dialog trigger decisions
This fixes the issue where changing any task's reminder time would
appear to trigger all overdue reminders - they were always there but
hidden due to the dialog being skipped on Android.
Ensures translations are loaded before the migration dialog appears,
preventing untranslated keys (e.g., "MIGRATE.DIALOG_TITLE") from being
displayed to users. Detects browser language and preloads the
appropriate translation file synchronously.
Adds explicit waits after archive operations to ensure IndexedDB writes
complete before proceeding with sync operations. This prevents race
conditions where sync attempts to read state before archive persistence
finishes.
Changes:
- Add waitForArchivePersistence() helper to sync-helpers.ts
- Waits 1000ms for IndexedDB operations to complete
- Additional 100ms for pending micro-tasks/animations
- Add 500ms waits in waitForSyncComplete() after detecting sync success
- Ensures IndexedDB writes fully settle before returning
- Apply waitForArchivePersistence() in webdav-sync-archive.spec.ts
- After Client A archives Task1
- After Client B archives Task3
- Apply waitForArchivePersistence() in webdav-sync-delete-cascade.spec.ts
- After Client A archives task (tag deletion test)
- After Client B archives Task1 (concurrent archive test)
These changes address flakiness in CI environments where async IndexedDB
operations may not complete before the next test assertion.
Related to: Bug #5995, Bug #6044 (focus-mode test fixes)
Bug #5995 test was failing due to improper setup - not using page objects
and waiting for app readiness. Bug #6044 tests had incorrect expectations
about when long breaks occur in the Pomodoro cycle.
Root Cause Analysis:
- Bug #5995: Test navigated manually without using workViewPage fixture
- Bug #6044: Tests expected long breaks after sessions 4 & 8, but the
correct logic is after sessions 3 & 7 (when cycle becomes 4 & 8)
Pomodoro Cycle Logic:
- Initial state: cycle = 1
- After session 1: cycle = 2 → short break
- After session 2: cycle = 3 → short break
- After session 3: cycle = 4 → LONG break (4 % 4 === 0)
- After session 4: cycle = 5 → short break
- Pattern: S S L S S S L S (not S S S L S S S L)
Changes:
- bug-5995: Use workViewPage fixture and proper navigation
- bug-6044: Fix all 4 tests to expect long breaks at correct sessions
- bug-6044: Fix completeSession helper to wait for break screen
- bug-6044: Update test descriptions and patterns to match reality
Test Results:
- All 5 focus-mode e2e tests now passing
- No code changes needed - underlying bug fixes were correct
- Add GlobalTrackingIntervalService and TakeABreakService providers to FocusMode test suites
- Add selectIsResumingBreak selector overrides to bug #5875 tests
- Update BackupService test expectations for dual-archive architecture (no merge)
- All 6,412 unit tests now passing
When focus sync is enabled, the "without break" timer incorrectly
accumulated time during Pomodoro breaks, treating them as work time.
This caused false break reminders after completing two 25/5 sessions.
The issue occurred because the break timer only reset when no task
was being tracked. With isPauseTrackingDuringBreak=false (default),
tasks remain active during breaks, preventing the timer from resetting.
Solution: Add explicit break timer reset when startBreak action is
dispatched. This ensures Pomodoro breaks are recognized as rest periods
regardless of task tracking state.
Also updates bug-5995 tests to mock TakeABreakService dependency.
Add unit tests for Bug #2 fix from issue #5995:
- Test pauseBreak() uses currentTaskId when tracking is active
- Test fallback to stored pausedTaskId when tracking is stopped
- Ensures overlay pause correctly stops tracking during breaks
Related to fixes in a0719c15c and 92fdcc6a1
Move selectIsResumingBreak from outer combineLatest to inner
withLatestFrom to ensure we check the current flag value at
execution time, not a stale value from the outer closure.
Replace time-based flag with store-based _isResumingBreak flag to
reliably distinguish break resume from manual tracking start.
This eliminates race conditions that caused breaks to be skipped.
The dataRepair function was merging archiveOld into archiveYoung,
contradicting the dual-archive architecture where both archives
should remain separate for proper age-based archiving.
Changes:
- Removed archive merging logic from dataRepair (lines 80-97)
- Updated 11 repair functions to handle both archiveYoung and archiveOld:
* _fixEntityStates
* _removeNonExistentTagsFromTasks
* _removeNonExistentProjectIdsFromTasks
* _addInboxProjectIdIfNecessary
* _removeDuplicatesFromArchive
* _removeMissingTasksFromListsOrRestoreFromArchive
* _moveArchivedSubTasksToUnarchivedParents
* _moveUnArchivedSubTasksToArchivedParents
* _removeNonExistentRepeatCfgIdsFromTasks
* _cleanupOrphanedSubTasks
* _setTaskProjectIdAccordingToParent
- Added debug logging to BackupService for validation failures
Tests:
- All 40 data-repair unit tests pass
- All 189 archive-related unit/integration tests pass
- All 6 archive import/export E2E tests pass
Fixes E2E test: "should persist both archive types after import"
When splitting one operation into misc and tasks operations:
- Both operations now get unique ID suffixes (_misc and _tasks)
- Skip logic verifies both conditions before skipping:
1. tasks config has migrated field (isConfirmBeforeDelete)
2. misc config has NO migrated fields remaining
This prevents:
- Potential operation ID conflicts in the sync log
- Data loss in partial migration scenarios
Adds test cases for partial migration and correct skip scenarios.
Fixes inconsistency introduced in bug #6044 fix where auto-start breaks use
cycle directly but manual-start breaks still used cycle-1 adjustment.
After session 4, both auto and manual breaks now correctly trigger long break.
- Remove obsolete cycle-1 adjustment from _handleStartAfterSessionComplete
- Update test to expect cycle=4 instead of cycle=5 for long break
- Update comment to reference bug #6044 fix
- Fix TypeScript type errors in test file (as any assertions)
Adds explicit validation for the {day, duration} payload structure used by
logFocusSession action. This prevents the false positive warning about
"unusual structure" while maintaining correct validation for all other
METRIC operations. The specialized payload format is intentional for
append-only focus session logging.
Tags in the selection menu (shown when adding/editing tasks) now
respect the custom order defined in the left panel navigation instead
of being sorted alphabetically.
The component now uses MenuTreeService.buildTagViewTree() to maintain
user-defined ordering, including tags within folders. This provides
consistent UX between the navigation panel and tag selection dialogs.
Fixes#6046
Relates to #6044
Added comprehensive E2E tests to verify the correct Pomodoro break pattern:
- Sessions 1-3 should trigger short breaks
- Session 4 should trigger a LONG break (critical test for bug #6044)
- Session 5 should trigger a short break (not long)
- Session 8 should trigger a LONG break (second cycle)
**Test Coverage:**
- Individual test for long break after 4th session
- Individual test for short break after 5th session
- Individual test for long break after 8th session
- Full pattern verification: S S S L S S S L
**Test Structure:**
The tests follow the existing E2E test patterns and include:
- Helper functions for common operations (openFocusModeWithTask, startFocusSession, etc.)
- Break type detection to verify short vs long breaks
- Screenshot capture for visual verification
- Console logging for debugging and verification
**Additional Changes:**
- Added screenshots/ directory for test artifacts
- Updated e2e/.gitignore to exclude generated screenshots
These E2E tests complement the 131 passing unit tests to ensure the bug fix works correctly in the actual application.
The tray icon was jumping between showing task time and focus session time
when focus mode was active with a task being tracked. This occurred because
the tray display logic didn't know which focus mode was active.
Changes:
- Send focus mode type (Countdown/Pomodoro/Flowtime) from frontend to Electron
- Update IPC handler to receive and pass focus mode type to tray message creation
- Implement three-mode priority logic in createIndicatorMessage():
1. Countdown/Pomodoro modes: Show focus session countdown timer
2. Flowtime mode: Show task estimate or title (no timer)
3. No focus mode: Show normal task time (existing behavior)
- Update TypeScript type definitions for updateCurrentTask()
- Update unit tests to mock the new mode() signal
This ensures the tray displays the correct timer without jumping based on
the active focus mode, matching the behavior of the overlay indicator.
Fixes jumping tray indicator during focus mode + tracking
Converts setTaskBarProgress$ effect from selector-based to action-based
with 500ms throttling to prevent excessive IPC calls. The selector-based
effect was firing on every timer tick (1s), causing the Windows taskbar
progress bar to fill completely every second instead of gradually over
the session duration.
Fixes#6061
Fixes#6042 where app wouldn't launch from taskbar when minimize to tray
was enabled. The second-instance handler now uses showOrFocus() which
properly handles both hidden and minimized windows, matching the behavior
of the tray icon click handler.
Adds a secondary "End Focus Session" button to the focus banner when a session completes, allowing users to completely exit focus mode and dismiss the banner instead of only being able to start a break or next session.
Change trigger from pull_request to pull_request_target to allow the
workflow to run with write permissions even for external contributors.
This fixes the "Actor has insufficient permissions" error.
Also add condition to skip draft PRs to reduce API usage.