feat: Stage 3 — alert detail, acknowledge, comments, stats charts
Press enter on any alert to open a full-screen detail pane (viewport). Keybindings in detail mode: a/A acknowledge / unacknowledge (updates immediately) c compose a comment (text input at bottom) [/] cycle comment cursor up/down d delete selected comment (y/N confirmation) s assign placeholder — shows "not yet supported by server" S open stats view: top alerts + by-hour/by-day ASCII bar charts esc back to dashboard API additions: GetAlert, AcknowledgeAlert, UnacknowledgeAlert, GetComments, AddComment, DeleteComment, GetTopAlerts, GetStatsByHour, GetStatsByDay.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -92,6 +93,100 @@ func (c *Client) GetAlertStats() (*AlertStats, error) {
|
||||
return &stats, c.do(req, &stats)
|
||||
}
|
||||
|
||||
func (c *Client) newRequestWithBody(method, path string, body any) (*http.Request, error) {
|
||||
data, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest(method, c.baseURL+path, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetAlert(id int64) (*Alert, error) {
|
||||
req, err := c.newRequest(http.MethodGet, fmt.Sprintf("/api/alerts/%d", id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var alert Alert
|
||||
return &alert, c.do(req, &alert)
|
||||
}
|
||||
|
||||
func (c *Client) AcknowledgeAlert(id int64) (*Alert, error) {
|
||||
req, err := c.newRequest(http.MethodPost, fmt.Sprintf("/api/alerts/%d/acknowledge", id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var alert Alert
|
||||
return &alert, c.do(req, &alert)
|
||||
}
|
||||
|
||||
func (c *Client) UnacknowledgeAlert(id int64) error {
|
||||
req, err := c.newRequest(http.MethodDelete, fmt.Sprintf("/api/alerts/%d/acknowledge", id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.do(req, nil)
|
||||
}
|
||||
|
||||
func (c *Client) GetComments(alertID int64) ([]Comment, error) {
|
||||
req, err := c.newRequest(http.MethodGet, fmt.Sprintf("/api/alerts/%d/comments", alertID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var comments []Comment
|
||||
return comments, c.do(req, &comments)
|
||||
}
|
||||
|
||||
func (c *Client) AddComment(alertID int64, content string) (*Comment, error) {
|
||||
req, err := c.newRequestWithBody(http.MethodPost, fmt.Sprintf("/api/alerts/%d/comments", alertID), map[string]string{"content": content})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var comment Comment
|
||||
return &comment, c.do(req, &comment)
|
||||
}
|
||||
|
||||
func (c *Client) DeleteComment(alertID, commentID int64) error {
|
||||
req, err := c.newRequest(http.MethodDelete, fmt.Sprintf("/api/alerts/%d/comments/%d", alertID, commentID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.do(req, nil)
|
||||
}
|
||||
|
||||
func (c *Client) GetTopAlerts(limit int) ([]TopAlert, error) {
|
||||
req, err := c.newRequest(http.MethodGet, fmt.Sprintf("/api/stats/alerts/top?limit=%d", limit))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []TopAlert
|
||||
return result, c.do(req, &result)
|
||||
}
|
||||
|
||||
func (c *Client) GetStatsByHour() ([]HourStat, error) {
|
||||
req, err := c.newRequest(http.MethodGet, "/api/stats/alerts/by-hour")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []HourStat
|
||||
return result, c.do(req, &result)
|
||||
}
|
||||
|
||||
func (c *Client) GetStatsByDay() ([]DayStat, error) {
|
||||
req, err := c.newRequest(http.MethodGet, "/api/stats/alerts/by-day")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []DayStat
|
||||
return result, c.do(req, &result)
|
||||
}
|
||||
|
||||
// HealthCheck calls GET /healthz (unauthenticated path, no auth needed but we send it anyway).
|
||||
func (c *Client) HealthCheck() error {
|
||||
req, err := http.NewRequest(http.MethodGet, c.baseURL+"/healthz", nil)
|
||||
|
||||
Reference in New Issue
Block a user