mirror of
https://github.com/prometheus/alertmanager
synced 2025-04-01 14:38:52 +00:00
Switch to /alerts endpoint and restlye alerts list page
Instead of using the /alerts/groups endpoint to retriev alerts this commit introduces usage of the /alerts endpoint. This bypasses a lot of complexity by ignoring alert groups and alert blocks. Groups and blocks are left as a pure back-end detail. Fixes #694
This commit is contained in:
parent
233cad6591
commit
30c62c2f9f
@ -15,7 +15,8 @@
|
||||
"elm-lang/navigation": "2.0.1 <= v < 3.0.0",
|
||||
"elm-tools/parser": "2.0.0 <= v < 3.0.0",
|
||||
"evancz/url-parser": "2.0.1 <= v < 3.0.0",
|
||||
"jweir/elm-iso8601": "3.0.2 <= v < 4.0.0"
|
||||
"jweir/elm-iso8601": "3.0.2 <= v < 4.0.0",
|
||||
"rluiten/elm-date-extra": "8.5.0 <= v < 9.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
|
@ -8,6 +8,22 @@
|
||||
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.5.3/css/tachyons.min.css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
|
||||
<script src="https://use.fontawesome.com/b7508bb100.js"></script>
|
||||
<style>
|
||||
.alert-list-item:nth-child(odd) {
|
||||
background: #f7f7f9;
|
||||
}
|
||||
.alert-list-item:not(:hover) .btn {
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: gray;
|
||||
}
|
||||
.alert-list-item:not(:hover) .badge {
|
||||
background-color: gray;
|
||||
}
|
||||
.alert-list-item:hover {
|
||||
background: #f7f7f9;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -7,13 +7,13 @@ import Utils.Types exposing (ApiData)
|
||||
import Utils.Filter exposing (Filter, generateQueryString)
|
||||
|
||||
|
||||
alertGroups : Filter -> Cmd (ApiData (List AlertGroup))
|
||||
alertGroups filter =
|
||||
fetchAlerts : Filter -> Cmd (ApiData (List Alert))
|
||||
fetchAlerts filter =
|
||||
let
|
||||
url =
|
||||
String.join "/" [ baseUrl, "alerts", "groups" ++ (generateQueryString filter) ]
|
||||
String.join "/" [ baseUrl, "alerts" ++ (generateQueryString filter) ]
|
||||
in
|
||||
Utils.Api.send (Utils.Api.get url alertGroupsDecoder)
|
||||
Utils.Api.send (Utils.Api.get url alertsDecoder)
|
||||
|
||||
|
||||
|
||||
@ -22,22 +22,9 @@ alertGroups filter =
|
||||
-- re-use the silence decoder.
|
||||
|
||||
|
||||
alertGroupsDecoder : Json.Decoder (List AlertGroup)
|
||||
alertGroupsDecoder =
|
||||
Json.at [ "data" ] (Json.list alertGroupDecoder)
|
||||
|
||||
|
||||
alertGroupDecoder : Json.Decoder AlertGroup
|
||||
alertGroupDecoder =
|
||||
Json.map2 AlertGroup
|
||||
(decodeBlocks)
|
||||
(Json.at [ "labels" ] (Json.keyValuePairs Json.string))
|
||||
|
||||
|
||||
decodeBlocks : Json.Decoder (List Block)
|
||||
decodeBlocks =
|
||||
Json.maybe (field "blocks" (Json.list blockDecoder))
|
||||
|> andThen (unwrapWithDefault [])
|
||||
alertsDecoder : Json.Decoder (List Alert)
|
||||
alertsDecoder =
|
||||
Json.at [ "data" ] (Json.list alertDecoder)
|
||||
|
||||
|
||||
unwrapWithDefault : a -> Maybe a -> Json.Decoder a
|
||||
@ -50,25 +37,11 @@ unwrapWithDefault default val =
|
||||
Json.succeed default
|
||||
|
||||
|
||||
blockDecoder : Json.Decoder Block
|
||||
blockDecoder =
|
||||
Json.map2 Block
|
||||
(field "alerts" <| Json.list alertDecoder)
|
||||
(field "routeOpts" routeOptsDecoder)
|
||||
|
||||
|
||||
routeOptsDecoder : Json.Decoder RouteOpts
|
||||
routeOptsDecoder =
|
||||
Json.map RouteOpts
|
||||
(field "receiver" Json.string)
|
||||
|
||||
|
||||
alertDecoder : Json.Decoder Alert
|
||||
alertDecoder =
|
||||
Json.map7 Alert
|
||||
Json.map6 Alert
|
||||
(Json.maybe (field "annotations" (Json.keyValuePairs Json.string)) |> andThen (unwrapWithDefault []))
|
||||
(field "labels" (Json.keyValuePairs Json.string))
|
||||
(field "inhibited" Json.bool)
|
||||
(Json.maybe (field "silenced" Json.string))
|
||||
(decodeSilenced)
|
||||
(field "startsAt" iso8601Time)
|
||||
|
@ -4,10 +4,12 @@ import Utils.Types exposing (Labels)
|
||||
import Time exposing (Time)
|
||||
|
||||
|
||||
-- TODO: Revive inhibited field
|
||||
|
||||
|
||||
type alias Alert =
|
||||
{ annotations : Labels
|
||||
, labels : Labels
|
||||
, inhibited : Bool
|
||||
, silenceId : Maybe String
|
||||
, silenced : Bool
|
||||
, startsAt : Time
|
||||
|
@ -1,6 +1,6 @@
|
||||
module Silences.Types exposing (Silence, nullSilence, nullMatcher, nullTime, SilenceId)
|
||||
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Utils.Types exposing (Matcher, ApiData, ApiResponse(Success))
|
||||
import Time exposing (Time)
|
||||
|
||||
@ -14,7 +14,7 @@ nullSilence =
|
||||
, endsAt = 0
|
||||
, updatedAt = 0
|
||||
, matchers = [ nullMatcher ]
|
||||
, silencedAlertGroups = Success []
|
||||
, silencedAlerts = Success []
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ type alias Silence =
|
||||
, endsAt : Time
|
||||
, updatedAt : Time
|
||||
, matchers : List Matcher
|
||||
, silencedAlertGroups : ApiData (List AlertGroup)
|
||||
, silencedAlerts : ApiData (List Alert)
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,9 +13,8 @@ import Utils.Types
|
||||
( ApiResponse(Loading, Failure, Success)
|
||||
, Matcher
|
||||
)
|
||||
import Utils.Filter exposing (nullFilter)
|
||||
import Views.AlertList.Updates
|
||||
import Views.AlertList.Types exposing (AlertListMsg(FetchAlertGroups))
|
||||
import Views.AlertList.Types exposing (AlertListMsg(FetchAlerts))
|
||||
import Views.Silence.Types exposing (SilenceMsg(SilenceFetched, InitSilenceView))
|
||||
import Views.SilenceList.Types exposing (SilenceListMsg(FetchSilences))
|
||||
import Views.Silence.Updates
|
||||
@ -43,7 +42,7 @@ update msg model =
|
||||
NavigateToAlerts filter ->
|
||||
let
|
||||
( alertList, cmd ) =
|
||||
Views.AlertList.Updates.update FetchAlertGroups model.alertList filter
|
||||
Views.AlertList.Updates.update FetchAlerts model.alertList filter
|
||||
in
|
||||
( { model | alertList = alertList, route = AlertsRoute filter, filter = filter }, cmd )
|
||||
|
||||
|
@ -5,6 +5,9 @@ import Parser exposing (Parser, (|.), (|=))
|
||||
import Time
|
||||
import Utils.Types as Types
|
||||
import Tuple
|
||||
import Date
|
||||
import Date.Extra.Format
|
||||
import Date.Extra.Config.Config_en_us exposing (config)
|
||||
|
||||
|
||||
parseDuration : String -> Maybe Time.Time
|
||||
@ -62,14 +65,19 @@ durationFormat time =
|
||||
|> String.trim
|
||||
|
||||
|
||||
dateFormat : ISO8601.Time -> String
|
||||
dateFormat t =
|
||||
String.join "/" <| List.map toString [ ISO8601.year t, ISO8601.month t, ISO8601.day t ]
|
||||
dateFormat : Time.Time -> String
|
||||
dateFormat =
|
||||
Date.fromTime >> (Date.Extra.Format.format config Date.Extra.Format.isoDateFormat)
|
||||
|
||||
|
||||
timeFormat : Time.Time -> String
|
||||
timeFormat =
|
||||
round >> ISO8601.fromTime >> dateFormat
|
||||
Date.fromTime >> (Date.Extra.Format.format config Date.Extra.Format.isoTimeFormat)
|
||||
|
||||
|
||||
dateTimeFormat : Time.Time -> String
|
||||
dateTimeFormat t =
|
||||
(dateFormat t) ++ " " ++ (timeFormat t)
|
||||
|
||||
|
||||
encode : Time.Time -> String
|
||||
|
@ -6,15 +6,20 @@ import Html.Events exposing (onCheck, onInput, onClick)
|
||||
import Http exposing (Error(..))
|
||||
|
||||
|
||||
onClickMsgButton : String -> msg -> Html msg
|
||||
onClickMsgButton content msg =
|
||||
a [ class "f6 link br1 ba mr1 mb2 dib light-silver hover-black ph3 pv2", onClick msg ]
|
||||
[ text content ]
|
||||
labelButton : Maybe msg -> ( String, String ) -> Html msg
|
||||
labelButton maybeMsg ( key, value ) =
|
||||
let
|
||||
label =
|
||||
[ span [ class " badge badge-warning" ]
|
||||
[ i [] [], text (key ++ "=" ++ value) ]
|
||||
]
|
||||
in
|
||||
case maybeMsg of
|
||||
Nothing ->
|
||||
span [ class "pl-2" ] label
|
||||
|
||||
|
||||
labelButton : ( String, String ) -> Html msg
|
||||
labelButton ( key, value ) =
|
||||
listButton "light-silver hover-black ph3 pv2" ( key, value )
|
||||
Just msg ->
|
||||
span [ class "pl-2", onClick msg ] label
|
||||
|
||||
|
||||
listButton : String -> ( String, String ) -> Html msg
|
||||
@ -61,8 +66,8 @@ textField labelText content msg =
|
||||
|
||||
buttonLink : String -> String -> String -> msg -> Html msg
|
||||
buttonLink icon link color msg =
|
||||
a [ class <| "f6 link br1 ba mr1 ph3 pv2 mb2 dib " ++ color, href link, onClick msg ]
|
||||
[ i [ class <| "fa fa-3 " ++ icon ] []
|
||||
a [ class <| "" ++ color, href link, onClick msg ]
|
||||
[ i [ class <| "" ++ icon ] []
|
||||
]
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[ navBar model.route
|
||||
, div [ class "container" ]
|
||||
, div [ class "container pb-4" ]
|
||||
[ currentView model ]
|
||||
]
|
||||
|
||||
|
89
ui/app/src/Views/AlertList/AlertView.elm
Normal file
89
ui/app/src/Views/AlertList/AlertView.elm
Normal file
@ -0,0 +1,89 @@
|
||||
module Views.AlertList.AlertView exposing (view)
|
||||
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (class, style, href)
|
||||
import Html.Events exposing (onClick)
|
||||
import Types exposing (Msg(CreateSilenceFromAlert, Noop, MsgForAlertList))
|
||||
import Utils.Date
|
||||
import Views.AlertList.Types exposing (AlertListMsg(AddFilterMatcher))
|
||||
import Utils.Views exposing (buttonLink)
|
||||
import Utils.Filter
|
||||
import Time exposing (Time)
|
||||
|
||||
|
||||
view : Alert -> Html Msg
|
||||
view alert =
|
||||
li
|
||||
[ class "align-items-center list-group-item alert-list-item p-0 d-inline-flex justify-content-start"
|
||||
]
|
||||
[ dateView alert.startsAt
|
||||
, labelButtons alert.labels
|
||||
, div [ class "ml-auto d-inline-flex align-self-stretch p-2", style [ ( "border-left", "1px solid #ccc" ) ] ]
|
||||
[ generatorUrlButton alert.generatorUrl
|
||||
, silenceButton alert
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
dateView : Time -> Html Msg
|
||||
dateView time =
|
||||
i
|
||||
[ class "h-100 d-flex flex-column justify-content-center p-2 text-muted"
|
||||
, style [ ( "border-right", "1px solid #ccc" ), ( "font-family", "monospace" ) ]
|
||||
]
|
||||
[ span [] [ text <| Utils.Date.timeFormat time ]
|
||||
, small [] [ text <| Utils.Date.dateFormat time ]
|
||||
]
|
||||
|
||||
|
||||
labelButtons : List ( String, String ) -> Html Msg
|
||||
labelButtons labels =
|
||||
labels
|
||||
-- the alertname label should be first
|
||||
|> List.partition (Tuple.first >> (==) "alertname")
|
||||
|> uncurry (++)
|
||||
|> List.map labelButton
|
||||
|> div []
|
||||
|
||||
|
||||
labelButton : ( String, String ) -> Html Msg
|
||||
labelButton ( key, value ) =
|
||||
let
|
||||
msg =
|
||||
AddFilterMatcher False
|
||||
{ key = key
|
||||
, op = Utils.Filter.Eq
|
||||
, value = value
|
||||
}
|
||||
|> MsgForAlertList
|
||||
in
|
||||
-- Hide "alertname" key if label is the alertname label
|
||||
if key == "alertname" then
|
||||
span [ class "pl-2", onClick msg ]
|
||||
[ span [ class "badge badge-primary" ]
|
||||
[ i [] [], text value ]
|
||||
]
|
||||
else
|
||||
Utils.Views.labelButton (Just msg) ( key, value )
|
||||
|
||||
|
||||
silenceButton : Alert -> Html Msg
|
||||
silenceButton alert =
|
||||
let
|
||||
id =
|
||||
Maybe.withDefault "" alert.silenceId
|
||||
in
|
||||
if alert.silenced then
|
||||
buttonLink "fa-deaf" ("#/silences/" ++ id) "blue" Noop
|
||||
else
|
||||
a [ class "h-100 btn btn-warning rounded-0", style [], href "#/silences/new?keep=1", onClick (CreateSilenceFromAlert alert) ] [ span [ class "fa fa-bell-slash-o" ] [] ]
|
||||
|
||||
|
||||
generatorUrlButton : String -> Html Msg
|
||||
generatorUrlButton url =
|
||||
a
|
||||
[ class "h-100 btn btn-primary rounded-0 align-items-center d-inline-flex border-right-0"
|
||||
, href url
|
||||
]
|
||||
[ i [ class "fa fa-line-chart" ] [] ]
|
@ -1,52 +1,30 @@
|
||||
module Views.AlertList.Filter exposing (receiver, silenced, matchers)
|
||||
module Views.AlertList.Filter exposing (silenced, matchers)
|
||||
|
||||
import Alerts.Types exposing (Alert, AlertGroup, Block)
|
||||
import Utils.Types exposing (Matchers)
|
||||
import Utils.Filter exposing (Matcher, MatchOperator(Eq, NotEq, RegexMatch, NotRegexMatch))
|
||||
import Regex exposing (regex, contains)
|
||||
|
||||
|
||||
receiver : Maybe Matcher -> List AlertGroup -> List AlertGroup
|
||||
receiver maybeReceiver groups =
|
||||
case maybeReceiver of
|
||||
Just { key, op, value } ->
|
||||
case op of
|
||||
Eq ->
|
||||
by (filterAlertGroup ((==) value)) groups
|
||||
|
||||
RegexMatch ->
|
||||
by (filterAlertGroup ((regex >> contains) value)) groups
|
||||
|
||||
NotEq ->
|
||||
by (filterAlertGroup ((/=) value)) groups
|
||||
|
||||
NotRegexMatch ->
|
||||
by (filterAlertGroup (((regex >> contains) value) >> not)) groups
|
||||
|
||||
Nothing ->
|
||||
groups
|
||||
|
||||
|
||||
matchers : Maybe Utils.Types.Matchers -> List AlertGroup -> List AlertGroup
|
||||
matchers matchers groups =
|
||||
matchers matchers alerts =
|
||||
case matchers of
|
||||
Just ms ->
|
||||
by (filterAlertGroupLabels ms) groups
|
||||
by (filterAlertGroupLabels ms) alerts
|
||||
|
||||
Nothing ->
|
||||
groups
|
||||
alerts
|
||||
|
||||
|
||||
silenced : Maybe Bool -> List AlertGroup -> List AlertGroup
|
||||
silenced maybeShowSilenced groups =
|
||||
silenced : Maybe Bool -> List Alert -> List Alert
|
||||
silenced maybeShowSilenced alerts =
|
||||
let
|
||||
showSilenced =
|
||||
Maybe.withDefault False maybeShowSilenced
|
||||
in
|
||||
if showSilenced then
|
||||
groups
|
||||
alerts
|
||||
else
|
||||
by alertGroupsSilenced groups
|
||||
List.filter (.silenced >> not) alerts
|
||||
|
||||
|
||||
filterAlertGroup : (String -> Bool) -> AlertGroup -> Maybe AlertGroup
|
||||
|
@ -113,7 +113,7 @@ view matchers matcherText backspacePressed =
|
||||
maybeMatcher == Nothing
|
||||
in
|
||||
div
|
||||
[ class "row no-gutters align-items-start" ]
|
||||
[ class "row no-gutters align-items-start pb-4" ]
|
||||
(viewMatchers matchers
|
||||
++ [ div
|
||||
[ class ("col form-group " ++ className)
|
||||
|
@ -1,13 +1,13 @@
|
||||
module Views.AlertList.Types exposing (AlertListMsg(..), Model, initAlertList)
|
||||
|
||||
import Utils.Types exposing (ApiData, ApiResponse(Loading))
|
||||
import Alerts.Types exposing (Alert, AlertGroup)
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Utils.Filter exposing (Filter)
|
||||
|
||||
|
||||
type AlertListMsg
|
||||
= AlertGroupsFetch (ApiData (List AlertGroup))
|
||||
| FetchAlertGroups
|
||||
= AlertsFetched (ApiData (List Alert))
|
||||
| FetchAlerts
|
||||
| AddFilterMatcher Bool Utils.Filter.Matcher
|
||||
| DeleteFilterMatcher Bool Utils.Filter.Matcher
|
||||
| PressingBackspace Bool
|
||||
@ -25,7 +25,7 @@ proceed to deleting the next matcher.
|
||||
|
||||
-}
|
||||
type alias Model =
|
||||
{ alertGroups : ApiData (List AlertGroup)
|
||||
{ alerts : ApiData (List Alert)
|
||||
, matchers : List Utils.Filter.Matcher
|
||||
, backspacePressed : Bool
|
||||
, matcherText : String
|
||||
@ -34,7 +34,7 @@ type alias Model =
|
||||
|
||||
initAlertList : Model
|
||||
initAlertList =
|
||||
{ alertGroups = Loading
|
||||
{ alerts = Loading
|
||||
, matchers = []
|
||||
, backspacePressed = False
|
||||
, matcherText = ""
|
||||
|
@ -27,18 +27,18 @@ immediatelyFilter filter model =
|
||||
update : AlertListMsg -> Model -> Filter -> ( Model, Cmd Types.Msg )
|
||||
update msg model filter =
|
||||
case msg of
|
||||
AlertGroupsFetch alertGroups ->
|
||||
( { model | alertGroups = alertGroups }, Cmd.none )
|
||||
AlertsFetched listOfAlerts ->
|
||||
( { model | alerts = listOfAlerts }, Cmd.none )
|
||||
|
||||
FetchAlertGroups ->
|
||||
FetchAlerts ->
|
||||
( { model
|
||||
| matchers =
|
||||
filter.text
|
||||
|> Maybe.andThen parseFilter
|
||||
|> Maybe.withDefault []
|
||||
, alertGroups = Loading
|
||||
, alerts = Loading
|
||||
}
|
||||
, Api.alertGroups filter |> Cmd.map (AlertGroupsFetch >> MsgForAlertList)
|
||||
, Api.fetchAlerts filter |> Cmd.map (AlertsFetched >> MsgForAlertList)
|
||||
)
|
||||
|
||||
AddFilterMatcher emptyMatcherText matcher ->
|
||||
|
@ -1,25 +1,25 @@
|
||||
module Views.AlertList.Views exposing (view)
|
||||
|
||||
import Alerts.Types exposing (Alert, AlertGroup, Block)
|
||||
import Views.AlertList.Filter exposing (silenced, receiver, matchers)
|
||||
import Views.AlertList.FilterBar
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Utils.Date
|
||||
import Utils.Types exposing (ApiResponse(Success, Loading, Failure))
|
||||
import Utils.Filter exposing (Filter)
|
||||
import Utils.Views exposing (buttonLink, onClickMsgButton, listButton)
|
||||
import Views.AlertList.Types exposing (AlertListMsg(AddFilterMatcher), Model)
|
||||
import Types exposing (Msg(Noop, CreateSilenceFromAlert, MsgForAlertList))
|
||||
import Utils.Filter exposing (Filter)
|
||||
import Utils.Types exposing (ApiResponse(Success, Loading, Failure))
|
||||
import Utils.Views exposing (buttonLink, listButton)
|
||||
import Views.AlertList.AlertView as AlertView
|
||||
import Views.AlertList.Filter exposing (silenced, matchers)
|
||||
import Views.AlertList.FilterBar
|
||||
import Views.AlertList.Types exposing (AlertListMsg(AddFilterMatcher), Model)
|
||||
|
||||
|
||||
view : Model -> Filter -> Html Msg
|
||||
view { alertGroups, matchers, matcherText, backspacePressed } filter =
|
||||
view { alerts, matchers, matcherText, backspacePressed } filter =
|
||||
div []
|
||||
[ Views.AlertList.FilterBar.view matchers matcherText backspacePressed
|
||||
, case alertGroups of
|
||||
, case alerts of
|
||||
Success groups ->
|
||||
viewGroups groups filter
|
||||
alertList groups filter
|
||||
|
||||
Loading ->
|
||||
Utils.Views.loading
|
||||
@ -29,79 +29,13 @@ view { alertGroups, matchers, matcherText, backspacePressed } filter =
|
||||
]
|
||||
|
||||
|
||||
viewGroups : List AlertGroup -> Filter -> Html Msg
|
||||
viewGroups alertGroups filter =
|
||||
alertList : List Alert -> Filter -> Html Msg
|
||||
alertList alerts filter =
|
||||
let
|
||||
filteredGroups =
|
||||
receiver filter.receiver alertGroups
|
||||
|> silenced filter.showSilenced
|
||||
filteredAlerts =
|
||||
silenced filter.showSilenced alerts
|
||||
in
|
||||
if List.isEmpty filteredGroups then
|
||||
if List.isEmpty filteredAlerts then
|
||||
div [ class "mt2" ] [ text "no alerts found" ]
|
||||
else
|
||||
ul
|
||||
[ classList
|
||||
[ ( "list", True )
|
||||
, ( "pa0", True )
|
||||
]
|
||||
]
|
||||
(List.map alertGroupView filteredGroups)
|
||||
|
||||
|
||||
alertGroupView : AlertGroup -> Html Msg
|
||||
alertGroupView alertGroup =
|
||||
li [ class "pa3 pa4-ns bb b--black-10" ]
|
||||
[ div [ class "mb3" ] (List.map alertHeader <| List.sort alertGroup.labels)
|
||||
, div [] (List.map blockView alertGroup.blocks)
|
||||
]
|
||||
|
||||
|
||||
blockView : Block -> Html Msg
|
||||
blockView block =
|
||||
div [] (List.map alertView block.alerts)
|
||||
|
||||
|
||||
alertView : Alert -> Html Msg
|
||||
alertView alert =
|
||||
let
|
||||
id =
|
||||
Maybe.withDefault "" alert.silenceId
|
||||
|
||||
b =
|
||||
if alert.silenced then
|
||||
buttonLink "fa-deaf" ("#/silences/" ++ id) "blue" Noop
|
||||
else
|
||||
buttonLink "fa-exclamation-triangle" "#/silences/new?keep=1" "dark-red" (CreateSilenceFromAlert alert)
|
||||
|
||||
labels =
|
||||
List.filter (Tuple.first >> (/=) "alertname") alert.labels
|
||||
in
|
||||
div [ class "f6 mb3" ]
|
||||
[ div [ class "mb1" ]
|
||||
[ b
|
||||
, buttonLink "fa-bar-chart" alert.generatorUrl "black" Noop
|
||||
, p [ class "dib mr2" ] [ text <| Utils.Date.timeFormat alert.startsAt ]
|
||||
]
|
||||
, div [ class "mb2 w-80-l w-100-m" ] (List.map labelButton labels)
|
||||
]
|
||||
|
||||
|
||||
labelButton : ( String, String ) -> Html Msg
|
||||
labelButton ( key, value ) =
|
||||
onClickMsgButton
|
||||
(key ++ "=" ++ value)
|
||||
(AddFilterMatcher False
|
||||
{ key = key
|
||||
, op = Utils.Filter.Eq
|
||||
, value = value
|
||||
}
|
||||
|> MsgForAlertList
|
||||
)
|
||||
|
||||
|
||||
alertHeader : ( String, String ) -> Html msg
|
||||
alertHeader ( key, value ) =
|
||||
if key == "alertname" then
|
||||
b [ class "db f4 mr2 dark-red dib" ] [ text value ]
|
||||
else
|
||||
listButton "ph1 pv1" ( key, value )
|
||||
ul [ class "list-group" ] (List.map AlertView.view filteredAlerts)
|
||||
|
@ -6,9 +6,7 @@ import Html.Attributes exposing (class)
|
||||
import Utils.Views exposing (labelButton)
|
||||
|
||||
|
||||
view : Int -> Alert -> Html msg
|
||||
view idx alert =
|
||||
li [ class "mb2 w-80-l w-100-m" ]
|
||||
[ span [] [ text <| toString (idx + 1) ++ ". " ]
|
||||
, div [] (List.map labelButton alert.labels)
|
||||
]
|
||||
view : Alert -> Html msg
|
||||
view alert =
|
||||
li [ class "mb2 w-80-l w-100-m" ] <|
|
||||
List.map (labelButton Nothing) alert.labels
|
||||
|
@ -1,14 +1,12 @@
|
||||
module Views.Shared.AlertListCompact exposing (view)
|
||||
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Html exposing (Html, ul)
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Html exposing (Html, ol)
|
||||
import Html.Attributes exposing (class)
|
||||
import Views.Shared.AlertCompact
|
||||
|
||||
|
||||
view : AlertGroup -> Html msg
|
||||
view { blocks } =
|
||||
blocks
|
||||
|> List.concatMap .alerts
|
||||
|> List.indexedMap Views.Shared.AlertCompact.view
|
||||
|> ul [ class "list pa0" ]
|
||||
view : List Alert -> Html msg
|
||||
view alerts =
|
||||
List.map Views.Shared.AlertCompact.view alerts
|
||||
|> ol [ class "list pa0" ]
|
||||
|
@ -33,9 +33,9 @@ view silence =
|
||||
[ text alertName ]
|
||||
]
|
||||
, div [ class "mb1" ]
|
||||
[ buttonLink "fa-pencil" editUrl "blue" Noop
|
||||
, buttonLink "fa-trash-o" "#/silences" "dark-red" (MsgForSilenceList (DestroySilence silence))
|
||||
, p [ class "dib mr2" ] [ text <| "Until " ++ Utils.Date.timeFormat silence.endsAt ]
|
||||
[ buttonLink "fa fa-pencil" editUrl "blue" Noop
|
||||
, buttonLink "fa fa-trash-o" "#/silences" "dark-red" (MsgForSilenceList (DestroySilence silence))
|
||||
, p [ class "dib mr2" ] [ text <| "Until " ++ Utils.Date.dateTimeFormat silence.endsAt ]
|
||||
]
|
||||
, div [ class "mb2 w-80-l w-100-m" ] (List.map matcherButton silence.matchers)
|
||||
]
|
||||
|
@ -9,13 +9,12 @@ import Utils.Views exposing (error, loading)
|
||||
|
||||
view : Silence -> Html msg
|
||||
view s =
|
||||
case s.silencedAlertGroups of
|
||||
Success alertGroups ->
|
||||
if List.isEmpty alertGroups then
|
||||
case s.silencedAlerts of
|
||||
Success alerts ->
|
||||
if List.isEmpty alerts then
|
||||
div [] [ text "No matches" ]
|
||||
else
|
||||
div []
|
||||
(List.map Views.Shared.AlertListCompact.view alertGroups)
|
||||
div [] [ Views.Shared.AlertListCompact.view alerts ]
|
||||
|
||||
Loading ->
|
||||
loading
|
||||
|
@ -1,12 +1,12 @@
|
||||
module Views.Silence.Types exposing (SilenceMsg(..))
|
||||
|
||||
import Silences.Types exposing (Silence, SilenceId)
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Utils.Types exposing (ApiData)
|
||||
|
||||
|
||||
type SilenceMsg
|
||||
= FetchSilence String
|
||||
| SilenceFetched (ApiData Silence)
|
||||
| AlertGroupsPreview (ApiData (List AlertGroup))
|
||||
| AlertGroupsPreview (ApiData (List Alert))
|
||||
| InitSilenceView SilenceId
|
||||
|
@ -15,13 +15,13 @@ update msg model =
|
||||
FetchSilence id ->
|
||||
( model, getSilence id (SilenceFetched >> MsgForSilence) )
|
||||
|
||||
AlertGroupsPreview alertGroups ->
|
||||
AlertGroupsPreview alerts ->
|
||||
case model.silence of
|
||||
Success silence ->
|
||||
( { model
|
||||
| silence =
|
||||
Success
|
||||
{ silence | silencedAlertGroups = alertGroups }
|
||||
{ silence | silencedAlerts = alerts }
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
@ -31,9 +31,9 @@ update msg model =
|
||||
|
||||
SilenceFetched (Success silence) ->
|
||||
( { model
|
||||
| silence = Success { silence | silencedAlertGroups = Loading }
|
||||
| silence = Success { silence | silencedAlerts = Loading }
|
||||
}
|
||||
, Alerts.Api.alertGroups
|
||||
, Alerts.Api.fetchAlerts
|
||||
({ nullFilter | text = Just (Utils.List.mjoin silence.matchers) })
|
||||
|> Cmd.map (AlertGroupsPreview >> MsgForSilence)
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ module Views.SilenceForm.Types
|
||||
)
|
||||
|
||||
import Silences.Types exposing (Silence, SilenceId)
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Alerts.Types exposing (Alert)
|
||||
import Utils.Types exposing (Matcher, ApiData, Duration, ApiResponse(..))
|
||||
import Time exposing (Time)
|
||||
import Utils.Date exposing (timeToString, timeFromString, durationFormat)
|
||||
@ -35,7 +35,7 @@ toSilence { createdBy, comment, startsAt, endsAt, matchers } =
|
||||
, endsAt = parsedEndsAt
|
||||
|
||||
{- ignored -}
|
||||
, silencedAlertGroups = Success []
|
||||
, silencedAlerts = Success []
|
||||
|
||||
{- ignored -}
|
||||
, updatedAt = 0
|
||||
@ -105,7 +105,7 @@ type SilenceFormMsg
|
||||
= UpdateField SilenceFormFieldMsg
|
||||
| CreateSilence Silence
|
||||
| PreviewSilence Silence
|
||||
| AlertGroupsPreview (ApiData (List AlertGroup))
|
||||
| AlertGroupsPreview (ApiData (List Alert))
|
||||
| FetchSilence String
|
||||
| NewSilenceFromMatchers (List Matcher)
|
||||
| NewSilenceFromMatchersAndTime (List Matcher) Time
|
||||
|
@ -152,8 +152,8 @@ update msg model =
|
||||
( model, Cmd.none )
|
||||
|
||||
PreviewSilence silence ->
|
||||
( { model | silence = Ok { silence | silencedAlertGroups = Loading } }
|
||||
, Alerts.Api.alertGroups
|
||||
( { model | silence = Ok { silence | silencedAlerts = Loading } }
|
||||
, Alerts.Api.fetchAlerts
|
||||
{ nullFilter | text = Just (Utils.List.mjoin silence.matchers) }
|
||||
|> Cmd.map (AlertGroupsPreview >> MsgForSilenceForm)
|
||||
)
|
||||
@ -161,7 +161,7 @@ update msg model =
|
||||
AlertGroupsPreview alertGroups ->
|
||||
case model.silence of
|
||||
Ok sil ->
|
||||
( { model | silence = Ok { sil | silencedAlertGroups = alertGroups } }
|
||||
( { model | silence = Ok { sil | silencedAlerts = alertGroups } }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user