Skip to content

Sync state dialog/UI for FW Lite#1668

Merged
rmunn merged 54 commits into
developfrom
feat/fw-lite-sync-view
May 26, 2025
Merged

Sync state dialog/UI for FW Lite#1668
rmunn merged 54 commits into
developfrom
feat/fw-lite-sync-view

Conversation

@rmunn

@rmunn rmunn commented May 15, 2025

Copy link
Copy Markdown
Contributor

Fixes #1411.

Dialog fully functional, all numbers and dates are correct, sync buttons work.

image

@rmunn rmunn self-assigned this May 15, 2025
@coderabbitai

coderabbitai Bot commented May 15, 2025

Copy link
Copy Markdown

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.

📝 Walkthrough

Walkthrough

These changes introduce a new synchronization status API and UI dialog for projects. Backend services and data models are extended to expose sync status information, while the frontend adds a dialog component, supporting services, and type definitions to display and trigger sync actions. TypeScript and .NET types are updated for interop.

Changes

Files/Paths Change Summary
backend/FwLite/FwLiteShared/Projects/LexboxProjectService.cs, backend/FwLite/FwLiteShared/Sync/SyncService.cs Added async methods to fetch project sync status from Lexbox. SyncService now depends on IOptions<AuthConfig>.
backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs, frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/DotnetService.ts Added SyncService to the DotnetService enum and mapped it in the provider.
backend/FwLite/FwLiteShared/Services/ProjectServicesProvider.cs Modified ProjectScope to accept and manage a SyncServiceJsInvokable reference. Updated disposal logic and constructor signature.
backend/FwLite/FwLiteShared/Services/SyncServiceJsInvokable.cs Introduced new class exposing a JS-invokable method to get sync status via SyncService.
backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs Added export configuration for ProjectSyncStatusEnum and ProjectSyncStatus types for TypeScript interop.
backend/LexBoxApi/Controllers/SyncController.cs Added [RequireScope(LexboxAuthScope.SendAndReceive)] attribute for authorization.
backend/LexCore/Sync/SyncStatus.cs Decorated ProjectSyncStatusEnum and its property for string-based JSON serialization.
frontend/viewer/src/DotnetProjectView.svelte Integrated new syncService into project context setup.
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/IProjectScope.ts Added optional syncService property to IProjectScope interface.
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts Added new interface for sync status service with getSyncStatus method.
frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/IProjectSyncStatus.ts, frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/ProjectSyncStatusEnum.ts Added TypeScript interface and enum for project sync status.
frontend/viewer/src/lib/project-context.svelte.ts Extended ProjectContext to include an optional syncService property and related logic.
frontend/viewer/src/lib/services/service-provider.ts Registered new sync and history services in the service registry type.
frontend/viewer/src/lib/services/sync-status-service.ts Added a new service for accessing sync status from the project context.
frontend/viewer/src/project/ProjectSidebar.svelte Replaced static sync button with new SyncDialog component and logic to open it.
frontend/viewer/src/project/SyncDialog.svelte Introduced a dialog component to display sync status, show counts/timestamps, and trigger sync actions.

Assessment against linked issues

Objective Addressed Explanation
New Lexbox APIs: return current sync status to FW Lite; trigger fw headless sync (#1411)
UI: Dialog for displaying status, buttons to trigger sync (#1411)
FW Lite services: fetch sync status from Lexbox, manual trigger, return unsynced changes (#1411)
Show sync state in project view UI (#1411)

Poem

🐇
In the warren of code, a dialog appears,
Showing sync status to calm all our fears.
With buttons to press and statuses bright,
We hop through our projects, syncing just right.
Backend and frontend, now work hand in paw—
The sync bunny smiles, for all is in awe!


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions

github-actions Bot commented May 15, 2025

Copy link
Copy Markdown
Contributor

UI unit Tests

12 tests  ±0   12 ✅ ±0   0s ⏱️ ±0s
 4 suites ±0    0 💤 ±0 
 1 files   ±0    0 ❌ ±0 

Results for commit 9b05b6c. ± Comparison against base commit 3561600.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented May 15, 2025

Copy link
Copy Markdown
Contributor

C# Unit Tests

116 tests  ±0   116 ✅ ±0   10s ⏱️ ±0s
 17 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 9b05b6c. ± Comparison against base commit 3561600.

♻️ This comment has been updated with latest results.

@rmunn rmunn marked this pull request as ready for review May 20, 2025 10:08
@rmunn rmunn requested review from hahn-kev and myieye May 20, 2025 10:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (1)
frontend/viewer/src/project/ProjectSidebar.svelte (1)

90-105: 🛠️ Refactor suggestion

Potential improvement for sync dialog integration

The integration of the SyncDialog component is good, but there are a couple of improvements that could be made:

  1. The sync indicator (green/red dot) is still using the isSynchronizing state variable which doesn't appear to be connected to the actual sync status from the new service.
  2. The optional chaining in syncDialog?.open() is correct, but should be accompanied by a check that the component is properly initialized.
<SyncDialog
  bind:this={syncDialog}
  syncLbToLocal={() => console.log('Would sync Lexbox to local')}
  syncLbToFlex={() => console.log('Would sync Lexbox to FieldWorks')}
+  on:syncStateChange={(e) => isSynchronizing = e.detail.isSyncing}
/>
-<Sidebar.MenuButton onclick={() => syncDialog?.open()} class="justify-between">
+<Sidebar.MenuButton 
+  onclick={() => {
+    if (syncDialog) {
+      syncDialog.open();
+    } else {
+      console.error('Sync dialog not initialized');
+    }
+  }} 
+  class="justify-between">
🧹 Nitpick comments (8)
frontend/viewer/src/lib/services/service-provider.ts (1)

18-125: Consider adding helper functions for the new services

I notice you've added the services to the registry, but unlike other services (e.g., useAuthService()), there are no corresponding helper functions like useHistoryService() or useSyncService(). Consider adding these if they would be useful in multiple components.

Example implementation:

+export function useHistoryService(): IHistoryServiceJsInvokable {
+  return window.lexbox.ServiceProvider.getService(DotnetService.HistoryService);
+}
+
+export function useSyncService(): ISyncServiceJsInvokable {
+  return window.lexbox.ServiceProvider.getService(DotnetService.SyncService);
+}
backend/FwLite/FwLiteShared/Projects/LexboxProjectService.cs (1)

107-120: Implement consistent error handling with retry mechanism.

The error handling is appropriate, but consider implementing a retry mechanism for transient HTTP failures, which are common when making API calls.

 public async Task<ProjectSyncStatus?> GetLexboxSyncStatus(LexboxServer server, Guid projectId)
 {
     var httpClient = await clientFactory.GetClient(server).CreateHttpClient();
     if (httpClient is null) return null;
     try
     {
-        return (await httpClient.GetFromJsonAsync<ProjectSyncStatus?>($"/api/fw-lite/sync/status/{projectId}"));
+        // Add retry for transient failures
+        const int maxRetries = 3;
+        for (int i = 0; i < maxRetries; i++)
+        {
+            try 
+            {
+                return await httpClient.GetFromJsonAsync<ProjectSyncStatus?>($"/api/fw-lite/sync/status/{projectId}");
+            }
+            catch (HttpRequestException ex) when (i < maxRetries - 1 && (ex.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable || 
+                                                  ex.StatusCode == System.Net.HttpStatusCode.GatewayTimeout))
+            {
+                // Only retry on specific status codes indicating transient issues
+                await Task.Delay((i + 1) * 500); // Exponential backoff
+                logger.LogWarning(ex, "Retrying lexbox sync status request after transient failure (attempt {Attempt})", i + 1);
+            }
+        }
+        // Last attempt - let any exceptions propagate to the outer catch
+        return await httpClient.GetFromJsonAsync<ProjectSyncStatus?>($"/api/fw-lite/sync/status/{projectId}");
     }
     catch (Exception e)
     {
         logger.LogError(e, "Error getting lexbox sync status");
         return null;
     }
 }
backend/LexCore/Sync/SyncStatus.cs (1)

17-20: Consider adding XML documentation for properties.

The code functions correctly, but adding XML documentation comments would improve developer experience when working with this class.

 public record ProjectSyncStatus(
     [property:JsonConverter(typeof(JsonStringEnumConverter))]
     ProjectSyncStatusEnum status,
+    /// <summary>
+    /// Number of pending changes in the CRDT database that need to be synchronized.
+    /// </summary>
     int PendingCrdtChanges = 0,
+    /// <summary>
+    /// Number of pending Mercurial changes that need to be synchronized.
+    /// Will be -1 if there is no clone yet, meaning "all the commits, but unknown quantity".
+    /// </summary>
     int PendingMercurialChanges = 0, // Will be -1 if there is no clone yet; this means "all the commits, but we don't know how many there will be"
+    /// <summary>
+    /// Timestamp of the last CRDT commit that was synchronized.
+    /// </summary>
     DateTimeOffset? LastCrdtCommitDate = null,
+    /// <summary>
+    /// Timestamp of the last Mercurial commit that was synchronized.
+    /// </summary>
     DateTimeOffset? LastMercurialCommitDate = null)
backend/FwLite/FwLiteShared/Services/SyncServiceJsInvokable.cs (1)

1-14: Well-structured JavaScript-invokable service

The implementation correctly follows the pattern for exposing .NET methods to JavaScript. The class takes a SyncService dependency via constructor injection and exposes a clean API for the frontend to consume.

Consider adding exception handling to gracefully manage potential errors when calling syncService.GetSyncStatus(). This would help prevent uncaught exceptions from bubbling up to the JavaScript layer.

 [JSInvokable]
 public Task<ProjectSyncStatus?> GetSyncStatus()
 {
-    return syncService.GetSyncStatus();
+    try
+    {
+        return syncService.GetSyncStatus();
+    }
+    catch (Exception ex)
+    {
+        // Log the exception
+        Console.Error.WriteLine($"Error getting sync status: {ex.Message}");
+        return Task.FromResult<ProjectSyncStatus?>(null);
+    }
 }
frontend/viewer/src/lib/services/sync-status-service.ts (1)

10-19: Redundant constructor parameter

The constructor takes a parameter named projectContext with a private modifier, but then immediately assigns it to a private field #projectContext. This is redundant and could be simplified.

export class SyncStatusService {
  #projectContext: ProjectContext;
  get syncStatusApi(): ISyncServiceJsInvokable | undefined {
    return this.#projectContext.syncService;
  }

-  constructor(private projectContext: ProjectContext) {
-    this.#projectContext = projectContext;
+  constructor(projectContext: ProjectContext) {
+    this.#projectContext = projectContext;
  }
frontend/viewer/src/project/SyncDialog.svelte (3)

36-42: Address TODOs for tracking sync counts

Several placeholder values and TODOs indicate incomplete implementation of sync count tracking.

The code contains hardcoded zero values and TODOs about tracking local-to-LB and LB-to-local counts. Would you like assistance in determining how to properly track these counts based on the available API data?


51-52: Consider enhancing the loading UI

The TODO comment suggests the loading indicator needs improvement.

Consider implementing a loading overlay that maintains the dialog structure while showing the loading state:

{#if loading}
-  <!-- TODO: Show loading as an overlay? -->
-  <Loading />
+  <div class="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
+    <Loading />
+  </div>
+  <div class="opacity-50">
+    <!-- Add a placeholder/skeleton UI here -->
+    <div class="grid grid-rows-5 grid-cols-3 justify-around rounded-lg border-4">
+      <!-- Skeleton content -->
+    </div>
+  </div>
{:else if !status}

22-22: Address commented code and TODO

There's commented code with a TODO about finding the project ID.

Either implement the TODO or remove the commented code to keep the codebase clean:

-  // status = await service.getStatus('How do I find the project ID to use in the fallback?'); // TODO
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 784be48 and 1625f02.

📒 Files selected for processing (19)
  • backend/FwLite/FwLiteShared/Projects/LexboxProjectService.cs (2 hunks)
  • backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs (3 hunks)
  • backend/FwLite/FwLiteShared/Services/ProjectServicesProvider.cs (6 hunks)
  • backend/FwLite/FwLiteShared/Services/SyncServiceJsInvokable.cs (1 hunks)
  • backend/FwLite/FwLiteShared/Sync/SyncService.cs (3 hunks)
  • backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs (3 hunks)
  • backend/LexBoxApi/Controllers/SyncController.cs (2 hunks)
  • backend/LexCore/Sync/SyncStatus.cs (2 hunks)
  • frontend/viewer/src/DotnetProjectView.svelte (2 hunks)
  • frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/DotnetService.ts (1 hunks)
  • frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/IProjectScope.ts (1 hunks)
  • frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts (1 hunks)
  • frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/IProjectSyncStatus.ts (1 hunks)
  • frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/ProjectSyncStatusEnum.ts (1 hunks)
  • frontend/viewer/src/lib/project-context.svelte.ts (5 hunks)
  • frontend/viewer/src/lib/services/service-provider.ts (2 hunks)
  • frontend/viewer/src/lib/services/sync-status-service.ts (1 hunks)
  • frontend/viewer/src/project/ProjectSidebar.svelte (4 hunks)
  • frontend/viewer/src/project/SyncDialog.svelte (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
frontend/viewer/src/lib/services/service-provider.ts (2)
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/IHistoryServiceJsInvokable.ts (1)
  • IHistoryServiceJsInvokable (11-17)
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts (1)
  • ISyncServiceJsInvokable (8-11)
backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs (2)
backend/FwLite/FwLiteShared/Sync/SyncService.cs (1)
  • SyncService (19-184)
backend/FwLite/FwLiteShared/Services/SyncServiceJsInvokable.cs (1)
  • SyncServiceJsInvokable (7-14)
backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs (1)
backend/LexCore/Sync/SyncStatus.cs (1)
  • ProjectSyncStatus (25-33)
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts (1)
frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/IProjectSyncStatus.ts (1)
  • IProjectSyncStatus (8-18)
frontend/viewer/src/lib/project-context.svelte.ts (1)
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts (1)
  • ISyncServiceJsInvokable (8-11)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Publish FW Lite app for Android
  • GitHub Check: Publish FW Lite app for Windows
🔇 Additional comments (38)
frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/DotnetService.ts (1)

14-14: Addition of SyncService looks good

The SyncService enum value has been properly added to support the new synchronization functionality. This aligns with the PR's objective of creating a sync dialog/UI.

frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/IProjectScope.ts (1)

14-14: Optional syncService property has been properly added

The addition of the optional syncService property to the IProjectScope interface correctly follows the established pattern of other service references like historyService.

backend/LexBoxApi/Controllers/SyncController.cs (1)

4-4: Good security improvement with scope requirement

Adding the RequireScope attribute with SendAndReceive scope is an important security enhancement that ensures only authorized users can access the synchronization endpoints.

Also applies to: 14-14

frontend/viewer/src/lib/services/service-provider.ts (2)

18-19: Import of service interfaces looks good

The import of both IHistoryServiceJsInvokable and ISyncServiceJsInvokable interfaces is appropriate for type safety in the service registry.


29-30: Service registry entries properly added

The addition of registry entries for HistoryService and SyncService correctly maps to their respective interface types.

backend/FwLite/FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs (3)

7-7: Good addition of the namespace import.

The import of LexCore.Sync namespace is necessary to access the ProjectSyncStatusEnum and ProjectSyncStatus types being added to the TypeScript generation configuration.


108-108: Correctly configured enum export.

Adding ProjectSyncStatusEnum to be exported as a string enum is appropriate. Using .UseString() ensures the TypeScript enum will use string values instead of numeric indices, which matches the JSON serialization approach in the backend and improves readability in network debugging.


121-121: Correctly added type to exported interfaces.

Adding ProjectSyncStatus to the list of types exported as interfaces with public properties ensures the frontend can properly type-check against the synchronization status data structure returned by the backend.

backend/FwLite/FwLiteShared/Services/FwLiteProvider.cs (2)

48-48: Proper service type mapping.

The mapping from DotnetService.SyncService to typeof(SyncServiceJsInvokable) correctly integrates the new sync service with the existing service resolution infrastructure.


105-105: Good addition to DotnetService enum.

Adding SyncService to the DotnetService enum properly exposes the new service type to the frontend.

frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/ProjectSyncStatusEnum.ts (1)

1-12: Generated enum matches backend implementation.

This auto-generated TypeScript enum correctly represents the synchronization states from the backend. The string values match the enum values defined in the C# backend, ensuring consistent type safety across the stack.

frontend/viewer/src/DotnetProjectView.svelte (3)

4-4: Good updates to imports.

The imports are correctly updated to include DotnetService and ISyncServiceJsInvokable, which are necessary for initializing and typing the sync service.

Also applies to: 11-13


49-52: Proper initialization of sync service.

The code correctly initializes the syncService by checking if it exists in the project scope and then wraps it in a proxy using the appropriate service type. This follows the same pattern used for other services like historyService.


54-54: Correct integration with project context.

The project context setup is properly updated to include the new syncService, making it available to all components that use the project context.

frontend/viewer/src/lib/dotnet-types/generated-types/FwLiteShared/Services/ISyncServiceJsInvokable.ts (1)

6-11: Interface looks good with appropriate Promise return type.

The ISyncServiceJsInvokable interface correctly imports and uses the IProjectSyncStatus type, providing a clean contract for JavaScript interop with the backend sync service.

backend/FwLite/FwLiteShared/Sync/SyncService.cs (3)

1-11: Appropriate imports added for the new sync functionality.

The new imports for LexCore.Sync and Microsoft.Extensions.Options are correctly added to support the sync status functionality.


27-27: Constructor parameter added correctly.

The IOptions<AuthConfig> authOptions parameter is properly added to the constructor to support server configuration retrieval.


81-87: Well-structured sync status retrieval method.

The GetSyncStatus method is well-implemented with appropriate error handling by returning null when the status can't be retrieved. The code follows the existing patterns in the class.

backend/FwLite/FwLiteShared/Projects/LexboxProjectService.cs (1)

1-6: Appropriate imports added for HTTP JSON and sync types.

The added imports are necessary for the new sync status functionality and HTTP JSON operations.

backend/LexCore/Sync/SyncStatus.cs (2)

1-5: Added JSON serialization support correctly.

The addition of the JSON serialization namespace and converter ensures proper enum serialization in the API responses.


15-15: Proper JSON serialization for enum property.

The JsonConverter attribute ensures the enum values will be serialized as strings in JSON, which is better for cross-platform compatibility and readability.

frontend/viewer/src/project/ProjectSidebar.svelte (2)

18-18: Good addition of the SyncDialog import

The import is correctly placed with other component imports.


42-42: Properly defined reactive state variable

The reactive state variable correctly uses Svelte's $state decorator, matching the pattern used for other dialog components in this file.

frontend/viewer/src/lib/dotnet-types/generated-types/LexCore/Sync/IProjectSyncStatus.ts (1)

1-19: Auto-generated interface looks good

Since this is an auto-generated TypeScript interface, we shouldn't modify it directly. The structure correctly represents the C# ProjectSyncStatus class with appropriate property types.

Note that the recursive structure (where nested statuses are of the same type as the parent) could cause infinite recursion if not handled carefully when working with this data. Also, date fields are represented as strings and will need parsing to be used as Date objects in the UI.

Be mindful when working with the nested status properties (neverSynced, syncing, queuedToSync). If you print or iterate through this structure without limiting the depth, you could encounter a stack overflow or excessive memory usage.

frontend/viewer/src/lib/services/sync-status-service.ts (1)

1-9: Good service factory implementation

The factory function useSyncStatusService follows the pattern used for other services in the codebase. It correctly retrieves the project context and instantiates the service class.

frontend/viewer/src/lib/project-context.svelte.ts (6)

6-8: LGTM: ISyncServiceJsInvokable import addition

The import of the ISyncServiceJsInvokable interface is correctly structured as a named import with proper type annotation.


19-19: LGTM: syncService property added to ProjectContextSetup interface

The optional syncService property is correctly added to the ProjectContextSetup interface with the proper type.


39-39: LGTM: Private reactive state field added

The private #syncService field is properly declared using the $state directive, following the established pattern in this class.


68-70: LGTM: Public getter for syncService

The public getter follows the same pattern as other service getters in this class, returning the private field.


75-75: LGTM: Constructor initialization

The constructor correctly initializes #syncService from the optional args parameter.


84-84: LGTM: Setup method update

The setup method correctly updates the #syncService field from the args parameter.

backend/FwLite/FwLiteShared/Services/ProjectServicesProvider.cs (6)

64-66: LGTM: OpenCrdtProject signature updated

The OpenCrdtProject method now correctly creates and passes the SyncServiceJsInvokable instance to the ProjectScope constructor.


87-87: LGTM: OpenFwDataProject updated to pass null syncService

The OpenFwDataProject method now passes null for both historyService and syncService parameters, maintaining consistency with the updated ProjectScope constructor.


100-102: LGTM: ProjectScope constructor signature updated

The constructor signature is correctly extended to accept an optional SyncServiceJsInvokable parameter.


106-106: LGTM: SyncService initialization

The SyncService property is correctly initialized with a DotNetObjectReference if the syncService parameter is not null.


115-118: LGTM: SyncService disposal added

The cleanup delegate now properly disposes of the SyncService reference if it exists, following the same pattern as HistoryService disposal.


133-133: LGTM: SyncService property added

The public SyncService property is properly added to the ProjectScope class with the correct type.

frontend/viewer/src/project/SyncDialog.svelte (1)

1-11: LGTM: Component imports and structure

The imports are well-organized and include all necessary UI components, icons, dialog components, and utility modules needed for the sync dialog.

Comment thread backend/FwLite/FwLiteShared/Projects/LexboxProjectService.cs Outdated
Comment thread frontend/viewer/src/lib/services/sync-status-service.ts Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
@myieye

myieye commented May 20, 2025

Copy link
Copy Markdown
Collaborator

I played with the design a bit.
Once we're happy with it, I might restructure the HTML a bit more:

image

I couldn't really figure out how to test it.
I always got an auth error complaining that I didn't have the LexboxApi scope 🤔

@rmunn

rmunn commented May 21, 2025

Copy link
Copy Markdown
Contributor Author

I don't understand why the auth error is complaining about the LexboxApi scope when I clearly put [RequireScope(LexboxAuthScope.SendAndReceive)] on the SyncController class. I also had permission issues trying to test this, but oddly enough they went away after a few minutes of trying (?) after I had apparently changed nothing (?!?). It was really confusing. But try logging out of Lexbox (via the link in FW Lite) and logging back in, then waiting a few minutes before trying to sync again. At one point I theorized that Tilt was rebuilding a Kubernetes container behind the scenes but I was still connecting to the old container, not the new one where I had adjusted the OAuth scope requirement. But the .NET logs were both overly verbose and also lacking details that I needed (e.g. when I got a 401 or 403, I couldn't see the content of the 401 or 403 so I couldn't tell which scope it was complaining about — where did you see the message telling you which scope it wanted?), so I was struggling to understand the errors because I couldn't see the complete error messages.

Feature flag requirement was requiring Lexbox API scope, which conflicts
with the requirement for the SendAndReceive scope that we pass here.
Disable the feature flag requirement for now to allow testing the sync
dialog without OAuth errors.
@rmunn

rmunn commented May 21, 2025

Copy link
Copy Markdown
Contributor Author

NOTE: Revert commit c6db730 before merging, we don't want to remove the feature flag requirement when we actually push this.

@rmunn

rmunn commented May 23, 2025

Copy link
Copy Markdown
Contributor Author

Got correct sync date working, local sync button tested, everything looks good. Only flaw left is that after synchronizing, the notification popup shows on the page, muted by the dialog's overlay until you click Close. Screenshot demonstrating this:

image

I thought of auto-closing the dialog, but that might not be what the user expects? ... Actually, no, I think it is. After the sync returns a success, if all the values are 0, I think we should set a timeout of 750 milliseconds to auto-close the dialog, so that the user has just enough time to see that the numbers went to 0 before the dialog auto-closes itself and they see the notification at the bottom of the screen.

rmunn added 2 commits May 23, 2025 17:15
Arbitrarily picked 750 ms timeout, could configure that with prop
@rmunn

rmunn commented May 23, 2025

Copy link
Copy Markdown
Contributor Author

Commit c866494 auto-closes dialog 750 ms after a successful FW sync. Can easily revert that if it turns out to be a bad idea. I picked 750 ms because that's enough time to register that the numbers have become 0, but not so long that you're starting to move the mouse cursor over to the X button. Hopefully people will be pleasantly surprised that the dialog closes itself for them once they're done with it.

@myieye

myieye commented May 23, 2025

Copy link
Copy Markdown
Collaborator

I might have gotten a little carried away 😆

localhost_5137_project_elawa-dev-3-train-flex_browse_entryId.715b5801-0248-4643-aaf4-f57ebeedce6a.syncDialogOpen.true.-.Google.Chrome.2025-05-23.15-02-28.mp4

@myieye myieye left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is a whopping PR 💪.
As far as I can tell everything's working well! 🎉

@hahn-kev

Copy link
Copy Markdown
Collaborator

This looks great! Nice work Robin.
One minor thing I found, I took the server offline (so auto sync didn't do anything), then made a change, brought the server back online and the sync dialog looked like this:
image
one change not yet pushed to lexbox, and one change to sync to lexbox FLEx. Then after I clicked Auto Synchronizing the UI looked like this:
image
notice that the changes to push count updated, however the changes to sync with FLEx did not change. Closing and opening the dialog updated that value to 2 as expected. After a sync where the changes to push has changed we should also refresh the number of changes to push to FLEx.

@hahn-kev hahn-kev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

left some comments, one thing needs to be fixed, the rest are optional. Otherwise great job!

Comment thread backend/FwLite/FwLiteShared/Sync/SyncService.cs
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
Comment thread frontend/viewer/src/project/SyncDialog.svelte Outdated
rmunn added 4 commits May 26, 2025 12:21
To not have an HTTP connection hanging that gets closed down after 30
seconds, we leave it open for 25 seconds and then retry if we didn't
receive a response by that time, with a total configurable timeout
defaulting to 15 minutes.
Because local sync might have pushed a change, so now the remote
LB-to-FW sync may have different pending numbers.
@rmunn rmunn merged commit 404ae07 into develop May 26, 2025
27 checks passed
@rmunn rmunn deleted the feat/fw-lite-sync-view branch May 26, 2025 08:54
@coderabbitai coderabbitai Bot mentioned this pull request Sep 11, 2025
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.

Show sync state in dedicated dialog/ui

3 participants