Skip to content

User idle detection and dynamic polling#59

Merged
0101 merged 24 commits into
mainfrom
user-idle
May 20, 2026
Merged

User idle detection and dynamic polling#59
0101 merged 24 commits into
mainfrom
user-idle

Conversation

@0101
Copy link
Copy Markdown
Owner

@0101 0101 commented Apr 8, 2026

Summary

Client-side idle detection with dynamic polling intervals — active users get fast updates, idle tabs poll less frequently.

Changes

  • Shared types: Add \ActivityLevel\ discriminated union (Active/Idle/DeepIdle) to \Types.fs\
  • Client idle detection: Track mouse/keyboard/scroll/touch activity in \App.fs; report activity level to server; adjust polling interval dynamically (5s active → 30s idle → 60s deep idle)
  • Server-side decay: \RefreshScheduler.fs\ decays client activity over time, only reports transitions, pure update function
  • API endpoint:
    eportActivity\ method via Fable.Remoting in \WorktreeApi.fs\
  • Visual indicator: Droopy eyelid SVG animation on worktree cards when Idle/DeepIdle
  • Spec: New \docs/spec/user-idle-detection.md; updated refresh intervals in \worktree-monitor.md\
  • Tests: 41 unit tests for idle detection logic in \IdleDetectionTests.fs\

Stats

14 files changed, 519 insertions, 62 deletions

0101 and others added 24 commits March 27, 2026 18:01
… method

Add [RequireQualifiedAccess] ActivityLevel DU (Active | Idle | DeepIdle) to
src/Shared/Types.fs. Add reportActivity: ActivityLevel -> Async<unit> to
IWorktreeApi record. Stub implementations in readOnlyApi and worktreeApi.
Add ActivityLevel tracking to client Model with LastActivityTime.
Add UserActivity message with throttled activity subscription.
Add computeActivityLevel pure function (60s Idle, 15min DeepIdle).
Update Tick handler with activity transition detection.
Update pollingSubscription to use activity-level-based intervals.
Fix test files to pass ActivityLevel parameter.
…section

Replaced fixed interval table with cross-reference to user-idle-detection.md.
Added user-idle-detection.md to Related Specs section.
…ivity, timestamp/expiry, flatten intervalOf

- Send initial reportActivity(Active) on app startup (4or.2)
- Add ClientActivityAt timestamp to DashboardState and server-side timeout logic (4or.3)
- Refactor intervalOf from nested match to flat tuple pattern (4or.4)
- Report activity to server on every tick, not just transitions
  Fixes server decaying to Idle after 5min while user is active
- Pass timestamps via Msg payloads (Tick of float, UserActivity of float)
  instead of calling Date.now() in update handlers
- Update elmish-mvu-discipline rule to require pure update functions
- Update no-unnecessary-comments rule to allow section dividers in tests
- Idle (3min): lid ~25% closed with darker fill
- DeepIdle (15min): lid ~50% closed
- Removed opacity change on eye-closed for consistency
- Bumped idle threshold from 60s to 180s
The implementation uses 180s (3 min) for the idle threshold.
Update spec and boundary tests to match.
…ity, naming

- Only call reportActivity on activity level transitions, not every Tick
- Replace error callbacks with NoOp to prevent unbounded retry loop
- Use message payload timestamp instead of Date.now() in update
- Rename pollingSubscription to appSubscriptions
- Replace wildcard match with explicit ActivityLevel.Active case
- Update stale spec text for variable 1-15s polling cadence
- Delete 18 zero-value IntervalOfTests (flat lookup assertions)
# Conflicts:
#	src/Server/WorktreeApi.fs
#	src/Shared/Types.fs
# Conflicts:
#	src/Server/WorktreeApi.fs
#	src/Shared/Types.fs
@0101 0101 merged commit 71b3c92 into main May 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant