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 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-02-02 17:19:52 +03:00
parent e0404186ad
commit 0bde12a39d
5 changed files with 202 additions and 99 deletions

View File

@@ -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) {