Commit graph

286 commits

Author SHA1 Message Date
Florian Bachmann
729d35501f
Fix immutable caldav task (#6705)
* Fix immutable CalDAV task after completion

* Linting

* Resolves Claude suggestions
2026-03-03 15:05:57 +01:00
Johannes Millan
144dadba41 docs(caldav): add VEVENT expansion design document
Design for extending the existing CalDAV provider with VEVENT (calendar
event) support alongside existing VTODO sync. Serves privacy-focused
self-hosted calendar users with no new auth infrastructure needed.
Complements the Google Calendar provider design.
2026-03-03 11:27:20 +01:00
Johannes Millan
ed2fb966db docs(google-calendar): add provider design document
Evaluates authentication approaches for cross-platform Google Calendar
integration and documents decisions: hybrid auth proxy with user-provided
credentials option, REST API v3, and phased two-way sync rollout.
2026-03-03 11:27:20 +01:00
Johannes Millan
ab8b577c10 docs(sync): add file-based sync flowchart for Dropbox/WebDAV/LocalFile
Parallel to the SuperSync flowchart, covering the file-based sync
decision tree: gap detection, snapshot hydration, rev-based upload
retry, and error handling. Verified against source code with matching
abstraction level to the SuperSync chart.
2026-03-01 21:27:08 +01:00
Johannes Millan
058c26594b docs(sync): fix structural inaccuracies in supersync scenarios flowchart
Correct the flowchart to match actual codebase behavior:
- Move fresh-client dialogs under the "has remote ops" branch (was incorrectly under "no remote ops")
- Split single password dialog into two distinct decrypt error dialogs (DecryptNoPasswordError vs DecryptError)
- Route SYNC_IMPORT conflicts to ImportConflictDialog (was incorrectly using SyncConflictDialog)
- Add encryption-only change bypass for password-change SYNC_IMPORTs
- Add LWW tie-breaking details (remote wins on tie, archive ops always win)
- Add retry limit note on re-download, correct "Cancel" to "Disable SuperSync"
- Show silent server migration path for fresh clients with local data on empty server
2026-03-01 21:27:08 +01:00
Johannes Millan
b820055b3e docs(sync): distinguish dialog types and highlight actions in flowchart
Rename generic "Conflict dialog" labels to SyncConflictDialog and
ImportConflictDialog to reflect the two distinct components. Add orange
action styling for key state-changing nodes (apply, force upload/download,
enable encryption, upload).
2026-03-01 21:27:08 +01:00
Johannes Millan
dafee46f7a docs(sync): add encryption architecture and scenario documentation
Add comprehensive documentation for the encryption and sync features:

- Add SuperSync encryption architecture document
- Add SuperSync scenario spec with flowcharts
- Add simplified scenario reference
- Add SuperSync client simplification plan
2026-03-01 21:27:08 +01:00
Johannes Millan
56dd1c8887 docs(electron): add beta rollout plan for Electron upgrade
Cover GitHub pre-release, Snap beta channel, and Flatpak beta
branch strategies with recommended combined approach.
2026-02-26 16:28:56 +01:00
Johannes Millan
de3745dfe6 docs(electron): add Electron 37→40 upgrade research and plan
Document findings from attempted Electron upgrade including the
upstream blocker (electron-builder#9452) for Snap packaging and
a phased implementation plan for when it's resolved.
2026-02-26 16:28:56 +01:00
Gitoffthelawn
778eae009d
Reworked the How to Rate Super Productivity page (#6609)
Hopefully this will help.
2026-02-23 11:34:54 +01:00
Johannes Millan
03572c3f2c
Feat/start of next day (#6565)
* feat: add label to heatmap for repeat task

* style(e2e): fix prettier formatting in planner spec

* fix(focus-mode): clear stale _isResumingBreak flag when isPauseTrackingDuringBreak is enabled (#6534)

When both isSyncSessionWithTracking and isPauseTrackingDuringBreak are
enabled, pausing and resuming a break left _isResumingBreak stale,
causing the next manual tracking start to dispatch clearResumingBreakFlag
instead of skipBreak. Refactor syncSessionResumeToTracking$ to explicitly
dispatch clearResumingBreakFlag in this case.

* refactor(sync): unify JWT expiry to 365 days for all auth methods

Replace separate JWT_EXPIRY_MAGIC_LINK (365d) and JWT_EXPIRY_PASSKEY (7d)
constants with a single JWT_EXPIRY (365d). The auth method only matters
during login — once a JWT is issued, it represents a verified session
regardless of how the user authenticated.

* feat(start-of-next-day): respect startOfNextDayDiff offset in today view

Thread startOfNextDayDiffMs through AppState, selectors, meta-reducers,
and task component so that "today" membership correctly accounts for the
user's configured day-start offset. When startOfNextDay=4 (4 AM), at
2:30 AM the app now correctly treats the previous calendar day as "today".

- Add isTodayWithOffset utility for offset-aware date comparison
- Store startOfNextDayDiffMs in AppState alongside todayStr
- Update all selectors (work-context, planner, task, overdue) to use offset
- Update meta-reducers with defensive fallbacks for state access
- Fix task component computed signals (isOverdue, isScheduledToday, etc.)
- Add 48 new tests covering offset boundary conditions

* style(planner): remove unused eslint-disable directive

* fix(start-of-next-day): use offset-aware date in ensureTasksDueTodayInTodayTag effect

Replace raw getDbDateStr() and getDateRangeForDay(Date.now()) with
store-derived todayStr and offset-adjusted range in task-due.effects.ts.
Without this, the effect would use the wrong day between midnight and
the configured startOfNextDay hour.

Also add selectOverdueTasks offset boundary tests.

* refactor(start-of-next-day): use DateService for offset-aware today checks

Add DateService.isToday() method that encapsulates the startOfNextDayDiff
offset logic, replacing scattered isToday()/getDbDateStr() calls across
effects, services, and components.

- Add isToday(date) to DateService for DRY offset-aware checks
- Fix task-repeat-cfg.effects.ts: 6 isToday/getDbDateStr calls
- Fix task-repeat-cfg.service.ts: isToday call
- Fix task-context-menu-inner.component.ts: 6 isToday/getDbDateStr calls
- Fix task-related-model.effects.ts: getDbDateStr call
- Fix work-context.service.ts: getDbDateStr call
- Remove duplicate planTaskForDay handler from tag.reducer.ts
  (already handled by planner-shared meta-reducer with offset)

* refactor(start-of-next-day): migrate remaining isToday() calls to offset-aware DateService

Replace 6 call sites still using the non-offset isToday()/isYesterday()
with DateService methods that respect startOfNextDayDiff. Also adds
isYesterday() to DateService and uses isTodayWithOffset in legacy backup
migration. Behavior is identical at offset=0 (default).

* fix(start-of-next-day): fix offset bugs, sync regression, and code quality issues

- Fix wrong config path in legacy backup migration (misc.startOfNextDay)
- Restore sync readiness check (filter+first instead of take(1))
- Restore SYNC_AFTER_ENABLE in setInitialSyncDone conditions
- Use offset-aware dates in addAllDueToday/addAllDueTomorrow
- Make isSameDay offset-aware and pass offset through planner selectors
- Fix TagSettingsPageComponent selector from 'project-settings' to 'tag-settings'
- Hide settings link for virtual TODAY tag
- Revert direct ru.json edits (only en.json should be edited)
- Add standalone:true and use takeUntilDestroyed in settings components
- Restore Math.max(duration,1) for zero-duration overlap detection
- Remove dead code, stale CSS, and commented-out HTML
- Add input validation clamping in DateService.setStartOfNextDayDiff

* fix(start-of-next-day): fix offset bugs in overdue detection, planner display, and LWW sync

- Fix isOverdue ignoring offset for dueWithTime tasks in task.component
- Remove duplicate moveBeforeTask handler from tag.reducer (handled by meta-reducer)
- Add skip(1) and hydration guard to setTodayStr$ effect to prevent race condition
- Move side effects from map() to tap() in global-config.effects
- Fix isSameDay double-offset bug in planner.selectors for scheduled tasks/events
- Replace unsafe `as any` casts with proper PlannerState types
- Use safe optional chaining for todayStr access in meta-reducers
- Refactor handlePlanTaskForDay to use helper functions with hasChanges optimization
- Extend syncTodayTagTaskIds in LWW meta-reducer to handle dueWithTime changes
- Fix absolute import path in global-config.effects
- Add @deprecated to isToday() in favor of offset-aware alternatives

* fix(config): migrate task dueDays when startOfNextDay offset changes

When the "start of next day" offset changes and causes todayStr to shift,
existing tasks with dueDay matching the old todayStr are now migrated to
the new todayStr so they remain classified as "today" tasks.

* refactor(config): use switchMap and document archive task exclusion

Replace mergeMap with switchMap in setStartOfNextDayDiffOnChange
effect to better communicate intent (only latest emission matters).
Add comment clarifying archived tasks are intentionally excluded
from dueDay migration.

* test(sync): add LWW tests for dueWithTime → TODAY_TAG sync

Cover the dueWithTime path in syncTodayTagTaskIds that was added
but had no test coverage. Tests verify TODAY_TAG membership updates
when dueWithTime changes via LWW sync.
2026-02-21 12:47:19 +01:00
Corey Newton
c2b18683d8
docs/wiki content v0.7 (#6568)
* docs(wiki): add new Quickstart to help with using Sync

There is a slew of notes that try to explain or show this so a
Quickstart can help bring everything into one place.

* docs(wiki): combine "First Steps" into single note with relevant links

* docs(wiki): update index notes

* docs(wiki): fix remaining broken external links

* docs(wiki): add core developer How-To guides to orient first-time devs

The majority of the documentation is currently spread across several
files ins "docs/" and READMEs. Over time these can be consolidated into
the wiki while retaining the common CONTRIBUTING.md as a valid entry
point.

* docs(wiki): add basic guides for plugins and issue integration

As with the core development docs, there is too much to add here right
now. These notes will serve as a simple entry to other resources.

* docs(wiki): add basic reference note for theming

* docs(wiki): add basic Translation guide

* docs(wiki): rename Theming and linting to clean up headings

* docs(wiki): add heading lint exception for GH-specific nav pages; rework sidebar and index pages

Sidebar should be a quick-access for the more common topics grouped
thematically with the X.00 notes simply enumerating all the notes where
appropriate.
2026-02-20 21:13:38 +01:00
Johannes Millan
90c698fc5b docs: add iOS App Store section to how-to-rate guide 2026-02-17 18:19:20 +01:00
Corey Newton
3b587f1cdc docs(wiki): lint headings and lists 2026-02-16 16:23:32 +01:00
Corey Newton
d4b615abde docs(wiki): clarify differences between iCal and CalDAV
Some discussion and research has confirmed a few things. More field
reports needed to help extend How-To guides
2026-02-16 16:23:32 +01:00
Corey Newton
d37fc40718 docs(wiki): add note for configuring sync backends
As with 2.08, I expect this will need to be checked more frequently
until SuperSync's protocol replaces the blob-based format.
2026-02-16 16:23:32 +01:00
Corey Newton
81def26af2 docs(wiki): add guide on choosing a backend
I tried to include as much up-to-date guidance as possible but given the
dynamic nature of SuperSync at the moment this note will require some
updates as the new sync backend is rolled out to non-SuperSync
integrations.
2026-02-16 16:23:32 +01:00
Corey Newton
dc33035fee docs(wiki): update "new tasks" and "task integration notes" 2026-02-16 16:23:32 +01:00
Corey Newton
8c82683c14 docs(wiki): update original notes on data backups 2026-02-16 16:23:32 +01:00
Corey Newton
24f73db4f7 docs(wiki): populate task management how-to guides 2026-02-16 16:23:32 +01:00
Corey Newton
eda03fa801 docs(wiki): fix external link formatting 2026-02-16 16:23:32 +01:00
Johannes Millan
d5387b8ce6 fix(sync): prevent double-encryption of snapshot state in file-based adapter
When encryption was enabled, forceUploadLocalState (triggered by "Use local"
in conflict dialog) caused double-encryption: the upload service encrypted the
state payload, then the file adapter encrypted the entire file. On download,
only the outer layer was decrypted, leaving the state as an opaque string that
couldn't be hydrated — making "Use remote" silently fail and forcing a
ping-pong loop between clients.

Fix: _uploadSnapshot now uses getStateSnapshot() (matching _buildMergedSyncData)
instead of the passed state parameter, since file-level encryption already
handles security.

Also: clean up dead return values in _buildMergedSyncData, reset
_lastSyncTimestamps in _uploadSnapshot for consistency, and update stale
piggybacking doc reference.
2026-02-15 11:19:22 +01:00
Johannes Millan
08e8329f97 refactor(sync): consolidate LegacySyncProvider into SyncProviderId
Remove duplicate LegacySyncProvider enum and use SyncProviderId everywhere.
The two enums had identical values but were separate types for historical
reasons, making the "Legacy" name misleading since providers are actively used.
2026-02-15 11:19:22 +01:00
Johannes Millan
9328156ca1 fix(sync): add vector clock pruning to compaction and update docs
Add limitVectorClockSize to OperationLogCompactionService._doCompact()
which was the remaining saveStateCache caller that persisted unpruned
clocks. Update vector-clocks.md exhaustive pruning table with the three
new client-side pruning locations. Add boundary tests at exactly
MAX_VECTOR_CLOCK_SIZE for snapshot and hydrator services.
2026-02-15 11:19:22 +01:00
Johannes Millan
c70ced204e fix(sync): fix stale comments, doc refs, and preserve lastSeq on clean-slate
Remove references to deleted docs/ai/ files, update stale comments about
protectedClientIds and pruning-aware comparison to reflect current REPLACE
semantics, fix MAX=30→20 heading, client_0..29→19 comment, use ?? over ||,
preserve lastSeq in server clean-slate path to prevent sequence reuse, and
add clarifying comments for mock limitations and validation guards.
2026-02-12 16:27:56 +01:00
Johannes Millan
ea91e02b1a test(sync): add regression tests and update stale doc reference
- Add deterministic tie-breaking test for vector clock pruning with
  equal counters (shared-schema)
- Remove last isLikelyPruningArtifact reference from entity versioning doc
2026-02-12 16:27:55 +01:00
Johannes Millan
3f99e3773c fix(sync): fix replaceToken expiry, locale-independent sort, and stale comments
- Use JWT_EXPIRY_PASSKEY (7d) for replaceToken instead of 365d magic link
  expiry — token replacement is a security action, shorter lifetime is safer
- Replace localeCompare with locale-independent comparator in vector clock
  tie-breaking to ensure deterministic behavior across environments
- Fix 5 additional stale MAX=30 references in docs and tests (now 20)
- Update authentication.md to reflect dual JWT expiry tiers
- Clean up isLikelyPruningArtifact references in docs and LEGACY_MAX in tests
2026-02-12 16:27:55 +01:00
Johannes Millan
a335589dc6 refactor(sync): reduce vector clock DoS cap from 100 to 50 entries 2026-02-12 16:27:55 +01:00
Johannes Millan
f37280e082 refactor(sync): reduce MAX_VECTOR_CLOCK_SIZE from 30 to 20
Lower the cap to leave headroom for future increases and surface
size-related edge cases earlier. All pruning logic is MAX-agnostic
so this is a safe constant change with documentation updates.
2026-02-12 16:27:55 +01:00
Johannes Millan
53769019e2 cleanup 2026-02-12 16:27:55 +01:00
Johannes Millan
128ebe1f8a docs(sync): update stale MAX=10 and pruning-aware references in documentation 2026-02-12 16:27:55 +01:00
Johannes Millan
75a4102937 docs(sync): update pruning research to reflect MAX=30 simplification 2026-02-12 16:27:55 +01:00
Johannes Millan
29541951a3 refactor(sync): increase MAX_VECTOR_CLOCK_SIZE from 10 to 30 and remove defense layers
At MAX=10, pruning triggered frequently enough (11+ unique client IDs from
reinstalls/new browsers) to require 4 defense layers compensating for
information loss: pruning-aware comparison, protected client IDs with
migration, isLikelyPruningArtifact heuristic, and same-client check.

At MAX=30, pruning almost never triggers (needs 31+ unique client IDs).
A 30-entry clock is ~500 bytes — negligible bandwidth. This allows removing
most defense layers while keeping two cheap backward-compat checks for old
10-entry pruned data still on servers.

Removed:
- Pruning-aware mode in compareVectorClocks (standard comparison now)
- Protected client IDs mechanism (storage, migration, preservation)
- selectProtectedClientIds function
- Clock normalization in SyncImportFilterService

Kept temporarily (backward compat with old 10-entry data):
- isLikelyPruningArtifact with LEGACY_MAX=10
- Same-client check (always mathematically correct)
2026-02-12 16:27:55 +01:00
Johannes Millan
48924428c6 docs(sync): rewrite vector clocks architecture document from scratch
Replace the scattered, contradictory document with a coherent 13-section
architecture reference covering the full vector clock system: core
operations, pruning, conflict detection, SYNC_IMPORT filtering, defense
layers against pruning artifacts, and step-by-step scenario traces.
2026-02-12 16:27:55 +01:00
Johannes Millan
4a779a0218 fix(sync): replace vector clock on remote SYNC_IMPORT instead of merging
When a client with an established vector clock (10+ entries) received a
remote SYNC_IMPORT/BACKUP_IMPORT with a fresh clock, mergeRemoteOpClocks()
merged the import's clock into the old clock instead of replacing it.
This caused clock bloat (11+ entries), which led to server-side pruning
dropping the import's entry (lowest counter). Other clients then saw
these ops as CONCURRENT with the import and discarded them.

Fix: In mergeRemoteOpClocks(), when a full-state op is present, use its
clock as the base instead of the existing local clock. Regular ops
continue to merge normally.
2026-02-12 16:27:55 +01:00
Johannes Millan
fc56aabec4 docs(sync): fix stale DoS cap references from 3x to 5x MAX_VECTOR_CLOCK_SIZE
The sanitizeVectorClock() DoS cap was changed to 5x MAX (50 entries) but
comments in CLAUDE.md, vector-clocks.md, sync.types.ts, and
validation.service.ts still referenced the old 3x MAX (30) value.
2026-02-10 20:38:32 +01:00
Johannes Millan
13dc7a988a fix(sync): deduplicate retry budget counting per entity per batch
The retry counter incremented per-op instead of per-entity per cycle.
Multiple ops for the same entity in one batch would burn through all
MAX_CONCURRENT_RESOLUTION_ATTEMPTS immediately, causing permanent
rejection on the first sync cycle instead of allowing 3 retry cycles.

Also uses toEntityKey utility instead of manual string construction
and fixes docs/code mismatch (>= vs ===) for pruning-aware comparison.
2026-02-10 14:41:16 +01:00
Johannes Millan
c112b65d64 docs(sync): document pruning artifact heuristic and add rejection counter tests
Document the _isLikelyPruningArtifact() heuristic in vector-clocks.md
and add 3 tests for per-entity rejection counter edge cases.
2026-02-09 17:55:12 +01:00
Johannes Millan
fdc942babb
fix(sync): prevent infinite loop when concurrent modification resolution keeps failing (#6434)
* fix(sync): prevent infinite loop when concurrent modification resolution keeps failing

When vector clock pruning makes it impossible to create a dominating clock
(e.g., entity clock has MAX entries and client ID isn't among them), the cycle
"upload → CONFLICT_CONCURRENT → merge clocks → upload → reject again" repeats
endlessly. This adds a per-entity retry counter (MAX_CONCURRENT_RESOLUTION_ATTEMPTS=3)
that permanently rejects ops after exceeding the limit, breaking the sync loop.

The counter resets when a sync cycle completes with no rejections (healthy state).

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* fix(sync): move vector clock pruning after conflict detection to fix root cause

The infinite sync loop happens because it's mathematically impossible to build
a dominating clock with MAX_VECTOR_CLOCK_SIZE entries when the entity's clock
already has MAX entries and the client's ID isn't among them. The merged clock
needs MAX+1 entries (all entity clock IDs + client ID), but client-side pruning
drops one entity clock ID. The server's pruning-aware comparison then sees the
dropped key as non-shared and returns CONCURRENT instead of GREATER_THAN.

Fix: Move limitVectorClockSize from validation (before comparison) to
processOperation (after comparison, before storage). The full unpruned clock
is now used for conflict detection — all entity clock IDs are present so
bOnlyCount=0 → GREATER_THAN. Storage still gets the pruned clock.

Client-side: Stop pruning in SupersededOperationResolverService. The server
handles pruning after conflict detection.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* fix(sync): tighten vector clock sanitize limit from 100 to 3x MAX_VECTOR_CLOCK_SIZE

The old sanitize cap of 100 entries was unnecessarily wide. Since conflict
resolution clocks are at most ~12-15 entries (entity clock MAX=10 + client ID
+ a few merged), cap at 3x MAX (30) for DoS protection while leaving ample
room for legitimate clocks.

Also update server-side pruning tests to use realistic clock sizes (20 entries
instead of 50) to stay within the new sanitize limit.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* docs(sync): document vector clock pruning invariant and infinite loop fix

- Add "Pruning and the Pruning-Aware Comparison" section to vector-clocks.md
  explaining the critical invariant: server prunes AFTER comparison, not before
- Add rule 13 to CLAUDE.md to prevent future regressions
- Update conflict resolution key files table with rejected-ops-handler and
  superseded-operation-resolver services

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* docs(sync): update last-updated date in conflict resolution docs

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* test(sync): update pruning tests to reflect server-side pruning design

Client no longer prunes vector clocks during conflict resolution — the
server handles pruning after conflict detection. Tests now verify the
merged clock is sent unpruned with all keys preserved.

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

* test(sync): fix client-side pruning tests and add server-side regression test

- Update 7 SupersededOperationResolverService tests to verify client
  does NOT prune (server handles pruning after conflict detection)
- Remove redundant `newClock` alias in superseded-operation-resolver
- Add regression test: MAX+1 entry clock accepted as GREATER_THAN
  when it dominates a MAX entry entity clock (the core infinite loop fix)

https://claude.ai/code/session_016RAxms5dTouU98wFNQaAcv

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-09 12:01:43 +01:00
Johannes Millan
02d5861ac9 docs: add plan 2026-02-07 13:05:11 +01:00
Johannes Millan
985e839747 fix(tests): improve synchronization tests and increase timeout for IndexedDB operations 2026-02-06 20:10:21 +01:00
Johannes Millan
cfc43afc24 docs: add plans 2026-02-06 18:43:43 +01:00
Johannes Millan
d75cc00da8
docs: Add recurring events research and implementation plan (#6375)
* docs(research): add recurring events industry standards analysis

Comprehensive research comparing Super Productivity's recurring task
implementation against RFC 5545 RRULE standard and major applications
(Google Calendar, Todoist, Things 3, TickTick).

Key findings:
- Current implementation covers basic patterns but lacks nth weekday,
  last day of month, and end conditions (COUNT/UNTIL)
- Recommends adopting rrule.js library for RFC 5545 compliance
- Proposes incremental migration path preserving existing functionality
- Notes "after completion" mode as competitive advantage to preserve

https://claude.ai/code/session_01Rhuxtn9JKKhh4J3iLApaWX

* docs(research): add gap analysis and implementation plan for recurring events

Gap analysis compares current TaskRepeatCfg model against RFC 5545 RRULE
and major applications (Google Calendar, Todoist, Things 3, TickTick).

Implementation plan details 4-phase approach:
- Phase 1: Add rrule.js, create DST-safe wrappers
- Phase 2: Enable new patterns (nth weekday, last day, end conditions)
- Phase 3: Lazy migration strategy
- Phase 4: Natural language display, iCal export

https://claude.ai/code/session_01Rhuxtn9JKKhh4J3iLApaWX

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-05 15:32:44 +01:00
Johannes Millan
4d22a64955
Feat/plugin UI kit (#6362)
* fix(e2e): stabilize undo task delete sync test

Two flakiness sources fixed:
- Click on task element could activate title inline editor, causing
  Backspace to edit text instead of triggering delete. Now clicks the
  drag handle which calls focusSelf() without entering edit mode.
- Replaced deleteTask helper with inline sequence to avoid wasting
  2s of the 5s undo snackbar window on dialog-detection timeout.

* refactor: address code review findings from 2026-02-03

- Extract getBreakCycle helper to replace error-prone `cycle - 1 || 1`
  pattern at 3 call sites
- Add clarifying comment on intentionally broad 'timed out' match
- Reduce Pomodoro E2E test from 9 to 5 sessions (sufficient coverage)
- Remove dead _isTransientNetworkError wrapper from DropboxApi
- Extract stubWindowConfirm helper in task reducer tests

* fix(sync): prevent Formly from clearing provider config on show (#6345)

resetOnHide: true caused Formly to reset field values when provider
fieldGroups transitioned from hidden to visible, discarding user input
if sync was enabled before selecting a provider.

* fix(tasks): fix huge space between emoji and text in tag/project menus

Use matMenuItemIcon attribute on emoji spans so they project into the
icon slot of mat-menu-item instead of the text slot. Update emoji icon
sizing to 24x24px to match mat-icon and add overflow: hidden.

Closes #5977

* fix(tasks): guard against undefined task entities in selectors and archive (#6359)

Prevent TypeError crashes (reading 'dueWithTime', 'dueDay', 'issueProviderId') caused
by orphaned IDs in NgRx state. Fix archive merge to deduplicate IDs, filter orphans,
and use correct entity precedence (young over old). Add defensive null guards to
selectors and archive/task service methods.

* fix(tasks): guard against undefined task in mainListTasksInProject$ (#6360)

* fix(tasks): detect and sanitize orphaned task IDs to prevent startup crashes (#6359, #6360)

Orphaned task IDs (entries in task.ids without matching entities) caused
TypeError on app startup. Fix addresses three layers: validation now
flags orphaned IDs instead of silently skipping them, loadAllData
sanitizes IDs on load as a safety net, and data repair no longer crashes
when encountering orphaned IDs it's trying to fix.

* fix(sync): prevent recurring task duplication across clients

Remove SuperSync special-case that bypassed initial sync wait, causing
repeatable task effects to fire before sync completed. Add post-sync
cleanup effect that detects and removes stale duplicate repeat instances
when multiple active instances exist for the same repeat config.

* fix(sync): restore WebDAV provider compatibility warning text

* feat(sync): mark WebDAV and LocalFile sync options as experimental

* feat(plugins): add UI Kit with inject-first CSS strategy for iframe plugins

Introduce a lightweight CSS reset (UI Kit) that auto-styles basic HTML
elements in plugin iframes to match the host app theme. Injected after
<head> so plugin styles always win by source order.

UI Kit provides: element resets (body, headings, buttons, inputs, tables,
links, code, lists, hr), .btn-primary/.btn-outline button variants, and
.card/.card-clickable components.

All bundled plugins updated to use UI Kit classes, removing redundant
custom CSS (-542 lines net). Pico CSS removed from automations plugin.
sync-md converted from hardcoded colors to host theme variables.

* feat(plugins): extract shared CSS utilities into UI Kit

Move .text-muted, .text-primary, .page-fade and @keyframes fadeIn from
plugin CSS into the UI Kit so all iframe plugins get them automatically.
Add box-shadow focus ring to input:focus for better accessibility.
Remove per-plugin focus overrides now covered by the UI Kit.
2026-02-04 18:18:22 +01:00
Johannes Millan
d1f766d3a3 docs: add new plans 2026-02-04 17:15:14 +01:00
Corey Newton
343fc47d1d docs(wiki): lint style 2026-02-04 14:45:00 +01:00
Corey Newton
5f1dd7ef7f docs(wiki): normalize tables and rework ToC 2026-02-04 14:45:00 +01:00
Corey Newton
ff674fc6c9 docs(wiki): substantial addition of integrations (issue and sync)
Much of these notes will need additional validation prior to v1.0 as I have not yet used supersync and many of the other services.
2026-02-04 14:45:00 +01:00
Corey Newton
8557ce3595 docs(wiki): enhance User Data documentation with backup and import/export details 2026-02-04 14:45:00 +01:00
Corey Newton
daa5cea0f6 docs(wiki): add new notes for Quick History and Worklog 2026-02-04 14:45:00 +01:00