From 0bde12a39d07f3d9eb6ac78ec43ed5be4e558aef Mon Sep 17 00:00:00 2001 From: Mikhail Chusavitin Date: Mon, 2 Feb 2026 17:19:52 +0300 Subject: [PATCH] fix: display only real sync errors in error count and list - Added CountErroredChanges() method to count only pending changes with LastError - Previously, error count included all pending changes, not just failed ones - Added /api/sync/info endpoint with proper error count and error list - Added sync info modal to display sync status, error count, and error details - Made sync status indicators clickable to open the modal - Fixed disconnect between "Error count: 4" and "No errors" in the list Co-Authored-By: Claude Sonnet 4.5 --- cmd/server/main.go | 1 + internal/handlers/sync.go | 64 ++++++++ internal/localdb/localdb.go | 7 + web/templates/base.html | 192 +++++++++++++++--------- web/templates/partials/sync_status.html | 37 +---- 5 files changed, 202 insertions(+), 99 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index a4cb7be..7f8ca87 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -625,6 +625,7 @@ func setupRouter(db *gorm.DB, cfg *config.Config, local *localdb.LocalDB, dbUser syncAPI := api.Group("/sync") { syncAPI.GET("/status", syncHandler.GetStatus) + syncAPI.GET("/info", syncHandler.GetInfo) syncAPI.POST("/components", syncHandler.SyncComponents) syncAPI.POST("/pricelists", syncHandler.SyncPricelists) syncAPI.POST("/all", syncHandler.SyncAll) diff --git a/internal/handlers/sync.go b/internal/handlers/sync.go index bbea2ef..d5937aa 100644 --- a/internal/handlers/sync.go +++ b/internal/handlers/sync.go @@ -282,6 +282,70 @@ func (h *SyncHandler) GetPendingChanges(c *gin.Context) { }) } +// SyncInfoResponse represents sync information +type SyncInfoResponse struct { + LastSyncAt *time.Time `json:"last_sync_at"` + IsOnline bool `json:"is_online"` + ErrorCount int `json:"error_count"` + Errors []SyncError `json:"errors,omitempty"` +} + +// SyncError represents a sync error +type SyncError struct { + Timestamp time.Time `json:"timestamp"` + Message string `json:"message"` +} + +// GetInfo returns sync information for modal +// GET /api/sync/info +func (h *SyncHandler) GetInfo(c *gin.Context) { + // Check online status by pinging MariaDB + isOnline := h.checkOnline() + + // Get sync times + lastPricelistSync := h.localDB.GetLastSyncTime() + + // Get error count (only changes with LastError != "") + errorCount := int(h.localDB.CountErroredChanges()) + + // Get recent errors (last 10) + changes, err := h.localDB.GetPendingChanges() + if err != nil { + slog.Error("failed to get pending changes for sync info", "error", err) + // Even if we can't get changes, we can still return the error count + c.JSON(http.StatusOK, SyncInfoResponse{ + LastSyncAt: lastPricelistSync, + IsOnline: isOnline, + ErrorCount: errorCount, + Errors: []SyncError{}, // Return empty errors list + }) + return + } + + var errors []SyncError + for _, change := range changes { + // Check if there's a last error and it's not empty + if change.LastError != "" { + errors = append(errors, SyncError{ + Timestamp: change.CreatedAt, + Message: change.LastError, + }) + } + } + + // Limit to last 10 errors + if len(errors) > 10 { + errors = errors[:10] + } + + c.JSON(http.StatusOK, SyncInfoResponse{ + LastSyncAt: lastPricelistSync, + IsOnline: isOnline, + ErrorCount: errorCount, + Errors: errors, + }) +} + // SyncStatusPartial renders the sync status partial for htmx // GET /partials/sync-status func (h *SyncHandler) SyncStatusPartial(c *gin.Context) { diff --git a/internal/localdb/localdb.go b/internal/localdb/localdb.go index e609692..9558e38 100644 --- a/internal/localdb/localdb.go +++ b/internal/localdb/localdb.go @@ -396,6 +396,13 @@ func (l *LocalDB) CountPendingChangesByType(entityType string) int64 { return count } +// CountErroredChanges returns the number of pending changes with errors +func (l *LocalDB) CountErroredChanges() int64 { + var count int64 + l.db.Model(&PendingChange{}).Where("last_error != ?", "").Count(&count) + return count +} + // MarkChangesSynced marks multiple pending changes as synced by deleting them func (l *LocalDB) MarkChangesSynced(ids []int64) error { if len(ids) == 0 { diff --git a/web/templates/base.html b/web/templates/base.html index e5d2024..1cf1124 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -44,6 +44,52 @@
+ + +