Skip to content

Track and restore latest URL#2190

Merged
myieye merged 15 commits intodevelopfrom
claude/track-url-session-restore-9Wd2q
Mar 12, 2026
Merged

Track and restore latest URL#2190
myieye merged 15 commits intodevelopfrom
claude/track-url-session-restore-9Wd2q

Conversation

@myieye
Copy link
Collaborator

@myieye myieye commented Mar 3, 2026

Resolves #2210

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

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

This PR implements server-side JSON file-backed preferences storage and integrates URL persistence across the application. It adds a new JsonFilePreferencesService, introduces preference key enumeration, updates app startup to restore last URLs, creates reactive storage utilities for frontend persistence, and replaces localStorage-based preferences with service-backed storage.

Changes

Cohort / File(s) Summary
Backend Preferences Service Implementation
backend/FwLite/FwLiteShared/Services/JsonFilePreferencesService.cs, backend/FwLite/FwLiteShared/Services/PreferenceKey.cs
New JSON file-backed preferences service with thread-safe in-memory caching, atomic save operations, and corresponding PreferenceKey enum with AppLastUrl member.
Backend Integration & Service Registration
backend/FwLite/FwLiteMaui/App.xaml.cs, backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs, backend/FwLite/FwLiteWeb/Program.cs, backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs
Injects IPreferencesService into App constructor to restore last URL on startup; registers JsonFilePreferencesService in DI container; updates browser launch logic to use saved URL; exports PreferenceKey enum to TypeScript.
Frontend Storage & State Management Utilities
frontend/viewer/src/lib/utils/storage-prop.svelte.ts, frontend/viewer/src/lib/utils/app-storage.svelte.ts, frontend/viewer/src/lib/utils/project-storage.svelte.ts
Introduces StorageProp class for reactive async-persisted storage values; adds app-storage singleton for tracking last URL; refactors project-storage to use new project-scoped StorageProp pattern instead of localStorage.
Frontend Route Tracking & Service API
frontend/viewer/src/lib/services/service-provider.ts, frontend/viewer/src/AppRoutes.svelte
Changes tryUsePreferencesService to usePreferencesService (non-undefined return); adds runtime URL tracking via debounced pushState/replaceState/popstate handlers to persist current pathname+query+hash.
Generated TypeScript Types
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/PreferenceKey.ts, frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/index.ts
Generates TypeScript enum PreferenceKey with AppLastUrl member; adds re-export in Services index.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Handles IPreferencesService wiring and TS type generation shared with MAUI/localStorage implementations (#2158)
  • Refactors project-scoped storage architecture to use reactive StorageProp pattern for task selection persistence (#2142)
  • Modifies frontend routing/URL initialization logic for persistent state restoration across sessions (#2018)

Suggested labels

🟨Medium

Suggested reviewers

  • rmunn
  • imnasnainaec

Poem

🐰 A rabbit's delight in persistent paths!
URLs remembered, no second lapse,
JSON files hold preferences dear,
Reactive storage keeps configs near,
Click, save, reload—same place reappears! 📍✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully meets issue #2189 objectives: introduces JsonFilePreferencesService backend implementation [App.xaml.cs, JsonFilePreferencesService.cs, FwLiteWebKernel.cs], enables server-side preference persistence with shared PreferenceKey enum [PreferenceKey.cs, ReinforcedFwLiteTypingConfig.cs], integrates URL restoration logic across backend and frontend [Program.cs, AppRoutes.svelte, app-storage.svelte.ts], and replaces localStorage with backend-backed approach [storage-prop.svelte.ts, project-storage.svelte.ts].
Out of Scope Changes check ✅ Passed All changes are within scope of issue #2189: JSON-file preferences backend for Linux, preference key infrastructure, URL persistence and restoration across restarts, and shared type definitions between C# and TypeScript.
Title check ✅ Passed The title 'Track and restore latest URL' accurately summarizes the main change: implementing URL tracking and restoration functionality across app restarts, which is the core objective of the PR.
Description check ✅ Passed The pull request description 'Resolves #2210' is directly related to the changeset, which implements JSON-file-backed preferences for user URL restoration.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/track-url-session-restore-9Wd2q
📝 Coding Plan for PR comments
  • Generate coding plan

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 Mar 3, 2026

UI unit Tests

  1 files  ±0   54 suites  ±0   28s ⏱️ +4s
140 tests ±0  140 ✅ ±0  0 💤 ±0  0 ❌ ±0 
207 runs  ±0  207 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit bc56c5f. ± Comparison against base commit 626dc12.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

C# Unit Tests

165 tests  +3   165 ✅ +3   18s ⏱️ -1s
 23 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit bc56c5f. ± Comparison against base commit 626dc12.

♻️ This comment has been updated with latest results.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
frontend/viewer/src/AppRoutes.svelte (1)

25-28: Avoid magic number for debounce delay.

200 should be a named constant so this behavior is easier to tune and reason about.

💡 Suggested tweak
+  const URL_SAVE_DEBOUNCE_MS = 200;
   onMount(() => {
     let timeout: ReturnType<typeof setTimeout>;
     const saveUrl = () => {
       clearTimeout(timeout);
       timeout = setTimeout(() => {
         const { pathname, search, hash } = document.location;
         void appStorage.lastUrl.set(pathname + search + hash);
-      }, 200);
+      }, URL_SAVE_DEBOUNCE_MS);
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/viewer/src/AppRoutes.svelte` around lines 25 - 28, Replace the magic
number 200 with a named constant (e.g., URL_SAVE_DEBOUNCE_MS) declared in module
scope of AppRoutes.svelte and use that constant when creating the timeout;
update the timeout logic that references the variable timeout and the call to
appStorage.lastUrl.set(pathname + search + hash) to use the new constant so the
debounce delay is easy to find and tune.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/FwLite/FwLiteShared/Services/JsonFilePreferencesService.cs`:
- Around line 76-90: Save() currently catches and logs all exceptions, causing
Set()/Remove() to appear successful even when disk writes fail; change Save() to
surface failures instead of swallowing them by either rethrowing the caught
exception after logging (throw;) or returning a failure result that callers must
check, and update Set() and Remove() to propagate that failure (i.e., throw on
Save failure or return/propagate a false result) so callers get an exception or
error when File.WriteAllText/File.Move fails; reference Save(), Set(), Remove(),
_logger and _filePath when making the change.

In `@frontend/viewer/src/lib/utils/storage-prop.svelte.ts`:
- Line 27: The constructor currently calls void this.load() and other spots
(lines ~48-54) fire-and-forget the async load which can leave this.loading true
and produce unhandled rejections if backend.get() rejects; update the code so
the load() promise is observed and errors are handled: either add a .catch(...)
to the void this.load() call(s) in the constructor and at the other
fire-and-forget sites to log/handle the error, and/or modify the load() method
(the function named load that calls backend.get()) to wrap its await in
try/catch and a finally that always sets this.loading = false; ensure references
to backend.get() remain and use the class method names (constructor, load) so
the loading flag cannot remain true and no unhandled rejection escapes.

---

Nitpick comments:
In `@frontend/viewer/src/AppRoutes.svelte`:
- Around line 25-28: Replace the magic number 200 with a named constant (e.g.,
URL_SAVE_DEBOUNCE_MS) declared in module scope of AppRoutes.svelte and use that
constant when creating the timeout; update the timeout logic that references the
variable timeout and the call to appStorage.lastUrl.set(pathname + search +
hash) to use the new constant so the debounce delay is easy to find and tune.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc02e1c and ab65466.

📒 Files selected for processing (13)
  • backend/FwLite/FwLiteMaui/App.xaml.cs
  • backend/FwLite/FwLiteShared/Services/JsonFilePreferencesService.cs
  • backend/FwLite/FwLiteShared/Services/PreferenceKey.cs
  • backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs
  • backend/FwLite/FwLiteWeb/FwLiteWebKernel.cs
  • backend/FwLite/FwLiteWeb/Program.cs
  • frontend/viewer/src/AppRoutes.svelte
  • frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/PreferenceKey.ts
  • frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/index.ts
  • frontend/viewer/src/lib/services/service-provider.ts
  • frontend/viewer/src/lib/utils/app-storage.svelte.ts
  • frontend/viewer/src/lib/utils/project-storage.svelte.ts
  • frontend/viewer/src/lib/utils/storage-prop.svelte.ts

@argos-ci
Copy link

argos-ci bot commented Mar 3, 2026

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

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Mar 12, 2026, 10:23 AM

@myieye myieye changed the title Use JSON file for user preferences on Linux Track and restore latest URL Mar 3, 2026
@myieye myieye changed the base branch from develop to use-json-file-for-preferences-on-linux March 3, 2026 16:49
@myieye myieye force-pushed the claude/track-url-session-restore-9Wd2q branch from ab65466 to 1545e20 Compare March 3, 2026 16:50
@myieye myieye marked this pull request as draft March 3, 2026 16:51
@myieye myieye force-pushed the use-json-file-for-preferences-on-linux branch from 8ba07d0 to fb7c92c Compare March 4, 2026 07:46
@myieye myieye force-pushed the claude/track-url-session-restore-9Wd2q branch from 1545e20 to 5f944e1 Compare March 4, 2026 08:00
Base automatically changed from use-json-file-for-preferences-on-linux to develop March 4, 2026 13:45
myieye and others added 6 commits March 10, 2026 16:35
- Listen for hashchange events in url-tracker (fragment-only
  navigations like #sense links don't fire pushState/replaceState)
- Remove catch in StorageProp.load() — let global error handler
  surface failures instead of silently warning
- Include linter fixes: readonly _cache, static JsonSerializerOptions,
  collection expression syntax

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
@myieye myieye force-pushed the claude/track-url-session-restore-9Wd2q branch from 18fca29 to 0760e11 Compare March 10, 2026 16:35
claude added 4 commits March 11, 2026 16:01
The trackUrl feature added initAppStorage() to AppRoutes, which requires
a PreferencesService. The demo setup used by Playwright tests was missing
this service registration, causing all tests to crash on startup.

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
When running without a .NET host (e.g. Vite dev server, demo, tests),
app-level services like PreferencesService were not available early
enough — AppRoutes calls initAppStorage() before any route component
can register mocks. Now main.ts detects whether FwLiteProvider was set
by dotnet and, if not, registers browser-local implementations (e.g.
localStorage-backed PreferencesService) before mounting the app.

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
…vices

The hardcoded no-op JsEventListener default in LexboxServiceProvider
silently masked missing service registrations. Now it lives alongside
the browser PreferencesService in setupBrowserAppServices(), making
the contract explicit: dotnet must provide the real one, and the
browser-only path gets the no-op.

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
Storybook runs without a dotnet host, so it needs browser app services
(JsEventListener, PreferencesService) registered before InMemoryDemoApi
setup, just like main.ts does.

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
myieye and others added 5 commits March 12, 2026 10:52
…stored URL

- Rename isDotnetHosted → IsDotnetHosted (PascalCase to match Lexbox
  interface convention) and make it optional (undefined = not dotnet
  hosted), removing the redundant explicit false from setupServiceProvider
- Fix bind/apply redundancy in url-tracker.ts: origPushState is already
  bound via .bind(history), so .apply(this, args) is misleading — use
  spread instead
- Validate stored lastUrl starts with '/' before using it in both
  FwLiteWeb/Program.cs and FwLiteMaui/App.xaml.cs, guarding against
  corrupt preference values

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
- Restore missing closing braces from module script functions
- Remove duplicate setupBrowserAppServices() call
- Use camelCase local variable isDotnetHosted with explicit IsDotnetHosted
  property assignment to satisfy eslint naming-convention rule

https://claude.ai/code/session_01JSLxGWSPJ55fLLLb5CKQye
@myieye myieye marked this pull request as ready for review March 12, 2026 11:21
@myieye myieye merged commit 4d69c6a into develop Mar 12, 2026
27 checks passed
@myieye myieye deleted the claude/track-url-session-restore-9Wd2q branch March 12, 2026 15:31
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Let user pick up where they left off

2 participants