diff options
| author | zwlucas <lucas.fariamo08@gmail.com> | 2026-05-29 20:21:48 +0000 |
|---|---|---|
| committer | zwlucas <lucas.fariamo08@gmail.com> | 2026-05-29 20:21:48 +0000 |
| commit | d186a989b6808ff39fcd43a9f0b478aebc4aa346 (patch) | |
| tree | abf32684ea56e6066d8584e0378227ffc397ace2 /backend/internal/store | |
| parent | 6cc0bfd1d79074df790272b8091b1f0226d14283 (diff) | |
| download | yaum-d186a989b6808ff39fcd43a9f0b478aebc4aa346.tar.gz yaum-d186a989b6808ff39fcd43a9f0b478aebc4aa346.zip | |
feat: enhance maintenance management and heartbeat history features
- Updated Store interface to include methods for managing maintenances.
- Modified API functions to support pagination for heartbeat history and added CRUD operations for maintenances.
- Enhanced types to include paginated responses and initial log entries.
- Implemented maintenance management UI in the admin panel with create, edit, and delete functionalities.
- Updated service detail page to display paginated heartbeat history and improved chart rendering.
- Refactored status page to accommodate new data structures and ensure consistent data handling.
Signed-off-by: Lucas Faria Mendes <lucas.fariamo08@gmail.com>
Diffstat (limited to 'backend/internal/store')
| -rw-r--r-- | backend/internal/store/memory.go | 81 | ||||
| -rw-r--r-- | backend/internal/store/postgres.go | 75 | ||||
| -rw-r--r-- | backend/internal/store/store.go | 7 |
3 files changed, 155 insertions, 8 deletions
diff --git a/backend/internal/store/memory.go b/backend/internal/store/memory.go index a77e877..1ee2e05 100644 --- a/backend/internal/store/memory.go +++ b/backend/internal/store/memory.go @@ -49,6 +49,17 @@ func (s *MemoryStore) SeedMockData() { s.heartbeats[svc.ID] = make([]*model.Heartbeat, 0) s.seedHistory(svc.ID) } + + s.maintenances = []model.Maintenance{ + { + ID: s.nextMtnID, + Title: "Manutenção Programada — Servidores", + StartTime: now.Add(-1 * time.Hour), + EndTime: now.Add(1 * time.Hour), + IsActive: true, + }, + } + s.nextMtnID++ } func (s *MemoryStore) seedHistory(serviceID int) { @@ -187,21 +198,35 @@ func (s *MemoryStore) AddHeartbeat(hb model.Heartbeat) error { return nil } -func (s *MemoryStore) GetHistory(serviceID int, limit int) ([]model.Heartbeat, error) { +func (s *MemoryStore) GetHistory(serviceID int, limit int, offset int) ([]model.Heartbeat, error) { s.mu.RLock() defer s.mu.RUnlock() hbs := s.heartbeats[serviceID] - if len(hbs) > limit { - hbs = hbs[len(hbs)-limit:] - } - result := make([]model.Heartbeat, len(hbs)) + reverse := make([]*model.Heartbeat, len(hbs)) for i, hb := range hbs { + reverse[len(hbs)-1-i] = hb + } + if offset >= len(reverse) { + return []model.Heartbeat{}, nil + } + if offset+limit > len(reverse) { + limit = len(reverse) - offset + } + page := reverse[offset : offset+limit] + result := make([]model.Heartbeat, len(page)) + for i, hb := range page { result[i] = *hb } return result, nil } +func (s *MemoryStore) CountHeartbeats(serviceID int) (int, error) { + s.mu.RLock() + defer s.mu.RUnlock() + return len(s.heartbeats[serviceID]), nil +} + func (s *MemoryStore) GetLastHeartbeat(serviceID int) (*model.Heartbeat, error) { s.mu.RLock() defer s.mu.RUnlock() @@ -225,6 +250,52 @@ func (s *MemoryStore) GetActiveMaintenance(now time.Time) (*model.Maintenance, e return nil, nil } +func (s *MemoryStore) ListMaintenances() ([]model.Maintenance, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + result := make([]model.Maintenance, len(s.maintenances)) + copy(result, s.maintenances) + return result, nil +} + +func (s *MemoryStore) AddMaintenance(m model.Maintenance) (*model.Maintenance, error) { + s.mu.Lock() + defer s.mu.Unlock() + + m.ID = s.nextMtnID + s.nextMtnID++ + s.maintenances = append(s.maintenances, m) + return &m, nil +} + +func (s *MemoryStore) UpdateMaintenance(id int, m model.Maintenance) (*model.Maintenance, error) { + s.mu.Lock() + defer s.mu.Unlock() + + for i, existing := range s.maintenances { + if existing.ID == id { + m.ID = id + s.maintenances[i] = m + return &m, nil + } + } + return nil, errors.New("manutencao nao encontrada") +} + +func (s *MemoryStore) DeleteMaintenance(id int) error { + s.mu.Lock() + defer s.mu.Unlock() + + for i, m := range s.maintenances { + if m.ID == id { + s.maintenances = append(s.maintenances[:i], s.maintenances[i+1:]...) + return nil + } + } + return errors.New("manutencao nao encontrada") +} + func (s *MemoryStore) GetServiceStats(serviceID int) (*model.ServiceStats, error) { s.mu.RLock() defer s.mu.RUnlock() diff --git a/backend/internal/store/postgres.go b/backend/internal/store/postgres.go index a8d072a..57fa258 100644 --- a/backend/internal/store/postgres.go +++ b/backend/internal/store/postgres.go @@ -213,15 +213,16 @@ func (s *PostgresStore) AddHeartbeat(hb model.Heartbeat) error { return nil } -func (s *PostgresStore) GetHistory(serviceID int, limit int) ([]model.Heartbeat, error) { +func (s *PostgresStore) GetHistory(serviceID int, limit int, offset int) ([]model.Heartbeat, error) { query := ` SELECT id, service_id, status_code, response_time_ms, is_up, error_message, tested_at FROM heartbeats WHERE service_id = $1 ORDER BY tested_at DESC LIMIT $2 + OFFSET $3 ` - rows, err := s.pool.Query(context.Background(), query, serviceID, limit) + rows, err := s.pool.Query(context.Background(), query, serviceID, limit, offset) if err != nil { return nil, fmt.Errorf("get history: %w", err) } @@ -234,6 +235,18 @@ func (s *PostgresStore) GetHistory(serviceID int, limit int) ([]model.Heartbeat, }) } +func (s *PostgresStore) CountHeartbeats(serviceID int) (int, error) { + var count int + err := s.pool.QueryRow(context.Background(), + `SELECT COUNT(*) FROM heartbeats WHERE service_id = $1`, + serviceID, + ).Scan(&count) + if err != nil { + return 0, fmt.Errorf("count heartbeats: %w", err) + } + return count, nil +} + func (s *PostgresStore) GetLastHeartbeat(serviceID int) (*model.Heartbeat, error) { query := ` SELECT id, service_id, status_code, response_time_ms, is_up, error_message, tested_at @@ -322,3 +335,61 @@ func (s *PostgresStore) GetActiveMaintenance(now time.Time) (*model.Maintenance, } return &m, nil } + +func (s *PostgresStore) ListMaintenances() ([]model.Maintenance, error) { + query := `SELECT id, title, start_time, end_time, is_active FROM maintenances ORDER BY start_time DESC` + rows, err := s.pool.Query(context.Background(), query) + if err != nil { + return nil, fmt.Errorf("list maintenances: %w", err) + } + defer rows.Close() + return pgx.CollectRows(rows, func(row pgx.CollectableRow) (model.Maintenance, error) { + var m model.Maintenance + err := row.Scan(&m.ID, &m.Title, &m.StartTime, &m.EndTime, &m.IsActive) + return m, err + }) +} + +func (s *PostgresStore) AddMaintenance(m model.Maintenance) (*model.Maintenance, error) { + query := ` + INSERT INTO maintenances (title, start_time, end_time, is_active) + VALUES ($1, $2, $3, $4) + RETURNING id + ` + err := s.pool.QueryRow(context.Background(), query, m.Title, m.StartTime, m.EndTime, m.IsActive). + Scan(&m.ID) + if err != nil { + return nil, fmt.Errorf("add maintenance: %w", err) + } + return &m, nil +} + +func (s *PostgresStore) UpdateMaintenance(id int, m model.Maintenance) (*model.Maintenance, error) { + query := ` + UPDATE maintenances + SET title = $1, start_time = $2, end_time = $3, is_active = $4 + WHERE id = $5 + RETURNING id, title, start_time, end_time, is_active + ` + var updated model.Maintenance + err := s.pool.QueryRow(context.Background(), query, m.Title, m.StartTime, m.EndTime, m.IsActive, id). + Scan(&updated.ID, &updated.Title, &updated.StartTime, &updated.EndTime, &updated.IsActive) + if err != nil { + if err == pgx.ErrNoRows { + return nil, fmt.Errorf("manutencao nao encontrada") + } + return nil, fmt.Errorf("update maintenance: %w", err) + } + return &updated, nil +} + +func (s *PostgresStore) DeleteMaintenance(id int) error { + tag, err := s.pool.Exec(context.Background(), "DELETE FROM maintenances WHERE id = $1", id) + if err != nil { + return fmt.Errorf("delete maintenance: %w", err) + } + if tag.RowsAffected() == 0 { + return fmt.Errorf("manutencao nao encontrada") + } + return nil +} diff --git a/backend/internal/store/store.go b/backend/internal/store/store.go index e5e05f6..2c34b1c 100644 --- a/backend/internal/store/store.go +++ b/backend/internal/store/store.go @@ -15,9 +15,14 @@ type Store interface { ToggleService(int) (*model.Service, error) DeleteService(int) error AddHeartbeat(model.Heartbeat) error - GetHistory(int, int) ([]model.Heartbeat, error) + GetHistory(int, int, int) ([]model.Heartbeat, error) + CountHeartbeats(int) (int, error) GetLastHeartbeat(int) (*model.Heartbeat, error) GetServiceStats(int) (*model.ServiceStats, error) GetActiveMaintenance(now time.Time) (*model.Maintenance, error) + ListMaintenances() ([]model.Maintenance, error) + AddMaintenance(model.Maintenance) (*model.Maintenance, error) + UpdateMaintenance(int, model.Maintenance) (*model.Maintenance, error) + DeleteMaintenance(int) error } |