Conversation
…rding it `handle_recv_large_file_end` collapsed `FinishResult::CommittedWithConflict` into a plain `LargeFileEndOutcome::Committed`, silently discarding the `ConflictInfo` for any large file that conflicted during transfer. This made it impossible for callers (the filesync client's GUI state) to ever learn about large-file conflicts. Add `LargeFileEndOutcome::CommittedWithConflict(ConflictInfo)` so the information survives, and update the server's `client_recv_loop` match (which has no GUI to update) to treat it the same as `Committed` for broadcast purposes.
`SyncSnapshot` had no way to represent "a live incremental sync is happening" (only `InitialSync`) and no API for pushing conflicts into the snapshot, which is why the GUI's Conflicts tab and progress bar never reflected live-sync activity. Add to `gui/state.rs`: - `ConnectionStatus::Syncing`, a distinct state from `InitialSync` for post-initial live sync batches, with its own label/colour. - `SyncSnapshot::begin_sync_activity()` — transitions `Idle` -> `Syncing` (resetting transfer counters only on that transition) and always bumps `last_activity`. - `SyncSnapshot::end_sync_activity_if_quiet(idle_after)` — drops back to `Idle` once no activity has been observed for `idle_after` (intended to be driven from the GUI's tick loop). - `SyncSnapshot::push_conflict(...)` plus a module-level `next_conflict_id()` to append `Conflict` entries with unique ids from any code path. Includes unit tests for all new behavior.
…st initial sync
The header badge, status dot, and progress bar in the status panel only
activated for `ConnectionStatus::InitialSync`, so once the initial sync
finished the UI gave no indication that anything was happening during
later incremental syncs — from the user's perspective, a working live sync
looked identical to a stuck/frozen client.
- `header.rs` / `status_panel.rs`: treat `ConnectionStatus::Syncing` the
same as `InitialSync` for badge colour, status dot colour, and progress
bar visibility.
- `status_panel.rs`: the transfer detail text now also shows the file
count (`"{files} file(s) · {bytes} transferred"`), not just bytes, so
users can see concrete evidence of activity instead of only steps.
Includes tests for the new `Syncing` render paths.
The `Message::Tick` handler ran on every tick (once per second) and forced `active_tab` based on the *current* conflict count: switching to Conflicts whenever conflicts were non-empty and the user was on Stats, and switching back to Stats whenever conflicts were empty and the user was on Conflicts. The second branch fired continuously and overrode any manual tab selection, so clicking into the Conflicts tab would immediately get forced back to Stats. Make the auto-switch edge-triggered instead: track whether conflicts were present on the previous tick (`DashboardState::had_conflicts`) and only jump to the Conflicts tab the moment conflicts newly appear. The tab is never forcibly switched away again, so the user can freely stay on Conflicts (or navigate elsewhere) regardless of tick-to-tick conflict count changes. Also drive `SyncSnapshot::end_sync_activity_if_quiet` from the tick handler so the `Syncing` status correctly falls back to `Idle` once a live-sync batch goes quiet.
Two related bugs shared the same root cause: the client's send/recv loops never touched `gui_state` outside of the initial-sync phase, and even during initial sync, detected conflicts were computed but thrown away. - "GUI can't show conflicts": `ApplyResult.conflicts` / `ConflictInfo` from both bundle and large-file transfers was discarded (only `.written` was used). Add `push_gui_conflicts()`, which converts each `ConflictInfo` into a `Conflict` (resolving real display filename/folder and mtimes via a new dependency-free `format_modified`/`format_unix_secs` UTC formatter), and call it from every path that can produce a conflict: the initial-sync bundle/large-file loop and the live-sync `recv_loop` (bundle and large-file-end arms). - "Sync looks frozen" / no live-sync feedback: thread `gui_state` through `recv_loop`, `send_loop`, `flush_to_server`, and `send_paths_to_server` so every incoming/outgoing bundle, large-file chunk, delete, and rename calls `SyncSnapshot::begin_sync_activity()` and updates `files_sent`/`files_received`/`bytes_sent`/`bytes_received`. Combined with the new `ConnectionStatus::Syncing` state and status-panel changes, this makes ongoing background sync activity visible instead of the UI going quiet right after the initial sync completes. Adds `push_gui_conflicts_tests` (whitebox unit tests) covering the conflict-routing behavior directly, since reproducing a genuine two-sided conflict race over a real network connection is inherently flaky.
Every existing integration test constructs its `Client` with `gui_state: None`; the `Some(gui_state)` path used exclusively by the real `filesync-gui` binary was completely untested, which is exactly the scenario in the reported "initial sync freezes" bug report. Add `test_client_gui_state.rs`, which drives a real client/server pair over TCP+TLS with a live `SharedState` attached and asserts that initial sync actually completes (does not hang) and leaves the GUI snapshot in a correct, non-stuck state (status Idle/Syncing, correct file/byte counts, no spurious conflicts).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request enhances the synchronization client to better track and display file conflict information in the GUI, and improves the accuracy of GUI sync activity statistics. It does so by ensuring that all conflicts detected during sync operations are pushed to the GUI state, and by updating GUI statistics (like files/bytes sent or received) at every relevant sync event. Additionally, it introduces utilities for formatting modification times and includes comprehensive tests for the new conflict reporting logic.
Conflict reporting and GUI integration:
push_gui_conflictsto route all detected file conflicts (from bundle application and large file handling) into the GUI state, so that users are promptly informed of sync conflicts. This function is invoked in all relevant sync paths, including bundle application and large file end events. [1] [2] [3] [4] [5]LargeFileEndOutcomeenum to include aCommittedWithConflictvariant, and ensured this new outcome is handled both in the core logic and when updating the GUI. [1] [2] [3]GUI sync activity statistics:
Code structure and utility improvements:
SharedStatefor GUI integration, and added new utility functions for formatting file modification times for display. [1] [2] [3] [4]Testing:
push_gui_conflictslogic, including edge cases (no GUI state, empty conflicts), and for the date formatting utility.Imports and minor refactoring:
These changes collectively ensure that users are reliably notified of all file conflicts during sync, and that the GUI accurately reflects ongoing sync activity, improving both usability and reliability.