Fix broken markdown formatting where multiple sections were collapsed
into a single malformed block. Properly structure HTML/TypeScript code
examples, key naming conventions, usage examples, and edge cases. #6004
When users click on the icon input field, 50 icons now appear immediately
instead of requiring the user to type first. This makes the icon selection
more intuitive and discoverable.
When starting a focus session with "Sync focus sessions with time tracking"
enabled, if no valid (undone) task exists, dispatch showFocusOverlay so the
user can select or create a task instead of running the timer untracked.
- Remove placeholder address text from privacy policies (DE/EN)
- Expand HTML privacy policy with full GDPR disclosures:
- Legal bases (Art. 6), data subject rights (Art. 15-22)
- Supervisory authority, retention periods, DPA info
- Cookies/tracking and automated decision-making sections
- Align HTML terms with German ToS:
- Add proper termination notice periods (2 weeks/good cause)
- Add 6-week notice for ToS amendments
- Add consumer withdrawal rights (14 days)
- Add ODR platform link and jurisdiction info
The generic type parameter on viewChild() conflicts with the read option.
Remove it to match the pattern used elsewhere in the codebase.
Fixes compilation error introduced in 1bb61fdd4.
Use visibility:hidden instead of display:none for additional buttons
to keep elements in layout flow. This ensures getBoundingClientRect()
returns correct values for mat-menu positioning.
Also use overflow:clip instead of overflow:hidden to prevent CDK
overlay positioning issues.
When "Sync focus sessions with time tracking" is enabled:
- Play button is disabled when no task is selected
- Tooltip shows "Select a task first to start tracking"
- Clicking the button opens the task selector instead of starting
Includes comprehensive unit tests for the new behavior.
Bug #5974: When using Pomodoro with isPauseTrackingDuringBreak=false and
isManualBreakStart=true, pressing the time tracking button to stop tracking
after session ends, then pressing "Start" to begin break, would not resume
tracking.
Root cause: storePausedTaskOnManualBreakSession$ only stored pausedTaskId when
isPauseTrackingDuringBreak=true. Without the stored task ID, the banner button
couldn't resume tracking.
Fix: Store pausedTaskId whenever manual break is enabled, regardless of the
isPauseTrackingDuringBreak setting. This ensures the task ID is available to
resume tracking when the break starts (if user manually stopped tracking).
Add deduplication guard to prevent Windows emoji picker from inserting
emojis twice. The issue occurs due to feedback loop in ngModel/formControl
binding when the picker triggers multiple events.
The automations plugin uses `declare const plugin: PluginAPI` while existing
bundled plugins use `PluginAPI` directly. This fix provides both variable names
pointing to the same API object, ensuring all plugins work correctly.
The plugin was using a custom vite.config.ts that generated separate
JS/CSS files with broken relative paths. When loaded in a blob URL
iframe, these paths couldn't resolve.
- Switch to @super-productivity/vite-plugin which inlines assets
- Fix title from "Procrastination Buster" to "AI Productivity Prompts"
- Fix misleading comment in sync-wrapper.service.ts safeguard
- Add missing SCSS for pause-resume button in focus mode break
- Remove commented archive store code from feature-stores.module.ts
- Increase touch submenu test buffer from 350ms to 450ms for CI stability
- Remove redundant isEmojiIcon method in tag-toggle-menu-list component
Replace racy :focus selector with explicit visibility wait and focus()
call. The original selector failed intermittently because Angular sets
focus asynchronously via change detection.
- SYNC_IMPORT: Throws error when empty archive would overwrite non-empty
(this is always a bug - sync should use getStateSnapshotAsync)
- BACKUP_IMPORT: Shows window.confirm dialog allowing user to choose
whether to proceed with restoring backup that has empty archives
This prevents silent data loss and state divergence between clients.
Follow-up to the ID mismatch fix. If the server MUST use the client's
opId (to prevent ID mismatch bugs), then it should be required, not
optional. This makes the type signature match the comment.
- Changed `opId?: string` to `opId: string` in provider.interface.ts
- Updated all callers (SuperSync, FileBasedSyncAdapter, tests)
- Added uuidv7 import to encryption-password-change.service.ts
When uploading BACKUP_IMPORT via uploadSnapshot(), the client's op.id
was not sent to the server. The server would generate its own ID,
causing the client to not recognize the operation when downloaded later.
This led to data loss as the old backup state would be re-applied.
Changes:
- Add opId parameter to uploadSnapshot() interface
- Pass op.id from operation-log-upload.service.ts
- Send opId in SuperSync API request payload
- Server uses client's opId instead of generating new one
- Add E2E test to verify ID matching
The fix is backwards compatible - legacy clients without opId still work
as the server falls back to uuidv7() when opId is not provided.
ImmediateUploadService checks isSyncInProgress before uploading, but
SYNCING status was never being set, so uploads could occur during sync
dialog interactions. This caused the CANCEL button on import conflict
dialogs to fail - uploads triggered conflict resolution downloads that
applied remote data before the user could cancel.
Also improved E2E test reliability by verifying dropdown selection was
actually applied before proceeding.
- Add settle delays after bulk task creation for UI/NgRx processing
- Wait for done button visibility before clicking
- Use toPass() retry pattern for CSS class assertions
- Add explicit triggerSync() before expecting conflict dialog
- Add pause/resume button to break screen for fullscreen break control
- Add "Back to Planning" button to exit break without auto-starting next session
- Add exitBreakToPlanning action to allow returning to preparation state
- Add translation keys for PAUSE_BREAK and RESUME_BREAK
This addresses the two issues reported:
1. Users can now pause breaks from the fullscreen break view
2. Users can click "Back to Planning" to change timer modes during break
Test coverage:
- 48 reducer unit tests (including 4 new for exitBreakToPlanning)
- 14 component unit tests (including pause/resume/exit methods)
- 4 E2E tests for break flow (1 skipped due to NgRx/zone.js E2E limitation)
When using Countdown timer mode with "Sync focus sessions with time tracking"
and "Pause task tracking breaks" enabled, time tracking now correctly stops
when the timer ends naturally (not just when manually ended).
The issue was that Countdown mode has shouldStartBreakAfterSession=false,
so autoStartBreakOnSessionComplete$ never fired, and stopTrackingOnManualEnd$
only fired for manual completions (isManual=true).
The fix renames stopTrackingOnManualEnd$ to stopTrackingOnSessionEnd$ and
extends the filter to also fire on automatic completions when no break will
auto-start (for Countdown/Flowtime modes or when isManualBreakStart is enabled).
Fixes#5996
The Plan tab in Daily Summary was showing empty because tomorrow$
returned null due to timezone-related date calculation. The bug was
caused by parsing a date string ("YYYY-MM-DD") as UTC midnight, then
using local timezone operations to add one day.
Fixed by using millisecond arithmetic (same pattern as daysToShow$)
and changed from hardcoded days[1] to days.find() for robustness.
Added 14 comprehensive unit tests covering:
- Basic functionality
- Timezone handling near midnight
- startOfNextDayDiff configuration
- Edge cases: month/year boundaries, leap years
Reduce tasks from 10 to 5 in the bulk tag deletion sync test.
Creating and syncing 10 tasks was exceeding the 180s test timeout.
5 tasks still validates atomic tag deletion behavior.
- Increase task creation timeout from 10s to 15s for slow renders
- Use force:true on backdrop click to bypass overlay coverage
- Replace page.evaluate() with Playwright locators in expandSection()
- Add proper condition-based waiting for collapsible panel visibility
Replace arbitrary waitForTimeout calls with condition-based waiting:
- Use specific selector scoped to .mat-mdc-menu-content for tag button
- Wait for tag to appear on task instead of waiting for menu to close
- Keep only the justified 350ms wait for touch protection delay testing
Add unit tests for selectAllTasksWithDueDay and selectAllTasksDueToday
selectors to ensure the performance optimizations work correctly.
Tests cover:
- Filtering tasks by dueDay and dueWithTime
- Sorting by dueDay chronologically
- Handling empty state and missing entities
- Deduplication of tasks from multiple sources
- Edge cases like subtasks with dueDay
Consolidate two Object.values() calls into a single iteration over
taskState.ids. This avoids creating two intermediate arrays and
reduces the number of passes over all tasks from 2 to 1.
Iterate taskState.ids instead of using Object.values() to avoid
creating an intermediate array. Also simplified the sort comparator
using localeCompare since dueDay is in YYYY-MM-DD format which is
lexicographically sortable.
Emojis in tag icons were rendered inside <mat-icon> elements, causing
excessive whitespace. Now emojis are detected via isSingleEmoji() and
rendered in a <span> with proper emoji styling.
Fixes#5977
Archives (archiveYoung, archiveOld) were being loaded into NgRx state
at startup but their selectors were never read anywhere in the codebase.
All code that needs archives loads them directly from IndexedDB via
ArchiveDbAdapter (StateSnapshotService, TaskArchiveService, etc).
This change removes the archive store registrations from NgRx, which:
- Reduces memory usage for users with large archives
- Improves startup time (no longer dispatching large archive data to NgRx)
- Reduces GC pressure (fewer large objects in memory)
Archive functionality is unaffected - archives are still stored in
IndexedDB and loaded on-demand when needed for worklog, sync, etc.
When importing a backup while connected to SuperSync, the server was
rejecting the operation with 409 SYNC_IMPORT_EXISTS error. This happened
because backup imports were using OpType.SyncImport which maps to
reason='initial' on the server.
Fix:
- Change OpType.SyncImport → OpType.BackupImport in backup.service.ts
- OpType.BackupImport maps to reason='recovery' on the server
- Server allows reason='recovery' even when SYNC_IMPORT exists
This enables users to recover data by importing backups when connected
to SuperSync, which is essential for disaster recovery scenarios.
Add unit test verifying OpType.BackupImport is used and E2E test that
validates the full backup recovery flow works when SYNC_IMPORT exists.
SYNC_IMPORT operations and local backups were losing archived tasks because
they used sync snapshot methods that return empty DEFAULT_ARCHIVE instead of
loading real archive data from IndexedDB.
Changes:
- ServerMigrationService: use getStateSnapshotAsync() to include archives
- LocalBackupService: use getAllSyncModelDataFromStoreAsync() for backups
- ArchiveOperationHandler: add safety guard to prevent overwriting non-empty
archives with empty ones
Add unit tests for archive preservation and E2E test that triggers actual
server migration by switching sync providers.