Commit graph

16620 commits

Author SHA1 Message Date
Johannes Millan
acedc67f2a fix(schedule): start tracking selected task when pressing Y in schedule view
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
2026-01-04 17:07:29 +01:00
Johannes Millan
2af57d2b4a fix(tasks): clear reminder when clicking "today" button on already-today tasks
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
2026-01-04 16:59:26 +01:00
Johannes Millan
098e19f9ca fix(e2e): use format-agnostic time change in task-detail tests
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.
2026-01-04 16:20:18 +01:00
Johannes Millan
70f1e4ba73 16.8.2 2026-01-04 14:57:50 +01:00
Johannes Millan
d4b40e80d5 fix(test): reset selector overrides to prevent test pollution
Add store.resetSelectors() in afterEach to prevent MockStore selector
overrides from persisting and affecting other test files.
2026-01-04 14:56:08 +01:00
Johannes Millan
d8a6a7dc62 build: update CLAUDE.md 2026-01-04 14:52:35 +01:00
Johannes Millan
77c4c33988 fix(calendar): add periodic refresh for planner and scheduler views
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
2026-01-04 14:14:25 +01:00
Johannes Millan
386c636e5f feat(effects): consolidate task update actions in PluginHooksEffects 2026-01-04 13:03:28 +01:00
Johannes Millan
ccd4846b88 fix(sync): show skip button immediately when offline
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
2026-01-04 12:54:21 +01:00
Johannes Millan
270eca3600 fix(db): add missing _afterReady guard to loadAll method
Fixes race condition where loadAll() could access the database before
initialization completes, causing "database connection is closing" errors.

Fixes #5734
2026-01-04 12:45:54 +01:00
Johannes Millan
b7cbef2f79 feat(android): add alarm sound and vibration to task reminders
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
2026-01-04 12:45:00 +01:00
Johannes Millan
12e68cdb0e feat(sync): add skip button to loading screen when waiting for sync
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
2026-01-04 12:36:00 +01:00
Johannes Millan
291d3e8caf fix(pomodoro): allow manual session end to start break early
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
2026-01-04 12:12:49 +01:00
Johannes Millan
abfff278a4 fix(i18n): add missing translate pipe to play button tooltip
Fixes #5874
2026-01-04 12:07:14 +01:00
Johannes Millan
4497aed317 fix(tasks): handle undefined tasks in reminder effect
Add optional chaining to prevent TypeError when planTasksForToday
is triggered with task IDs that no longer exist in the store.

Fixes #5873
2026-01-04 12:06:33 +01:00
Johannes Millan
55fc8551cd fix(focus-mode): sync time tracking with Pomodoro breaks and manual end
- Skip break when user starts time tracking during break (syncs state)
- Stop time tracking when session is manually ended via "End Session"

Fixes #5875
2026-01-04 12:05:34 +01:00
Johannes Millan
eca5fc930f refactor(e2e): improve test infrastructure for easier expansion
- 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
2026-01-03 18:39:40 +01:00
Johannes Millan
9faf80c53e chore(e2e): remove broken/empty skipped tests
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
2026-01-03 17:49:43 +01:00
Johannes Millan
8d9ceb5776 test(e2e): fix flaky plugin and WebDAV sync tests
- 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
2026-01-03 17:35:09 +01:00
Johannes Millan
11d85208e5 refactor(e2e): replace waitForTimeout with condition-based waits
- Replace ~100 waitForTimeout calls with proper condition-based waits
- Extract shared utilities for time input and task scheduling
- Add timeout constants for consistent wait times
- Add new selectors for reminder dialogs and detail panels

Files refactored across 25+ test files including:
- Plugin tests (lifecycle, upload, loading, enable, structure)
- Reminder tests (view-task, schedule-page, default-options)
- Work view, planner, focus mode, and app feature tests
- Task dragdrop, autocomplete, and daily summary tests

New utilities created:
- e2e/utils/time-input-helper.ts - Robust time input filling
- e2e/utils/schedule-task-helper.ts - Task scheduling helpers
- e2e/constants/timeouts.ts - Standardized timeout values
2026-01-03 15:29:38 +01:00
Johannes Millan
24c008df92 perf(e2e): remove ineffective waits to speed up test runs
- 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.
2026-01-03 13:42:22 +01:00
Johannes Millan
36a94ef1ac docs(e2e): add CLAUDE.md reference and barrel export for easier test creation
- 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
2026-01-03 13:27:24 +01:00
Johannes Millan
9c84de94ee build: update dep 2026-01-03 12:57:47 +01:00
Johannes Millan
e3f9daf9fa refactor(e2e): simplify waits and fix flaky tests
- 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
2026-01-03 12:57:16 +01:00
Johannes Millan
402fb69a85 feat(e2e): streamline e2e test development with improved infrastructure
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.
2026-01-03 11:21:40 +01:00
Johannes Millan
c0fc56f729 perf(e2e): optimize wait utilities and addTask method for faster test execution
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.
2026-01-03 11:11:01 +01:00
Johannes Millan
ac31531ca6 16.8.1 2026-01-02 20:12:41 +01:00
Johannes Millan
e6b6468d2a fix(e2e): improve WebDAV sync test reliability
- 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
2026-01-02 19:59:59 +01:00
Johannes Millan
092d32a39e 16.8.0 2026-01-02 19:26:41 +01:00
Johannes Millan
ca22c0d8f6 feat(i18n): add new translations 2026-01-02 19:26:18 +01:00
Johannes Millan
795ec42f64 fix: address code review issues from today's changes
- 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()
2026-01-02 18:34:29 +01:00
Johannes Millan
5007d6178f Merge remote-tracking branch 'origin/master'
* 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
2026-01-02 18:21:19 +01:00
Johannes Millan
6d57aaff13 fix: address code review issues from today's changes
- 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
2026-01-02 18:16:33 +01:00
Johannes Millan
cb27b53f85 fix(data-repair): change quickSetting to CUSTOM when startDate is missing
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
2026-01-02 18:16:20 +01:00
Johannes Millan
1ba7cf8960 fix(test): fix fetch spy setup in audio tests
Use jasmine.createSpy and direct assignment instead of spyOn for
window.fetch, which may not exist or may already be spied in the
test environment.
2026-01-02 17:56:51 +01:00
Johannes Millan
55d4fd1520 fix(android): sync time tracking from notification correctly on resume
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
2026-01-02 17:56:40 +01:00
Johannes Millan
9f6442bf6b fix(database): prevent repeated error dialogs when disk is full
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
2026-01-02 17:37:50 +01:00
Johannes Millan
9c3834b7ee fix(reminder): prevent dismissed reminders from reappearing
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
2026-01-02 17:13:28 +01:00
Johannes Millan
dc12403747 fix(task-repeat): prevent race condition when saving repeat config
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
2026-01-02 17:12:21 +01:00
Johannes Millan
a14c95093d fix(android): add error handling for native service calls
Wrap all androidInterface native method calls in try-catch blocks to
prevent app crashes when Java exceptions are raised during method
invocation. Users are now notified via snackbar when service start
fails, while update/stop failures are logged silently.

Changes:
- Add _safeNativeCall helper to TypeScript effects for DRY error handling
- Add safeCall inline helper to Kotlin JavaScriptInterface
- Wrap focus mode and tracking service calls with error handling
- Show user-friendly error notification on service start failures
- Add unit tests for error handling logic

Fixes #5819
2026-01-02 17:09:08 +01:00
Johannes Millan
93e957edc1 fix(reminder): cancel native Android reminders immediately on task deletion
On Android, native reminders scheduled via AlarmManager were not being
canceled reliably when tasks were deleted. This happened because the
reactive cancellation via reminders$ observable could fail when:
- App was backgrounded (WebView suspended)
- 5-second startup delay in Android effects
- Race conditions with async callbacks

Now explicitly cancel native reminders in the task deletion effects
(clearRemindersOnDelete$, clearMultipleReminders, clearRemindersForArchivedTasks$)
immediately when tasks are deleted, before the web-side cleanup.

Fixes #5831
2026-01-02 17:05:54 +01:00
Johannes Millan
b2d0319ea2 fix(error-handler): use getErrorTxt to prevent [object Object] in error titles
Replace unsafe string cast `origErr as string` with proper error text
extraction using getErrorTxt utility. This ensures GitHub issue titles
generated from crashes show meaningful error messages instead of
"[object Object]".

Fixes #5822
2026-01-02 16:56:12 +01:00
Johannes Millan
4198a6bbc9 fix(planner): use task startDate for weekly repeat weekday calculation
When creating a weekly repeating task with WEEKLY_CURRENT_WEEKDAY quick
setting, the weekday was incorrectly set based on today's date instead
of the task's scheduled date (startDate). This caused tasks scheduled
for future days to not appear in the planner.

The fix passes the startDate to getQuickSettingUpdates() so that the
correct weekday is set based on when the task is scheduled, not when
it was created.

Fixes #5806
2026-01-02 16:25:55 +01:00
Johannes Millan
ce70df4a66 fix(focus-mode): use independent 1s timer for Pomodoro countdown
The Focus Mode timer was using GlobalTrackingIntervalService.tick$
which only emits at the configured trackingInterval (up to 100s).
When users set a high tracking interval to reduce disk writes,
the Pomodoro timer would only update every N seconds.

Now uses its own interval(1000) for smooth 1-second updates,
independent of the global tracking interval setting.

Fixes #5813
2026-01-02 16:23:27 +01:00
Johannes Millan
b9bf655e00 feat(focus-mode): add Skip Break button to banner during active breaks
When using focus mode with the overlay hidden (banner-only mode), users
can now skip an active break directly from the banner. Previously, the
Skip Break button was only available in the full-screen overlay.

Fixes #5818
2026-01-02 16:06:39 +01:00
Johannes Millan
09d0131760 feat(notes): add auto-save to fullscreen markdown editor
Add debounced auto-save (500ms) to the fullscreen task note editor
to prevent data loss. Changes are now saved automatically while typing
and when pressing Escape. Remove the Cancel button since all changes
are preserved.

Fixes #5804
2026-01-02 15:59:55 +01:00
Johannes Millan
4c278812d8 fix(reflection-note): prevent trailing spaces from being deleted while typing
Decoupled textarea input state from persisted store state. The component
now uses a local inputText signal for the textarea binding instead of
directly binding to the store value. This prevents the trimmed store
value from overwriting user input after the 500ms debounce.

Fixes #5800
2026-01-02 15:51:37 +01:00
Johannes Millan
7496b2dd60 fix(sync): add error handling for JSON parse failures in sync data
Add JsonParseError class that provides human-readable error messages
when sync data is corrupted or incomplete. This prevents the cryptic
"[object Object] SyntaxError" from appearing in error dialogs.

- Add JsonParseError class with position extraction and data sampling
- Wrap JSON.parse in decompressAndDecrypt with proper error handling
- Add comprehensive unit tests (16 tests)

Fixes #5771
2026-01-02 15:45:12 +01:00
Johannes Millan
e571d6e3bc fix(error-handling): prevent [object Object] from appearing in error messages
Improve error text extraction utilities to never return "[object Object]"
when displaying error messages to users. The fix adds more robust fallback
mechanisms including:

- Check for message, name, statusText properties before calling toString()
- Detect "[object Object]" result and fallback to JSON.stringify()
- Provide meaningful fallback messages when all extraction methods fail

Fixes #5790
2026-01-02 15:40:14 +01:00
Johannes Millan
3a5cddd8e8 fix(audio): prevent app freeze during focus mode ticking sound
Use singleton AudioContext and cache audio buffers to prevent memory
leak and resource exhaustion. Previously, a new AudioContext was
created for every sound play (once per second with ticking enabled),
causing ~480+ instances after 8 minutes and browser GC pauses.

Also fixes race condition where source.start() was called before
audio data was loaded.

Fixes #5798
2026-01-02 15:26:12 +01:00