Add global sync summary component for all providers (#588)

* Add shared sync statistics collection and provider sync summary UI

- Introduced `SyncStats::Collector` concern to centralize sync statistics logic, including account, transaction, holdings, and health stats collection.
- Added collapsible `ProviderSyncSummary` component for displaying sync summaries across providers.
- Updated syncers (e.g., `LunchflowItem::Syncer`) to use the shared collector methods for consistent stats calculation.
- Added rake tasks under `dev:sync_stats` for testing and development purposes, including fake stats generation with optional issues.
- Enhanced provider-specific views to include sync summaries using the new shared component.

* Refactor `ProviderSyncSummary` to improve maintainability

- Extracted `severity_color_class` to simplify severity-to-CSS mapping.
- Replaced `holdings_label` with `holdings_label_key` for streamlined localization.
- Updated locale file to separate `found` and `processed` translations for clarity.

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
LPW
2026-01-09 13:26:37 -05:00
committed by GitHub
parent aaa336b091
commit 140ea78b0e
13 changed files with 998 additions and 130 deletions

View File

@@ -80,7 +80,20 @@
<div class="space-y-4 mt-4">
<% if plaid_item.accounts.any? %>
<%= render "accounts/index/account_groups", accounts: plaid_item.accounts %>
<% else %>
<% end %>
<%# Sync summary (collapsible) - using shared ProviderSyncSummary component %>
<% stats = if defined?(@plaid_sync_stats_map) && @plaid_sync_stats_map
@plaid_sync_stats_map[plaid_item.id] || {}
else
plaid_item.syncs.ordered.first&.sync_stats || {}
end %>
<%= render ProviderSyncSummary.new(
stats: stats,
provider_item: plaid_item
) %>
<% if plaid_item.accounts.empty? %>
<div class="p-4 flex flex-col gap-3 items-center justify-center">
<p class="text-primary font-medium text-sm"><%= t(".no_accounts_title") %></p>
<p class="text-secondary text-sm"><%= t(".no_accounts_description") %></p>