Commit graph

18504 commits

Author SHA1 Message Date
Johannes Millan
515dd9becc build: sign path setup 3 2026-01-28 12:21:41 +01:00
Johannes Millan
8eaf17f971 build: sign path setup 2 2026-01-28 11:59:44 +01:00
Johannes Millan
d0371971b3 build: sign path setup 2026-01-28 11:55:35 +01:00
Johannes Millan
c0f4f8be6c 17.0.6 2026-01-27 22:22:24 +01:00
Johannes Millan
89830910c5 fix(test): update mock client ID references in clean-slate tests
Update test expectations from E_newC to eNewC to match the mock
return value change from the lint fix commit.
2026-01-27 22:20:59 +01:00
Johannes Millan
fb759a0848 fix: lint 2026-01-27 22:19:01 +01:00
Johannes Millan
7f6c20a1c9 fix(sync): ensure protected client IDs are set after SYNC_IMPORT to prevent pruning issues 2026-01-27 22:02:38 +01:00
Johannes Millan
2285b07f99 improve E2E test reliability and add snapshotOpType interface param
- E2E: Use specific CSS selectors instead of fragile role/text matchers
- E2E: Add visibility assertions before clicking elements
- E2E: Refactor plugin tests to use shared helper functions
- E2E: Add 30s timeout for global-search test suite
- E2E: Increase parallel workers to 4 for local dev speed
- Interface: Add optional snapshotOpType param to uploadSnapshot
- Tests: Fix hydrator spec assertions to match implementation logic
2026-01-27 20:55:30 +01:00
Johannes Millan
a1c9b7cb93 feat(sync): make encryption actions explicit 2026-01-27 19:45:15 +01:00
Johannes Millan
e6fba6b3ed docs(sync): document protected client IDs mechanism and update tests
Add documentation explaining why all vectorClock keys must be protected
during SYNC_IMPORT/BACKUP_IMPORT operations to prevent incorrect
CONCURRENT comparisons after vector clock pruning.

Update tests to verify multi-key vectorClock protection.
2026-01-27 18:43:22 +01:00
Johannes Millan
abffd4f133 fix(sync): ensure all client IDs in vectorClock are protected during SYNC_IMPORT operations 2026-01-27 18:25:46 +01:00
Johannes Millan
d67d340f0e feat(sync): add encryption disable flow for file-based providers
Add "Remove Encryption" functionality for file-based sync providers
(WebDAV, Dropbox, LocalFile). Users can now disable encryption,
converting synced data to unencrypted format.

Changes:
- Add disableEncryptionForFileBased() method to EncryptionDisableService
- Add "Remove Encryption" button to file-based provider forms
- Add disable-only mode to change password dialog for file-based
- Add unit tests for the new disable flow
- Add E2E test (webdav-encryption-disable.spec.ts) validating full flow
- Extend sync.page.ts with encryption enable/disable helpers

The flow: user clicks Remove Encryption → confirmation dialog →
upload unencrypted snapshot → clear local encryption config.
2026-01-27 17:59:57 +01:00
Johannes Millan
56573083ad fix(issue-providers): make newer fields optional for backwards compatibility
Make fields that were added after initial provider creation optional so
Typia validation passes with persisted data that has undefined values.

Fixes #6215 - Data Damage Detected dialog on startup
2026-01-27 16:43:34 +01:00
Johannes Millan
2a83a0d627 test(sync): add tests for isEncryptionOperationInProgress and runWithSyncBlocked
- Test getter returns correct values before, during, and after operations
- Test runWithSyncBlocked executes operations and propagates results/errors
- Test sync is blocked during encryption operations
- Test sync is allowed after encryption operations complete
- Test runWithSyncBlocked waits for ongoing sync before starting
2026-01-27 16:16:27 +01:00
Johannes Millan
4acc7d6ca8 fix(sync): prevent ImmediateUploadService from triggering during encryption ops
forceUpload() blocks sync() via _isEncryptionOperationInProgress$, but
ImmediateUploadService only checked isSyncInProgress. This allowed it to
trigger during password changes and run server migration checks that
download/decrypt old data - causing DecryptError after password change.

- Expose isEncryptionOperationInProgress getter in SyncWrapperService
- Check the flag in ImmediateUploadService._canUpload()
- Add unit test for the new guard
2026-01-27 16:12:30 +01:00
Johannes Millan
ba449487a7 style(schedule): implement grid layout for consistent header and body widths 2026-01-27 15:06:52 +01:00
Johannes Millan
6063e57e45 test: fix failing unit tests for schedule and validation
Fix date-dependent tests using fixed dates relative to mocked today instead
of real current time. Update validation test expectation to match
implementation behavior allowing empty entityChanges without warning.
2026-01-27 14:57:34 +01:00
Johannes Millan
b911546e53 fix(sync): improve error visibility in SuperSync operations
- Add logging to empty catch block in validation (is-related-model-data-valid.ts)
- Notify users when ANY ops are rejected, not just >= 10 (rejected-ops-handler.service.ts)
- Change encryption auto-disable snackbar from SUCCESS to WARNING
- Add logging when sync-config-default-override.json fails to load
- Add DIALOG_RESULT_ERROR translation key for sync dialog errors
- Add test for single op rejection notification
2026-01-27 14:49:00 +01:00
Johannes Millan
48f9967cf5 fix(sync): handle MissingRefreshTokenAPIError for Dropbox re-auth
When Dropbox access token expires and refresh token is missing/invalid,
show user-friendly re-authentication prompt instead of cryptic error.
Fixes #6212
2026-01-27 14:49:00 +01:00
Johannes Millan
16be1ad91b refactor(encryption): improve code quality with strategy pattern
- Use discriminated union for DerivedKeyInfo (type-safe: webcrypto | fallback)
- Extract CryptoStrategy interface with WebCrypto and @noble/ciphers implementations
- Add fallback path tests with mocked crypto.subtle unavailability
- Add cross-compatibility tests (WebCrypto ↔ fallback interoperability)
- Total test count increased from 32 to 43
2026-01-27 14:49:00 +01:00
Johannes Millan
6dc00e442a fix(encryption): use @noble/ciphers fallback for AES-GCM on mobile
WebCrypto (crypto.subtle) is unavailable on Android/iOS Capacitor apps
due to insecure contexts. This adds @noble/ciphers as a pure JavaScript
fallback for AES-GCM encryption when WebCrypto is not available.

- Add @noble/ciphers dependency (Cure53 audited, ~4-6KB tree-shaken)
- Update DerivedKeyInfo to support both CryptoKey and raw bytes
- Add fallback encrypt/decrypt functions using gcm from @noble/ciphers
- Legacy PBKDF2 data still requires WebCrypto with clear error message
2026-01-27 14:49:00 +01:00
Johannes Millan
5f44e18aa2 fix(sync): show clear error when encryption unavailable on Android
WebCrypto (crypto.subtle) is unavailable in insecure contexts like
Android Capacitor (serves from http://localhost). Previously, encryption
operations would fail silently, making sync appear successful when data
wasn't actually syncing.

Changes:
- Add isCryptoSubtleAvailable() check function in encryption.ts
- Add assertCryptoSubtleAvailable() guard to encrypt/decrypt functions
- Add WebCryptoNotAvailableError handler in sync-wrapper.service.ts
- Check crypto availability BEFORE deleting server data in
  encryption-enable.service.ts and import-encryption-handler.service.ts
- Add WEB_CRYPTO_NOT_AVAILABLE translation key with clear error message

This ensures users see a clear error message instead of silent failure
when trying to use encryption on unsupported platforms.
2026-01-27 14:49:00 +01:00
Johannes Millan
ab6df00a72 fix(sync): handle duplicate operation IDs gracefully in appendBatch
When concurrent sync triggers occur (especially on Android), a race condition
between filterNewOps() and appendBatch() can cause ConstraintError due to
duplicate operation IDs in the byId unique index.

Instead of failing sync, catch ConstraintError and return empty array - the
ops were already inserted by a concurrent sync.

Fixes #6213
2026-01-27 14:49:00 +01:00
Johannes Millan
ebe72c14df fix(touch): limit click blocking to submenu triggers only
Regular menu items (like tag toggle buttons) were having their clicks
blocked by the touch fix directive. This caused tag assignment from
context menu to not work on mobile devices.

The click blocking is now limited to elements with matMenuTriggerFor
attribute, which are the actual submenu triggers that need protection
against accidental selection when submenus open under the finger.
2026-01-27 14:49:00 +01:00
Johannes Millan
6f79209466 fix(op-log): remove noisy warning for empty entityChanges
Empty entityChanges is intentional for most actions since the
actionPayload is sufficient for replay and sync. The warning
was triggering constantly for normal operations like updateTask.
2026-01-27 14:49:00 +01:00
Johannes Millan
e2c585ee45 fix(dropbox): use hash-wasm fallback for PKCE on Android
On Android, Capacitor serves the app from http://localhost which is not
a secure context. WebCrypto's crypto.subtle API is unavailable in
insecure contexts, causing Dropbox OAuth PKCE code generation to fail.

Use hash-wasm (already a dependency for Argon2id) as fallback when
crypto.subtle is unavailable.
2026-01-27 14:49:00 +01:00
Alberto Avon
3fc0be6924
feat(boards): move tasks to and from backlog when dragging to a panel with backlogState set (#6209)
Co-authored-by: Alberto Avon <a.avon@nehos.it>
2026-01-27 14:47:30 +01:00
Benjamin Hooper
2e20746fb8
feat: Copy Version Number #5108 (#6184)
* feat: Copy Version Number #5108

* Use Claude Code Review Suggestion

* Added Translation

* Refactor to use shared copyToClipboard function
2026-01-27 14:41:35 +01:00
Johannes Millan
ac700b6eed fix(sync): prevent race condition in encryption password change
Move unsynced operations check inside runWithSyncBlocked() to prevent
race condition where background operations could add unsynced ops
between the check and acquiring the lock.

Also add verification step after createCleanSlate() to ensure
SYNC_IMPORT was stored before proceeding, and keep new password
config on upload failure (reverting would encrypt with wrong password).

Fixes flaky E2E test in CI.
2026-01-26 21:20:50 +01:00
Johannes Millan
6ca7223dc6 refactor: add markdown renderer tests and remove dead IPC code
- Add 18 unit tests for marked-options-factory covering:
  - Image renderer (sizing syntax, lazy loading, dimensions)
  - Paragraph renderer (headings h1./h2. syntax)
  - parseImageDimensionsFromTitle helper
  - preprocessMarkdown hook
- Export parseImageDimensionsFromTitle and preprocessMarkdown for testability
- Remove unused IPC.TOGGLE_FULLSCREEN event and handler
  (F11 fullscreen is handled directly in main-window.ts)
2026-01-26 20:55:29 +01:00
Johannes Millan
a1af9d5d59 17.0.5 2026-01-26 19:48:56 +01:00
Johannes Millan
a4c0d84904 test(e2e): fix flaky dialog interactions by scoping to container
- Wait for mat-dialog-container to be visible before clicking
- Scope button selectors within the dialog container
- Wait for dialog to be detached after dismissing
- Remove flaky waitForTimeout in favor of proper state waits
2026-01-26 19:48:12 +01:00
Johannes Millan
8f935294a5 fix(schedule): apply dialog max-height to schedule task dialog only
Move the max-height constraint from global mat-dialog-content to the
dialog-schedule-task component specifically, since it has no header
and needs different sizing.
2026-01-26 19:37:50 +01:00
Johannes Millan
3534706f16 fix(open-project): make legacy config fields optional for backward compatibility
Fields progressOnDone, transitionConfig, and availableTransitions were added
after some users already had OpenProject configs, causing Typia validation
errors. Making them optional allows legacy data to load without errors.
2026-01-26 19:35:15 +01:00
Johannes Millan
7c49cc2e6b fix(android): flush time tracking data when app goes to background #6207
When the app goes to background on Android, accumulated time tracking
data was not being flushed to IndexedDB. If Android terminated the app
while backgrounded, tracked time would be lost.

This fix adds a flushOnPause$ effect that:
- Syncs elapsed time from the native foreground service
- Flushes accumulated time from the BatchedTimeSyncAccumulator
- Writes pending operations to IndexedDB

This follows the same pattern already used for notification button
clicks (handlePauseAction$, handleDoneAction$).
2026-01-26 18:28:06 +01:00
Johannes Millan
0f68c35932 17.0.4 2026-01-26 18:14:43 +01:00
Johannes Millan
84776535f4 test: fix flaky validate-state.service tests
Mock validateAndRepair directly instead of relying on global state
(environment.production, window.confirm spy) that could be affected
by test pollution when running the full test suite.
2026-01-26 18:12:44 +01:00
Johannes Millan
070469f239 fix(focus-mode): dispatch completeFocusSession when isManualBreakStart=true #6206
When isManualBreakStart was enabled, the detectSessionCompletion$ effect
was blocking the completeFocusSession action entirely. This prevented:
- Screen transition from Main to SessionDone
- Completion sound from playing
- Window focus on Electron
- "Start break" button from appearing

The isManualBreakStart check was incorrectly placed in detectSessionCompletion$.
It belongs only in autoStartBreakOnSessionComplete$ (which already has it)
to prevent breaks from auto-starting while still allowing session completion.
2026-01-26 17:53:02 +01:00
Johannes Millan
550eedefa8 fix: schedule dialog height #6187 2026-01-26 17:34:00 +01:00
Johannes Millan
73b9bb580f 17.0.3 2026-01-26 16:50:58 +01:00
Johannes Millan
753c40cbf3 build: update gitignore 2026-01-26 16:50:33 +01:00
Johannes Millan
2108e69e0b feat(sync): re-enable repair system with user confirmation
Re-enable the data repair system with user confirmation before execution.
When invalid data is detected, show a confirmation dialog asking if the
user wants to repair, giving users control and visibility.

Changes:
- Add translated confirmation dialog before repair executes
- Add isRemote flag to loadAllData dispatch in sync contexts to prevent
  LOCAL_ACTIONS effects from firing
- Add user notification when repair fails after confirmation
- Add comprehensive tests for validateAndRepairCurrentState()
- Add documentation for implicit contracts and limitations
- Improve type safety (replace `as any` with proper casts)
2026-01-26 16:29:21 +01:00
Johannes Millan
c0387f12d2 perf(ci): optimize E2E workflow with shared build and Playwright caching
- Create composite action for shared E2E setup (Node, npm, Playwright)
- Add build job that builds frontend once and uploads artifact
- Test jobs now download artifact instead of rebuilding
- Cache Playwright browsers to avoid fresh install each run
- Reduces frontend builds from 3x to 1x per workflow run
2026-01-26 16:00:19 +01:00
Johannes Millan
e9b1b9c34c perf(e2e): split scheduled CI into parallel jobs and reduce wait times
Split e2e-scheduled.yml into 3 parallel jobs (regular, webdav, supersync)
for ~3x faster nightly runs. Each job only starts the Docker services it
needs. Also reduced fixed wait times in sync-helpers.ts and waits.ts to
improve test execution speed while maintaining reliability.
2026-01-26 15:40:22 +01:00
Johannes Millan
df3f68c3a9 fix(tasks): handle undefined config in createNewTaskWithDefaults
Add optional chaining for cfg()?.tasks to prevent "Cannot read
properties of undefined (reading 'defaultProjectId')" error during
Dropbox sync when config is not yet loaded.

Fixes #6199
2026-01-26 15:04:51 +01:00
Johannes Millan
7c1c2cd3c1 fix(e2e): add retry logic for flaky provider dropdown clicks
Angular Material dropdowns can fail to open under load when multiple
test workers compete for resources. Add selectSuperSyncProviderWithRetry()
helper that retries the click up to 3 times with a 200ms initial delay.
Applied to setupSuperSync, enableEncryption, and disableEncryption methods.
2026-01-26 14:53:50 +01:00
Johannes Millan
afa8b7da4d test(ui): fix marked-options-factory tests for marked v17 API
Update link renderer tests to provide tokens array and mock parser
context as required by marked v17. Remove URL auto-linking tests
since gfm:true handles this automatically in the lexer now.
2026-01-26 13:48:11 +01:00
Johannes Millan
e0e03446b4 feat(dropbox): add Capacitor HTTP support for native platforms
Use CapacitorHttp instead of fetch() on iOS/Android to avoid
issues with WebKit and WebView handling of HTTP requests. Native
platform tests are skipped as CapacitorHttp cannot be properly
mocked in Jasmine.
2026-01-26 13:48:11 +01:00
Johannes Millan
6ffc414693 fix(tasks): allow subtask drag-drop reordering in Today/Tag views
Subtasks appearing as top-level items in Today/Tag views (when their
parent is not in the view) were snapping back to original position
when reordered via drag-drop.

Root cause: selectTodayTagRepair selector was excluding ALL subtasks
from valid taskIds, even those that should appear as top-level items.
After reordering, the repair effect immediately "fixed" the order by
removing the subtask.

Changes:
- Update selectTodayTagRepair to include subtasks whose parent is NOT
  in the Today list (these appear as top-level items)
- Update enterPredicate to check if subtask's parent is in target
  list's tasks for more reliable detection
- Add guard for OVERDUE to BACKLOG edge case in _move method
- Add comprehensive tests for enterPredicate (26 tests)
- Add edge case tests for selectTodayTagRepair (38 tests)
2026-01-26 13:48:11 +01:00
Johannes Millan
3c6d0369c6 fix(gitlab): use null as default for project field
Change DEFAULT_GITLAB_CFG.project from '' to null for semantic
correctness. The type GitlabCfg.project is string | null, so null
properly represents "not configured" rather than an empty string.

Fixes #6138
2026-01-26 13:48:11 +01:00