Show alert annotations (#833)

* Show annotations

* Update bindata.go

* Fix the versions of elm modules
This commit is contained in:
Andrey Kuzmin 2017-05-30 21:04:49 +02:00 committed by GitHub
parent 6a69491ecf
commit eff5341dec
9 changed files with 88 additions and 57 deletions

View File

@ -4,28 +4,44 @@ alerts1='[
"alertname": "DiskRunningFull", "alertname": "DiskRunningFull",
"dev": "sda1", "dev": "sda1",
"instance": "example1" "instance": "example1"
} },
"annotations": {
"info": "The disk sda1 is running full",
"summary": "please check the instance example1"
}
}, },
{ {
"labels": { "labels": {
"alertname": "DiskRunningFull", "alertname": "DiskRunningFull",
"dev": "sda2", "dev": "sda2",
"instance": "example1" "instance": "example1"
} },
"annotations": {
"info": "The disk sda2 is running full",
"summary": "please check the instance example1"
}
}, },
{ {
"labels": { "labels": {
"alertname": "DiskRunningFull", "alertname": "DiskRunningFull",
"dev": "sda1", "dev": "sda1",
"instance": "example2" "instance": "example2"
} },
"annotations": {
"info": "The disk sda1 is running full",
"summary": "please check the instance example2"
}
}, },
{ {
"labels": { "labels": {
"alertname": "DiskRunningFull", "alertname": "DiskRunningFull",
"dev": "sdb2", "dev": "sdb2",
"instance": "example2" "instance": "example2"
} },
"annotations": {
"info": "The disk sdb2 is running full",
"summary": "please check the instance example2"
}
}, },
{ {
"labels": { "labels": {

View File

@ -1,3 +1,3 @@
FROM node:latest FROM node:latest
RUN npm install -g elm elm-format elm-test RUN npm install -g elm@0.18.0 elm-format@0.6.1-alpha elm-test@0.18.3

View File

@ -16,47 +16,23 @@ fetchAlerts filter =
Utils.Api.send (Utils.Api.get url alertsDecoder) Utils.Api.send (Utils.Api.get url alertsDecoder)
-- Decoders
-- Once the API returns the newly created silence, this can go away and we
-- re-use the silence decoder.
alertsDecoder : Json.Decoder (List Alert) alertsDecoder : Json.Decoder (List Alert)
alertsDecoder = alertsDecoder =
Json.at [ "data" ] (Json.list alertDecoder) Json.list alertDecoder
-- populate alerts with ids:
|> Json.map (List.indexedMap (toString >> (|>)))
|> field "data"
unwrapWithDefault : a -> Maybe a -> Json.Decoder a {-| TODO: decode alert id when provided
unwrapWithDefault default val = -}
case val of alertDecoder : Json.Decoder (String -> Alert)
Just a ->
Json.succeed a
Nothing ->
Json.succeed default
alertDecoder : Json.Decoder Alert
alertDecoder = alertDecoder =
Json.map6 Alert Json.map5 Alert
(Json.maybe (field "annotations" (Json.keyValuePairs Json.string)) |> andThen (unwrapWithDefault [])) (Json.maybe (field "annotations" (Json.keyValuePairs Json.string))
|> andThen (Maybe.withDefault [] >> Json.succeed)
)
(field "labels" (Json.keyValuePairs Json.string)) (field "labels" (Json.keyValuePairs Json.string))
(Json.maybe (field "silenced" Json.string)) (Json.maybe (Json.at [ "status", "silencedBy", "0" ] Json.string))
(decodeSilenced)
(field "startsAt" iso8601Time) (field "startsAt" iso8601Time)
(field "generatorURL" Json.string) (field "generatorURL" Json.string)
decodeSilenced : Decoder Bool
decodeSilenced =
Json.maybe (field "silenced" Json.string)
|> andThen
(\val ->
case val of
Just _ ->
Json.succeed True
Nothing ->
Json.succeed False
)

View File

@ -11,9 +11,9 @@ type alias Alert =
{ annotations : Labels { annotations : Labels
, labels : Labels , labels : Labels
, silenceId : Maybe String , silenceId : Maybe String
, silenced : Bool
, startsAt : Time , startsAt : Time
, generatorUrl : String , generatorUrl : String
, id : String
} }

View File

@ -7,13 +7,13 @@ import Html.Events exposing (onClick)
import Types exposing (Msg(CreateSilenceFromAlert, Noop, MsgForAlertList)) import Types exposing (Msg(CreateSilenceFromAlert, Noop, MsgForAlertList))
import Utils.Date import Utils.Date
import Views.FilterBar.Types as FilterBarTypes import Views.FilterBar.Types as FilterBarTypes
import Views.AlertList.Types exposing (AlertListMsg(MsgForFilterBar)) import Views.AlertList.Types exposing (AlertListMsg(MsgForFilterBar, SetActive))
import Utils.Filter import Utils.Filter
import Time exposing (Time) import Time exposing (Time)
view : List ( String, String ) -> Alert -> Html Msg view : List ( String, String ) -> Maybe String -> Alert -> Html Msg
view labels alert = view labels maybeActiveId alert =
let let
-- remove the grouping labels, and bring the alertname to front -- remove the grouping labels, and bring the alertname to front
ungroupedLabels = ungroupedLabels =
@ -25,11 +25,20 @@ view labels alert =
li li
[ class "align-items-start list-group-item border-0 alert-list-item p-0 mb-4" [ class "align-items-start list-group-item border-0 alert-list-item p-0 mb-4"
] ]
[ div [ class "w-100 mb-2 d-flex align-items-start" ] [ div
[ class "w-100 mb-2 d-flex align-items-start" ]
[ dateView alert.startsAt [ dateView alert.startsAt
, if List.length alert.annotations > 0 then
annotationsButton maybeActiveId alert
else
text ""
, generatorUrlButton alert.generatorUrl , generatorUrlButton alert.generatorUrl
, silenceButton alert , silenceButton alert
] ]
, if maybeActiveId == Just alert.id then
table [ class "table w-100 mb-1" ] (List.map annotation alert.annotations)
else
text ""
, div [] (List.map labelButton ungroupedLabels) , div [] (List.map labelButton ungroupedLabels)
] ]
@ -43,6 +52,30 @@ dateView time =
] ]
annotationsButton : Maybe String -> Alert -> Html Msg
annotationsButton maybeActiveId alert =
if maybeActiveId == Just alert.id then
button
[ onClick (SetActive Nothing |> MsgForAlertList)
, class "btn btn-outline-info border-0 active"
]
[ i [ class "fa fa-minus mr-2" ] [], text "Info" ]
else
button
[ onClick (SetActive (Just alert.id) |> MsgForAlertList)
, class "btn btn-outline-info border-0"
]
[ i [ class "fa fa-plus mr-2" ] [], text "Info" ]
annotation : ( String, String ) -> Html Msg
annotation ( key, value ) =
tr []
[ th [ class "text-nowrap" ] [ text (key ++ ":") ]
, td [ class "w-100" ] [ text value ]
]
labelButton : ( String, String ) -> Html Msg labelButton : ( String, String ) -> Html Msg
labelButton ( key, value ) = labelButton ( key, value ) =
button button

View File

@ -12,6 +12,7 @@ type AlertListMsg
| MsgForFilterBar FilterBar.Msg | MsgForFilterBar FilterBar.Msg
| MsgForGroupBar GroupBar.Msg | MsgForGroupBar GroupBar.Msg
| ToggleSilenced Bool | ToggleSilenced Bool
| SetActive (Maybe String)
| SetTab Tab | SetTab Tab
@ -25,6 +26,7 @@ type alias Model =
, groupBar : GroupBar.Model , groupBar : GroupBar.Model
, filterBar : FilterBar.Model , filterBar : FilterBar.Model
, tab : Tab , tab : Tab
, activeId : Maybe String
} }
@ -34,4 +36,5 @@ initAlertList =
, groupBar = GroupBar.initGroupBar , groupBar = GroupBar.initGroupBar
, filterBar = FilterBar.initFilterBar , filterBar = FilterBar.initFilterBar
, tab = FilterTab , tab = FilterTab
, activeId = Nothing
} }

View File

@ -42,7 +42,7 @@ update msg ({ groupBar, filterBar } as model) filter =
newFilterBar = newFilterBar =
FilterBar.setMatchers filter filterBar FilterBar.setMatchers filter filterBar
in in
( { model | alerts = Loading, filterBar = newFilterBar, groupBar = newGroupBar } ( { model | alerts = Loading, filterBar = newFilterBar, groupBar = newGroupBar, activeId = Nothing }
, Api.fetchAlerts filter |> Cmd.map (AlertsFetched >> MsgForAlertList) , Api.fetchAlerts filter |> Cmd.map (AlertsFetched >> MsgForAlertList)
) )
@ -67,3 +67,6 @@ update msg ({ groupBar, filterBar } as model) filter =
GroupBar.update "/#/alerts" filter msg groupBar GroupBar.update "/#/alerts" filter msg groupBar
in in
( { model | groupBar = newGroupBar }, Cmd.map (MsgForGroupBar >> MsgForAlertList) cmd ) ( { model | groupBar = newGroupBar }, Cmd.map (MsgForGroupBar >> MsgForAlertList) cmd )
SetActive maybeId ->
( { model | activeId = maybeId }, Cmd.none )

View File

@ -36,7 +36,7 @@ renderSilenced maybeShowSilenced =
view : Model -> Filter -> Html Msg view : Model -> Filter -> Html Msg
view { alerts, groupBar, filterBar, tab } filter = view { alerts, groupBar, filterBar, tab, activeId } filter =
div [] div []
[ div [ div
[ class "card mb-5" ] [ class "card mb-5" ]
@ -58,7 +58,7 @@ view { alerts, groupBar, filterBar, tab } filter =
] ]
, case alerts of , case alerts of
Success alerts -> Success alerts ->
alertGroups filter groupBar alerts alertGroups activeId filter groupBar alerts
Loading -> Loading ->
Utils.Views.loading Utils.Views.loading
@ -71,8 +71,8 @@ view { alerts, groupBar, filterBar, tab } filter =
] ]
alertGroups : Filter -> GroupBar.Model -> List Alert -> Html Msg alertGroups : Maybe String -> Filter -> GroupBar.Model -> List Alert -> Html Msg
alertGroups filter groupBar alerts = alertGroups activeId filter groupBar alerts =
let let
grouped = grouped =
alerts alerts
@ -86,14 +86,14 @@ alertGroups filter groupBar alerts =
|> List.filterMap |> List.filterMap
(\labels -> (\labels ->
Maybe.map Maybe.map
(alertList labels filter) (alertList activeId labels filter)
(Dict.get labels grouped) (Dict.get labels grouped)
) )
|> div [] |> div []
alertList : Labels -> Filter -> List Alert -> Html Msg alertList : Maybe String -> Labels -> Filter -> List Alert -> Html Msg
alertList labels filter alerts = alertList activeId labels filter alerts =
div [] div []
[ div [] [ div []
(case labels of (case labels of
@ -111,5 +111,5 @@ alertList labels filter alerts =
, if List.isEmpty alerts then , if List.isEmpty alerts then
div [] [ text "no alerts found" ] div [] [ text "no alerts found" ]
else else
ul [ class "list-group mb-4" ] (List.map (AlertView.view labels) alerts) ul [ class "list-group mb-4" ] (List.map (AlertView.view labels activeId) alerts)
] ]

File diff suppressed because one or more lines are too long