planTaskForDay set dueDay and cleared dueWithTime but left remindAt
untouched. The reminder worker kept firing for the past remindAt value,
causing the reminder popup to reopen in a loop after "Reschedule for
tomorrow".
The devError module has shared mutable state (isShowAlert flag) that
caused flaky test failures in America/Los_Angeles timezone. Add a
test-only reset function and call it before the affected test.
- Extract executeNativeRequestWithRetry and isTransientNetworkError into
shared native-http-retry.ts for reuse by Dropbox and SuperSync
- Add locale-proof error.code checks: iOS NSURLErrorDomain, Android
SocketTimeoutException/UnknownHostException/ConnectException
- Keep English string matching as fallback for web/Electron
- Wrap Dropbox token refresh in retry logic
- Split timeouts: 30s for auth endpoints, 120s for data transfer
- Apply retry wrapper to SuperSync _fetchApiNative and _fetchApiCompressedNative
The reducer unconditionally prepended payload taskIds into state.ids
without checking entity existence. During op-log replay or concurrent
effects, deleted task IDs could be re-injected as orphans, causing
TypeErrors on properties like dueWithTime and dueDay.
iOS CapacitorHttp uses URLSession.dataTask which does not auto-retry POST
requests. Large sync payloads crossing the WKWebView bridge are vulnerable
to TCP connection drops (NSURLErrorNetworkConnectionLost / -1005).
- Add _executeNativeRequestWithRetry() with max 2 retries and linear backoff
- Add _isTransientNetworkError() classifier for iOS NSError descriptions
- Increase readTimeout from 60s to 120s for all native CapacitorHttp calls
- Add comprehensive unit tests for error classification and edge cases
Closes#6333
PFLog was named after "Pfapi" which is no longer used. Replace with
SyncLog in sync provider files and OpLog in op-log infrastructure files.
Delete unused migration scripts.
When a fresh client first syncs with a file-based provider (WebDAV,
Dropbox, LocalFile), it receives both a snapshotState and recentOps.
The snapshot was hydrated correctly, but recentOps were not recorded,
causing duplication through two paths:
1. Download path: On the next sync cycle, recentOps bypassed the
appliedOpIds filter (not in IndexedDB) and were re-applied.
2. Piggyback path: The adapter's isForceFromZero guard skipped marking
ops as processed, so they were returned as piggybacked during upload.
Fix by writing recentOps to IndexedDB after snapshot hydration and
always marking downloaded ops as processed for piggyback tracking.
The WCO padding-right rule matched on macOS where window controls are
on the left side, causing header icons to be pushed ~140px inward.
Restrict the rule to non-Mac Electron using the isNoMac body class.
Closes#6337
Counter buttons were always behind a dropdown toggle after the habits
management page change. Restore inline rendering on desktop and restrict
the timer-icon dropdown to mobile viewports only.
* Fix long break condition calculation
Adjust calculation for long break condition to account for cycle update.
* Undo Previous Change to getBreakDuration
* Move fix To Focus-Mode.effects
Adjust break duration calculation to account for cycle increment.
* Fix formatting of getBreakDuration calculation
* fix Test(pomodoro-bug-6044): Change test cases to be correct
* fix(Focus-Mode-Session-done): Subtract 1 from cycle to get last cycle
* Fix Test(focus-mode-effect.spec): Verify decrement of cycle
* Fix(focus-mode.effect.ts): Make comments clearer
* Fix(Pormodoro-Bug-6044.spec): Update tests names
* fix(focus-mode-effects.ts): Fix Missed tests
* Add(fpcis-mode-session-done): add || 1 Guard
* Fix Linting and formatting
* fix(focus-mode.effects.spec.ts): update cycle number for manual break duration calculation
- fix(tasks): preserve selectAllTasks memoization by only filtering when
undefined entities exist, avoiding new array allocation on every call
- fix(sync): replace mutable ARGON2_PARAMS export with getter/setter to
prevent test pollution across spec files
- fix(sync): convert tag-task-page from async pipe to toSignal pattern
to fix OnPush change detection after bulk sync state updates
- fix(sync): remove E2E navigation workarounds that masked the rendering
bug now fixed by the toSignal conversion
- fix(sync): add clarifying comments for archive-wins sibling conflict
resolution and waitForSyncWindow switchMap concurrency semantics
- fix(ios): add hex preview of first 16 bytes to WebDAV UTF-8 decode
error for easier debugging
- docs: add JSDoc to getDiffInWeeks noting negative diff behavior
https://claude.ai/code/session_01Y51QDFEdvrJ9VVgp9XfWLJ
Co-authored-by: Claude <noreply@anthropic.com>
Remove unused _counterTitle parameter from counter helpers, replace
hardcoded waitForTimeout with visibility check, unify timeout strategy
to test.slow(), fix waitForSyncToComplete API call, add
skipConflictDetection for forceDownloadRemoteState, and clean up
package-lock.json.
- Use toEntityKey() utility instead of inline template strings
- Fix stale mock in remote-ops-processing.service.spec.ts to match
new _buildEntityFrontier logic (appliedFrontier !== undefined)
- Fix transient entity resurrection: non-archive conflicts for
locally-archived entities now resolve as local-wins (no localWinOp)
instead of remote-wins, preventing addOne() from resurrecting entities
- Add unit test for multi-conflict pre-scan scenario
- Add TODO comments for Angular reactivity navigation workarounds
Fix two sync bugs causing E2E test failures:
1. Archive-wins pre-scan: When an entity has multiple conflicts (e.g.,
field updates + archive), the archive op was only checked per-conflict.
Non-archive conflicts resolved via LWW, creating local-win update ops
that resurrected archived entities. Now pre-scans ALL conflicts to
build entity-level sets, so all conflicts for an archived entity
resolve as archive-wins.
2. Entity frontier for new entities: When snapshotEntityKeys was undefined
(old format), _buildEntityFrontier used the snapshot vector clock for
ALL entities, inflating the frontier for genuinely new entities never
seen locally. Remote ops for these entities were incorrectly discarded
as superseded. Now only uses snapshot clock when appliedFrontier exists
for the entity.
Also improves E2E tests with navigation-based component refresh and
Playwright auto-retry assertions (toHaveCount with timeout).
Extract Argon2 params into mutable exported constant so tests can use
minimal KDF settings (8 KiB memory, 1 iteration) instead of production
values (64 MB, 3 iterations). Add batch operation creation helper and
configurable download limit to SimulatedClient, reducing test op counts
from 500-1000 to 50-100 while still exercising pagination.
Use immutable `created` timestamp instead of mutable `dueDay` for
duplicate detection in task-repeat-cfg.service.ts. The old check
used dueDay which gets mutated by planTasksForToday when users
reschedule overdue tasks, causing false-positive duplicate matches.
Replace filter-and-drop with waitForSyncWindow operator in all three
TaskDueEffects so day-change emissions during hydration/sync are
deferred rather than permanently lost.
Add waitForSyncWindow reusable RxJS operator and expose isInSyncWindow
as a computed signal + observable on HydrationStateService.
Use inline-flex centering on the mat-icon to align the font glyph
to the geometric center of its bounding box, and promote the spinning
element to a GPU compositing layer via translateZ(0) to prevent
sub-pixel anti-aliasing shifts during rotation.
Closes#6318
exitBreakToPlanning resets focus session state but had no effect to stop
tracking, leaving it running orphaned. Add effect to dispatch
unsetCurrentTask() when isSyncSessionWithTracking is enabled.
getDiffInWeeks used Math.round(ms / weekMs) which rounded Friday (day 4
of 7) into the next week. Switch to day-first calculation with
Math.floor(days / 7) to respect week boundaries while preserving DST
safety via Math.round on the day count.
iOS WebDAV sync could write but not read data due to Capacitor's native
bridge auto-parsing responses as JSON and replacing data with error strings.
Add a native URLSession-based plugin (matching the existing Android one)
that bypasses CapacitorHttp entirely.
Fixes#6317
Make checkOpForConflicts async to check current entity state when
a CONCURRENT remote op targets an entity with no pending local ops.
If the entity no longer exists in state (archived/deleted), treat
concurrent updates as superseded to prevent ghost resurrections.
On each successful sync request, the server now returns a fresh 14-day
JWT via X-Refreshed-Token response header. The client reads and stores
it automatically, preventing token expiry during active usage.
Server: export JWT_EXPIRY/getJwtSecret from auth, add createRefreshedToken(),
add onSend hook scoped to sync routes, expose header via CORS.
Client: store refreshed token in all 4 fetch methods, fix _getServerSeqKey
to hash only baseUrl (prevents full re-download on token change).
- Remove redundant subset condition in compareVectorClocks
- Add clarifying comment for conservative return in hasVectorClockChanges
- Batch per-key verbose logs into single summary log
- Add defensive warning for negative startingSeq in file-based sync
- Extract magic timeout constant in E2E test
- Update stale doc date
* feat: Extended ukrainian translation
Added the properties that do exist in en.json, but didn't exist in uk.json.
BUT, PLEASE PAY ATTENTION, Most of that new properties that I added, were translated using LLM, I didn't review each of them, so they still need human review
* feat: Extended czech translation
Added the properties that do exist in en.json, but didn't exist in cz.json.
BUT, PLEASE PAY ATTENTION, Most of that new properties that I added, were translated using LLM, I didn't review each of them, so they still need human review
* fix: Fixes after claude PR review
https://github.com/super-productivity/super-productivity/pull/6292#discussion_r2749397256
* feat: introduce habit tracking page and enhance simple counters with streak tracking and comprehensive configuration options.
* feat: add habit tracker for simple counters with navigation and internationalization.
* feat: Introduce habit tracker component and tests for simple counter streak duration calculation.
* Fix the dialog style that appears in the Habit interface
* bug fix
* Fixed translation and time zone issues
* habit icon
* app features
* Add a Settings button to the Habits page; clicking it opens the Settings interface and automatically expands the corresponding configuration section.
Clicking a habit icon allows you to configure that habit. To add a new habit, click the “Add” button.
* If a habit does not have a custom icon, its first character can be displayed inside a circular placeholder instead.
* The dialog box appears only after you release the button following a long press.
* Add the functionality to display names; clicking the button shows the habitual name. This can be persisted
* bug修复:Date adjustment (left/right) in shrink mode is not functioning as expected.
* Set Text Icon
* Fix abnormal icon size
* These development artifacts should not be committed to the repository.
* Lost Chinese translations
* Flaky Date-Dependent Tests
* Logic error in streak calculation
* Fix the icon issue
* Translation file violation
Use of any type
---------
Co-authored-by: Xinjie <xinjie_zhou@163.com>
* fix(backup): support importing legacy v10-v13 backups into v17
When v17 rewrote the sync architecture (PFAPI → operation-log), all
cross-model migrations (2 through 4.5) were dropped. This means backups
created by v10-v13 cannot be imported — they fail Typia validation
because the data shape is incompatible and archived tasks are silently
lost.
Add `migrateLegacyBackup()` which consolidates the essential v16
cross-model migrations into a single pass that runs before validation:
- Migration 2: Split flat `taskArchive` → `archiveYoung`/`archiveOld`,
extract `timeTracking` from project/tag properties
- Migration 3: Planner→dueDay, INBOX project, legacy tag cleanup
- Migration 4: `plannedAt`→`dueWithTime`, strip TODAY_TAG from tagIds
- Migration 4.1-4.2: Task repeat config cleanup
- Migration 4.3-4.5: menuTree, localization, appFeatures, lowercase
The detection (`isLegacyBackupData`) only triggers on definitive legacy
markers (`taskArchive`, `improvement`, `obstruction` keys) so modern
backups are unaffected.
Tested against a real v10-era backup (253 tasks, 155 archived, 19
projects) — all data preserved after migration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test(backup): replace large fixture with minimal v10 scaffold
Replace the 17k-line migrated backup dump with a small hand-crafted
fixture (~160 lines) that exercises every legacy edge case: flat
taskArchive, workStart/workEnd on projects, _showSubTasksMode, numeric
issueId, null timeEstimate/created, plannedAt, TODAY_TAG in repeat
configs, and lang config section.
Add 12 fixture-based tests that verify each of these conversions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(backup): resolve lint issues in legacy migration code
- Cast legacy project/tag to `any` (v17 types lack workStart/workEnd)
- Remove unused TaskState import
- Rename functions to camelCase (eslint naming-convention)
- Add eslint-disable for prefer-arrow-functions and naming-convention
- Replace require() with ES import for test fixture
- Fix prettier formatting in backup.service.ts import
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(backup): preserve archiveYoung for v13-v15 backups in migration 2
Migration 2's skip condition checked timeTracking.project length, which
is 0 for users who never used project-level work tracking. For v13-v15
backups (already archive-split but detected via improvement/obstruction),
this caused archiveYoung to be overwritten with empty data since
taskArchive is undefined.
Fix: skip migration 2 when archiveYoung already has tasks, or when
archiveYoung + archiveOld + timeTracking all exist without taskArchive
(meaning migration 2 already ran in v13+).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(backup): use nullish coalescing for numeric task fields in migration
Use ?? instead of || for issueAttachmentNr and issuePoints to preserve
valid 0 values during legacy backup migration. Add tests for this case.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Update es.json
Modified typos found while using the app, also gave better structure to some phrases on the UI that weren't clear due to lack of context.
Will check further whenever I am able to.
* Update src/assets/i18n/es.json
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---------
Co-authored-by: Johannes Millan <johannesjo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
After upload, latestSeq was set to mergedOps.length (total ops count)
instead of finalSyncVersion. This caused false "Server sequence
decreased" warnings when ops count exceeded syncVersion, and could
trigger unnecessary re-downloads. Aligns upload with download behavior
which already correctly uses syncVersion.
- Replace fragile VectorClockComparison[result] enum lookup with safe cast
- Return CONCURRENT instead of EQUAL when only one side has non-shared
keys in pruning-aware mode (safe direction: triggers LWW instead of
silent skip)
- Fix docs claiming clocks "reset" at MAX_SAFE_INTEGER (they throw)
- Add Logger.warn() in ValidationService when oversized vector clocks
are pruned server-side, improving observability for buggy clients
- Add tests for hasVectorClockChanges (previously zero coverage)
- Add symmetric LESS_THAN test for pruning-aware comparison mode
- Export MAX_LWW_REUPLOAD_RETRIES constant to eliminate magic number
coupling between sync-wrapper service and its test
- Add test verifying uploading client ID is preserved during server-side
clock pruning
- Add test for limitVectorClockSize when preserveClientIds exceeds MAX
Make hasVectorClockChanges pruning-aware by checking clock size before
logging missing keys — downgrade to verbose when pruning is likely,
warn when corruption is likely. Add return value assertion to LWW retry
exhaustion test, asymmetric pruning test cases, server-side pruning
tradeoff documentation, and fix stale "max 50" in docs.
When both vector clocks are at MAX size (pruning-aware mode) and shared
keys compare as equal, non-shared keys on both sides indicate genuinely
different causal histories. Returning EQUAL caused silent data loss by
skipping operations as duplicates. Returning CONCURRENT safely triggers
LWW conflict resolution instead.
Also fixes server snapshot pruning to preserve the requesting client's
ID and the snapshot author's client ID when limiting vector clock size.
Return CONCURRENT instead of EQUAL when two max-size clocks share no
keys (independent client populations). Fix misleading SyncStatus.InSync
return when LWW retry exhaustion leaves pending ops. Document known
limitation of size-based pruning heuristic. Add missing edge case tests.