Skip to content

Refactor entries list with clean service architecture#2147

Closed
myieye wants to merge 66 commits intodevelopfrom
claude/refactor-entries-service-m4vT3
Closed

Refactor entries list with clean service architecture#2147
myieye wants to merge 66 commits intodevelopfrom
claude/refactor-entries-service-m4vT3

Conversation

@myieye
Copy link
Collaborator

@myieye myieye commented Jan 31, 2026

Extracts entry data management from EntriesList.svelte into dedicated
services with two implementation options:

Option 1 (Class-based): entries-service.svelte.ts + EntriesList.svelte

  • EntriesService class handles fetch, cache, and event subscriptions
  • Consistent with other services in codebase (PartOfSpeechService, etc.)
  • Clear separation: service manages data, component handles UI

Option 2 (Functional): use-entries.svelte.ts + EntriesList.functional.svelte

  • useEntries hook for a more functional composition style
  • Includes useVirtualListNavigation helper
  • Alternative pattern for comparison

Key improvements:

  • Immutable updates (no array splicing)
  • Race condition handling with fetch ID tracking
  • Debounced loading state to prevent UI flicker
  • Clean reactive flow: query params → fetch → entries → view
  • Event bus handlers for real-time updates
  • View-specific filtering (FwLite) cleanly separated

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN

@github-actions github-actions bot added the 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related label Jan 31, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

The changes introduce a modular, hook-based architecture for entry management in the browse view. Three new utility modules—use-entries.svelte.ts, entries-store.svelte.ts, and entries-service.svelte.ts—establish a layered service and store pattern. A new functional component variant (EntriesList.functional.svelte) leverages these composables for data fetching, navigation, and selection. The original EntriesList.svelte is rewritten to be store-driven, replacing manual data-fetch logic with store-backed query synchronization.

Changes

Cohort / File(s) Summary
New Composable Hooks
frontend/viewer/src/project/browse/use-entries.svelte.ts, frontend/viewer/src/project/browse/entries-store.svelte.ts, frontend/viewer/src/project/browse/entries-service.svelte.ts
Introduces new service and store layers with debounced data fetching, race-condition guards (fetchId), event bus integration for entry updates/deletions, and lite-view filtering. Exports composable hooks (useEntries, useVirtualListNavigation) and store factory (createEntriesStore).
Component Updates
frontend/viewer/src/project/browse/EntriesList.svelte, frontend/viewer/src/project/browse/EntriesList.functional.svelte
Rewrites EntriesList.svelte to lean on store-driven state; introduces new EntriesList.functional.svelte variant using composable hooks. Both implement virtual list rendering, entry selection management, create-entry workflows, and export selectNextEntry() navigation method.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

💻 FW Lite

Suggested reviewers

  • hahn-kev
  • imnasnainaec

Poem

🐰 A rabbit hops through entries anew,
With hooks and stores, a cleaner view,
No stale fetches shall clog the way,
Virtual lists scroll smooth all day,
Debounced and deft, the data flows true! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Refactor entries list with clean service architecture' directly and accurately describes the main objective of the changeset—extracting entry data management into dedicated service modules with a clean architecture.
Description check ✅ Passed The description comprehensively covers both implementation options (class-based and functional), explains key architectural improvements, and contextualizes the refactoring work within the broader codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/refactor-entries-service-m4vT3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 31, 2026

UI unit Tests

  1 files   50 suites   23s ⏱️
137 tests 137 ✅ 0 💤 0 ❌
202 runs  202 ✅ 0 💤 0 ❌

Results for commit 9f7fe15.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 31, 2026

C# Unit Tests

146 tests   146 ✅  20s ⏱️
 22 suites    0 💤
  1 files      0 ❌

Results for commit 9f7fe15.

♻️ This comment has been updated with latest results.

@myieye myieye force-pushed the claude/refactor-entries-service-m4vT3 branch from f2c3d64 to a2d69e2 Compare January 31, 2026 14:26
@github-actions github-actions bot added the 📦 Lexbox issues related to any server side code, fw-headless included label Jan 31, 2026
@argos-ci
Copy link

argos-ci bot commented Jan 31, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ⚠️ Changes detected (Review) 6 changed Feb 3, 2026, 4:23 PM

@myieye myieye marked this pull request as draft February 2, 2026 14:37
myieye and others added 26 commits February 3, 2026 15:20
Use watch() to handle cleanup of previous entryLoader instance
instead of referencing entryLoader inside its own $derived.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Restructured the on-demand entry loader with cleaner architecture:

1. Extracted EntryCache class
   - Encapsulates all cache state (#entries, #idToIndex, #pending, #loaded)
   - Single responsibility: cache operations only
   - Clear API: getByIndex, storeBatch, isBatchLoaded, etc.

2. Extracted ViewportBatchTracker class
   - Tracks which batches the UI is currently viewing
   - Simplified from confusing #recentBatchNumbers object
   - Clear semantics: markAccessed(), getRelevantBatches()

3. Extracted QuietResetDebouncer class
   - Handles the coalescing of rapid quiet reset requests
   - Encapsulates the debounce/inflight promise logic
   - Configurable DEBOUNCE_MS constant

4. Simplified main EntryLoaderService
   - Now orchestrates the extracted components
   - Generation checks are localized and consistent
   - Better method organization by concern

All 74 tests pass - functionality fully preserved.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
Replace separate quiet/full reset paths with a single priority-based
ResetQueue that coalesces reset requests:
- FILTER priority: User filter changes (show loading, 300ms debounce)
- EVENT priority: Entry events (no loading, 600ms debounce)

Key improvements:
- Higher priority resets override pending lower priority ones
- Single #executeReset method handles both reset types
- Cleaner generation tracking in finally blocks
- Removed QuietResetDebouncer in favor of unified queue

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
Remove ugly polling loop (checking every 50ms) and replace with proper
promise-based debounce resolution:
- #debounceResolvers array collects promises waiting for debounce
- #resolveDebounce() resolves all waiters when timer fires
- #waitForDebounce() returns immediately if no timer, else waits

This is cleaner and more efficient than polling.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
- Add lodash.debounce dependency for robust debouncing
- Create reusable Debouncer class that wraps lodash.debounce with
  promise tracking for async workflows
- Refactor EntryLoaderService to use dual Debouncer pattern:
  - filterDebouncer (300ms) for search/sort/filter changes
  - eventDebouncer (600ms) for entry update/delete events
  - Filter resets cancel pending event resets (priority override)
- Remove loadInitialCount method (was only used for tests)
- Update tests to use reset() directly for race condition testing

The new architecture is cleaner:
- No custom ResetQueue class needed
- Standard lodash.debounce handles timing edge cases
- Debouncer utility is reusable elsewhere in the codebase

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
Replace the custom Debouncer utility with runed's built-in useDebounce,
which provides the same promise-based debouncing functionality. This
removes the lodash.debounce dependency and the custom wrapper class.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
- Remove premature generation bump and cache clear from reset()
- Generation now only bumped atomically AFTER data is fetched
- Add #filterResetInFlight to track executing filter resets
- quietReset() now waits for in-flight filter reset instead of
  starting an independent reset that could race

This restores the atomic swap behavior where totalCount and cache
are updated together, preventing skeleton count mismatches.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
Events that occur while a filter reset is in-flight would be lost
because we waited for the filter reset (which fetched data before
the event occurred). Now we track these events with a flag and
trigger a follow-up quiet reset after the filter reset completes.

This ensures entry updates/deletes are never silently dropped.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
- Add ASCII diagram documenting the reset flow and event queuing
- Initial load now calls #executeReset directly, skipping the 300ms
  debounce. Only subsequent filter changes are debounced.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
ASCII diagram replaced with Mermaid flowchart in ENTRY_LOADER_SERVICE.md
for better readability in GitHub/IDE markdown viewers.

https://claude.ai/code/session_01BcA6nLuRLkkaqaqNyYqnuN
@myieye myieye force-pushed the claude/refactor-entries-service-m4vT3 branch from 61ecdb1 to 98a95fa Compare February 3, 2026 14:27
@myieye myieye closed this Feb 3, 2026
@myieye myieye deleted the claude/refactor-entries-service-m4vT3 branch February 3, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related 📦 Lexbox issues related to any server side code, fw-headless included

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants