Add manual failures UI and global list filtering
This commit is contained in:
@@ -128,3 +128,32 @@ func (r *FailureRepository) ListAll(ctx context.Context, limit int) ([]domain.Fa
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (r *FailureRepository) Get(ctx context.Context, id string) (domain.FailureEvent, error) {
|
||||
row := r.db.QueryRowContext(ctx,
|
||||
`SELECT id, source, external_id, part_id, machine_id, failure_type, failure_time, details, confidence, created_at
|
||||
FROM failure_events
|
||||
WHERE id = ?`,
|
||||
id,
|
||||
)
|
||||
var event domain.FailureEvent
|
||||
var machineID sql.NullString
|
||||
var details sql.NullString
|
||||
var confidence sql.NullFloat64
|
||||
if err := row.Scan(&event.ID, &event.Source, &event.ExternalID, &event.PartID, &machineID, &event.FailureType, &event.FailureTime, &details, &confidence, &event.CreatedAt); err != nil {
|
||||
return domain.FailureEvent{}, err
|
||||
}
|
||||
if machineID.Valid {
|
||||
value := machineID.String
|
||||
event.MachineID = &value
|
||||
}
|
||||
if details.Valid {
|
||||
value := details.String
|
||||
event.Details = &value
|
||||
}
|
||||
if confidence.Valid {
|
||||
value := confidence.Float64
|
||||
event.Confidence = &value
|
||||
}
|
||||
return event, nil
|
||||
}
|
||||
|
||||
119
internal/repository/registry/installations_failure_ui.go
Normal file
119
internal/repository/registry/installations_failure_ui.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InstallationHistorySpan struct {
|
||||
ComponentID string
|
||||
AssetID string
|
||||
SlotName *string
|
||||
InstalledAt time.Time
|
||||
RemovedAt *time.Time
|
||||
}
|
||||
|
||||
type AssetInstallationRecord struct {
|
||||
ComponentID string
|
||||
AssetID string
|
||||
SlotName *string
|
||||
InstalledAt time.Time
|
||||
RemovedAt *time.Time
|
||||
}
|
||||
|
||||
func (r *InstallationRepository) ListInstallationHistoryByComponentIDs(ctx context.Context, componentIDs []string) (map[string][]InstallationHistorySpan, error) {
|
||||
result := make(map[string][]InstallationHistorySpan, len(componentIDs))
|
||||
if len(componentIDs) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
placeholders := make([]string, 0, len(componentIDs))
|
||||
args := make([]any, 0, len(componentIDs))
|
||||
for _, id := range componentIDs {
|
||||
id = strings.TrimSpace(id)
|
||||
if id == "" {
|
||||
continue
|
||||
}
|
||||
placeholders = append(placeholders, "?")
|
||||
args = append(args, id)
|
||||
result[id] = []InstallationHistorySpan{}
|
||||
}
|
||||
if len(placeholders) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
query := `SELECT part_id, machine_id, slot_name, installed_at, removed_at
|
||||
FROM installations
|
||||
WHERE part_id IN (` + strings.Join(placeholders, ",") + `)
|
||||
ORDER BY part_id, installed_at DESC, created_at DESC, id DESC`
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var row InstallationHistorySpan
|
||||
var slot sql.NullString
|
||||
var removedAt sql.NullTime
|
||||
if err := rows.Scan(&row.ComponentID, &row.AssetID, &slot, &row.InstalledAt, &removedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.SlotName = nullStringToPtr(slot)
|
||||
row.RemovedAt = nullTimeToPtr(removedAt)
|
||||
result[row.ComponentID] = append(result[row.ComponentID], row)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *InstallationRepository) ListInstallationsByAssetIDsSince(ctx context.Context, assetIDs []string, since time.Time) (map[string][]AssetInstallationRecord, error) {
|
||||
result := make(map[string][]AssetInstallationRecord, len(assetIDs))
|
||||
if len(assetIDs) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
placeholders := make([]string, 0, len(assetIDs))
|
||||
args := make([]any, 0, len(assetIDs)+1)
|
||||
for _, id := range assetIDs {
|
||||
id = strings.TrimSpace(id)
|
||||
if id == "" {
|
||||
continue
|
||||
}
|
||||
placeholders = append(placeholders, "?")
|
||||
args = append(args, id)
|
||||
result[id] = []AssetInstallationRecord{}
|
||||
}
|
||||
if len(placeholders) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
if since.IsZero() {
|
||||
since = time.Unix(0, 0).UTC()
|
||||
}
|
||||
query := `SELECT part_id, machine_id, slot_name, installed_at, removed_at
|
||||
FROM installations
|
||||
WHERE machine_id IN (` + strings.Join(placeholders, ",") + `)
|
||||
AND installed_at >= ?
|
||||
ORDER BY machine_id, installed_at DESC, created_at DESC, id DESC`
|
||||
args = append(args, since.UTC())
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var row AssetInstallationRecord
|
||||
var slot sql.NullString
|
||||
var removedAt sql.NullTime
|
||||
if err := rows.Scan(&row.ComponentID, &row.AssetID, &slot, &row.InstalledAt, &removedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.SlotName = nullStringToPtr(slot)
|
||||
row.RemovedAt = nullTimeToPtr(removedAt)
|
||||
result[row.AssetID] = append(result[row.AssetID], row)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user