mirror of
https://github.com/prometheus/alertmanager
synced 2024-12-26 08:02:16 +00:00
Support default grouping
Signed-off-by: Andrey Kuzmin <andrey.kuzmin@soundcloud.com>
This commit is contained in:
parent
1df9de3f28
commit
9ddadb8c77
@ -1,5 +1,6 @@
|
||||
module Alerts.Api exposing (fetchAlerts, fetchReceivers)
|
||||
module Alerts.Api exposing (fetchAlertGroups, fetchAlerts, fetchReceivers)
|
||||
|
||||
import Data.AlertGroup exposing (AlertGroup)
|
||||
import Data.GettableAlert exposing (GettableAlert)
|
||||
import Data.Receiver exposing (Receiver)
|
||||
import Json.Decode
|
||||
@ -18,6 +19,15 @@ fetchReceivers apiUrl =
|
||||
)
|
||||
|
||||
|
||||
fetchAlertGroups : String -> Filter -> Cmd (ApiData (List AlertGroup))
|
||||
fetchAlertGroups apiUrl filter =
|
||||
let
|
||||
url =
|
||||
String.join "/" [ apiUrl, "alerts", "groups" ++ generateQueryString filter ]
|
||||
in
|
||||
Utils.Api.send (Utils.Api.get url (Json.Decode.list Data.AlertGroup.decoder))
|
||||
|
||||
|
||||
fetchAlerts : String -> Filter -> Cmd (ApiData (List GettableAlert))
|
||||
fetchAlerts apiUrl filter =
|
||||
let
|
||||
|
@ -22,6 +22,7 @@ import Url exposing (percentEncode)
|
||||
type alias Filter =
|
||||
{ text : Maybe String
|
||||
, group : Maybe String
|
||||
, customGrouping : Bool
|
||||
, receiver : Maybe String
|
||||
, showSilenced : Maybe Bool
|
||||
, showInhibited : Maybe Bool
|
||||
@ -32,6 +33,7 @@ nullFilter : Filter
|
||||
nullFilter =
|
||||
{ text = Nothing
|
||||
, group = Nothing
|
||||
, customGrouping = False
|
||||
, receiver = Nothing
|
||||
, showSilenced = Nothing
|
||||
, showInhibited = Nothing
|
||||
@ -44,7 +46,7 @@ generateQueryParam name =
|
||||
|
||||
|
||||
generateQueryString : Filter -> String
|
||||
generateQueryString { receiver, showSilenced, showInhibited, text, group } =
|
||||
generateQueryString { receiver, customGrouping, showSilenced, showInhibited, text, group } =
|
||||
let
|
||||
parts =
|
||||
[ ( "silenced", Maybe.withDefault False showSilenced |> boolToString |> Just )
|
||||
@ -52,6 +54,7 @@ generateQueryString { receiver, showSilenced, showInhibited, text, group } =
|
||||
, ( "filter", emptyToNothing text )
|
||||
, ( "receiver", emptyToNothing receiver )
|
||||
, ( "group", group )
|
||||
, ( "customGrouping", boolToMaybeString customGrouping )
|
||||
]
|
||||
|> List.filterMap (\( a, b ) -> generateQueryParam a b)
|
||||
in
|
||||
@ -64,6 +67,15 @@ generateQueryString { receiver, showSilenced, showInhibited, text, group } =
|
||||
""
|
||||
|
||||
|
||||
boolToMaybeString : Bool -> Maybe String
|
||||
boolToMaybeString b =
|
||||
if b then
|
||||
Just "true"
|
||||
|
||||
else
|
||||
Nothing
|
||||
|
||||
|
||||
boolToString : Bool -> String
|
||||
boolToString b =
|
||||
if b then
|
||||
|
@ -5,8 +5,13 @@ import Url.Parser.Query as Query
|
||||
import Utils.Filter exposing (Filter, MatchOperator(..), parseMatcher)
|
||||
|
||||
|
||||
boolParam : String -> Query.Parser (Maybe Bool)
|
||||
boolParam : String -> Query.Parser Bool
|
||||
boolParam name =
|
||||
Query.custom name (List.head >> (/=) Nothing)
|
||||
|
||||
|
||||
maybeBoolParam : String -> Query.Parser (Maybe Bool)
|
||||
maybeBoolParam name =
|
||||
Query.custom name
|
||||
(List.head >> Maybe.map (String.toLower >> (/=) "false"))
|
||||
|
||||
@ -16,7 +21,8 @@ alertsParser =
|
||||
s "alerts"
|
||||
<?> Query.string "filter"
|
||||
<?> Query.string "group"
|
||||
<?> boolParam "customGrouping"
|
||||
<?> Query.string "receiver"
|
||||
<?> boolParam "silenced"
|
||||
<?> boolParam "inhibited"
|
||||
<?> maybeBoolParam "silenced"
|
||||
<?> maybeBoolParam "inhibited"
|
||||
|> map Filter
|
||||
|
@ -1,6 +1,12 @@
|
||||
module Views.AlertList.Types exposing (AlertListMsg(..), Model, Tab(..), initAlertList)
|
||||
module Views.AlertList.Types exposing
|
||||
( AlertListMsg(..)
|
||||
, Model
|
||||
, Tab(..)
|
||||
, initAlertList
|
||||
)
|
||||
|
||||
import Browser.Navigation exposing (Key)
|
||||
import Data.AlertGroup exposing (AlertGroup)
|
||||
import Data.GettableAlert exposing (GettableAlert)
|
||||
import Utils.Types exposing (ApiData(..))
|
||||
import Views.FilterBar.Types as FilterBar
|
||||
@ -10,6 +16,7 @@ import Views.ReceiverBar.Types as ReceiverBar
|
||||
|
||||
type AlertListMsg
|
||||
= AlertsFetched (ApiData (List GettableAlert))
|
||||
| AlertGroupsFetched (ApiData (List AlertGroup))
|
||||
| FetchAlerts
|
||||
| MsgForReceiverBar ReceiverBar.Msg
|
||||
| MsgForFilterBar FilterBar.Msg
|
||||
@ -27,6 +34,7 @@ type Tab
|
||||
|
||||
type alias Model =
|
||||
{ alerts : ApiData (List GettableAlert)
|
||||
, alertGroups : ApiData (List AlertGroup)
|
||||
, receiverBar : ReceiverBar.Model
|
||||
, groupBar : GroupBar.Model
|
||||
, filterBar : FilterBar.Model
|
||||
@ -39,6 +47,7 @@ type alias Model =
|
||||
initAlertList : Key -> Model
|
||||
initAlertList key =
|
||||
{ alerts = Initial
|
||||
, alertGroups = Initial
|
||||
, receiverBar = ReceiverBar.initReceiverBar key
|
||||
, groupBar = GroupBar.initGroupBar key
|
||||
, filterBar = FilterBar.initFilterBar key
|
||||
|
@ -14,21 +14,26 @@ import Views.ReceiverBar.Updates as ReceiverBar
|
||||
|
||||
|
||||
update : AlertListMsg -> Model -> Filter -> String -> String -> ( Model, Cmd Types.Msg )
|
||||
update msg ({ groupBar, filterBar, receiverBar } as model) filter apiUrl basePath =
|
||||
update msg ({ groupBar, alerts, filterBar, receiverBar, alertGroups } as model) filter apiUrl basePath =
|
||||
let
|
||||
alertsUrl =
|
||||
basePath ++ "#/alerts"
|
||||
in
|
||||
case msg of
|
||||
AlertGroupsFetched listOfAlertGroups ->
|
||||
( { model | alertGroups = listOfAlertGroups }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
AlertsFetched listOfAlerts ->
|
||||
( { model
|
||||
| alerts = listOfAlerts
|
||||
, groupBar =
|
||||
case listOfAlerts of
|
||||
Success alerts ->
|
||||
Success ungroupedAlerts ->
|
||||
{ groupBar
|
||||
| list =
|
||||
List.concatMap (.labels >> Dict.toList) alerts
|
||||
List.concatMap (.labels >> Dict.toList) ungroupedAlerts
|
||||
|> List.map Tuple.first
|
||||
|> Set.fromList
|
||||
}
|
||||
@ -47,9 +52,29 @@ update msg ({ groupBar, filterBar, receiverBar } as model) filter apiUrl basePat
|
||||
newFilterBar =
|
||||
FilterBar.setMatchers filter filterBar
|
||||
in
|
||||
( { model | alerts = Loading, filterBar = newFilterBar, groupBar = newGroupBar, activeId = Nothing }
|
||||
( { model
|
||||
| alerts =
|
||||
if filter.customGrouping then
|
||||
Loading
|
||||
|
||||
else
|
||||
alerts
|
||||
, alertGroups =
|
||||
if filter.customGrouping then
|
||||
alertGroups
|
||||
|
||||
else
|
||||
Loading
|
||||
, filterBar = newFilterBar
|
||||
, groupBar = newGroupBar
|
||||
, activeId = Nothing
|
||||
}
|
||||
, Cmd.batch
|
||||
[ Api.fetchAlerts apiUrl filter |> Cmd.map (AlertsFetched >> MsgForAlertList)
|
||||
[ if filter.customGrouping then
|
||||
Api.fetchAlerts apiUrl filter |> Cmd.map (AlertsFetched >> MsgForAlertList)
|
||||
|
||||
else
|
||||
Api.fetchAlertGroups apiUrl filter |> Cmd.map (AlertGroupsFetched >> MsgForAlertList)
|
||||
, ReceiverBar.fetchReceivers apiUrl |> Cmd.map (MsgForReceiverBar >> MsgForAlertList)
|
||||
]
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
module Views.AlertList.Views exposing (view)
|
||||
|
||||
import Data.AlertGroup exposing (AlertGroup)
|
||||
import Data.GettableAlert exposing (GettableAlert)
|
||||
import Dict exposing (Dict)
|
||||
import Html exposing (..)
|
||||
@ -35,15 +36,24 @@ renderCheckbox textLabel maybeShowSilenced toggleMsg =
|
||||
]
|
||||
|
||||
|
||||
groupTabName : Bool -> Html msg
|
||||
groupTabName customGrouping =
|
||||
if customGrouping then
|
||||
text "Group (custom)"
|
||||
|
||||
else
|
||||
text "Group"
|
||||
|
||||
|
||||
view : Model -> Filter -> Html Msg
|
||||
view { alerts, groupBar, filterBar, receiverBar, tab, activeId } filter =
|
||||
view { alerts, alertGroups, groupBar, filterBar, receiverBar, tab, activeId } filter =
|
||||
div []
|
||||
[ div
|
||||
[ class "card mb-5" ]
|
||||
[ div [ class "card-header" ]
|
||||
[ ul [ class "nav nav-tabs card-header-tabs" ]
|
||||
[ Utils.Views.tab FilterTab tab (SetTab >> MsgForAlertList) [ text "Filter" ]
|
||||
, Utils.Views.tab GroupTab tab (SetTab >> MsgForAlertList) [ text "Group" ]
|
||||
, Utils.Views.tab GroupTab tab (SetTab >> MsgForAlertList) [ groupTabName filter.customGrouping ]
|
||||
, receiverBar
|
||||
|> ReceiverBar.view filter.receiver
|
||||
|> Html.map (MsgForReceiverBar >> MsgForAlertList)
|
||||
@ -57,10 +67,14 @@ view { alerts, groupBar, filterBar, receiverBar, tab, activeId } filter =
|
||||
Html.map (MsgForFilterBar >> MsgForAlertList) (FilterBar.view filterBar)
|
||||
|
||||
GroupTab ->
|
||||
Html.map (MsgForGroupBar >> MsgForAlertList) (GroupBar.view groupBar)
|
||||
Html.map (MsgForGroupBar >> MsgForAlertList) (GroupBar.view groupBar filter.customGrouping)
|
||||
]
|
||||
]
|
||||
, Utils.Views.apiData (customAlertGroups activeId groupBar) alerts
|
||||
, if filter.customGrouping then
|
||||
Utils.Views.apiData (customAlertGroups activeId groupBar) alerts
|
||||
|
||||
else
|
||||
Utils.Views.apiData (defaultAlertGroups activeId) alertGroups
|
||||
]
|
||||
|
||||
|
||||
@ -85,6 +99,22 @@ customAlertGroups activeId { fields } ungroupedAlerts =
|
||||
)
|
||||
|
||||
|
||||
defaultAlertGroups : Maybe String -> List AlertGroup -> Html Msg
|
||||
defaultAlertGroups activeId groups =
|
||||
case groups of
|
||||
[] ->
|
||||
Utils.Views.error "No alert groups found"
|
||||
|
||||
_ ->
|
||||
div []
|
||||
(List.map
|
||||
(\{ labels, alerts } ->
|
||||
alertGroup activeId (Dict.toList labels) alerts
|
||||
)
|
||||
groups
|
||||
)
|
||||
|
||||
|
||||
alertGroup : Maybe String -> Labels -> List GettableAlert -> Html Msg
|
||||
alertGroup activeId labels alerts =
|
||||
div []
|
||||
|
@ -25,6 +25,7 @@ type Msg
|
||||
| Focus Bool
|
||||
| ResultsHovered Bool
|
||||
| UpdateFieldText String
|
||||
| CustomGrouping Bool
|
||||
| Noop
|
||||
|
||||
|
||||
|
@ -12,6 +12,14 @@ import Views.GroupBar.Types exposing (Model, Msg(..))
|
||||
update : String -> Filter -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update url filter msg model =
|
||||
case msg of
|
||||
CustomGrouping customGrouping ->
|
||||
( model
|
||||
, Cmd.batch
|
||||
[ Navigation.pushUrl model.key (url ++ generateQueryString { filter | customGrouping = customGrouping })
|
||||
, Dom.focus "group-by-field" |> Task.attempt (always Noop)
|
||||
]
|
||||
)
|
||||
|
||||
AddField emptyFieldText text ->
|
||||
immediatelyFilter url
|
||||
filter
|
||||
|
@ -6,11 +6,12 @@ import Html.Events exposing (keyCode, on, onBlur, onClick, onFocus, onInput, onM
|
||||
import Set
|
||||
import Utils.Keyboard exposing (keys, onKeyDown, onKeyUp)
|
||||
import Utils.List
|
||||
import Utils.Views
|
||||
import Views.GroupBar.Types exposing (Model, Msg(..))
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view ({ list, fieldText, fields } as model) =
|
||||
view : Model -> Bool -> Html Msg
|
||||
view ({ list, fieldText, fields } as model) customGrouping =
|
||||
let
|
||||
isDisabled =
|
||||
not (Set.member fieldText list) || List.member fieldText fields
|
||||
@ -24,20 +25,31 @@ view ({ list, fieldText, fields } as model) =
|
||||
|
||||
else
|
||||
"has-success"
|
||||
|
||||
checkbox =
|
||||
div [ class "mb-3" ]
|
||||
[ Utils.Views.checkbox "Enable custom grouping" customGrouping CustomGrouping ]
|
||||
in
|
||||
div
|
||||
[ class "row no-gutters align-items-start" ]
|
||||
(List.map viewField fields
|
||||
++ [ div
|
||||
[ class ("col " ++ className)
|
||||
, style "min-width" "200px"
|
||||
]
|
||||
[ textInputField isDisabled model
|
||||
, exampleField fields
|
||||
, autoCompleteResults model
|
||||
]
|
||||
]
|
||||
)
|
||||
if customGrouping then
|
||||
div []
|
||||
[ checkbox
|
||||
, div
|
||||
[ class "row no-gutters align-items-start" ]
|
||||
(List.map viewField fields
|
||||
++ [ div
|
||||
[ class ("col " ++ className)
|
||||
, style "min-width" "200px"
|
||||
]
|
||||
[ textInputField isDisabled model
|
||||
, exampleField fields
|
||||
, autoCompleteResults model
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
else
|
||||
checkbox
|
||||
|
||||
|
||||
exampleField : List String -> Html Msg
|
||||
|
@ -9,6 +9,6 @@ silenceListParser : Parser (Filter -> a) a
|
||||
silenceListParser =
|
||||
map
|
||||
(\t ->
|
||||
Filter t Nothing Nothing Nothing Nothing
|
||||
Filter t Nothing False Nothing Nothing Nothing
|
||||
)
|
||||
(s "silences" <?> Query.string "filter")
|
||||
|
@ -101,5 +101,6 @@ updateFilter maybeFilter =
|
||||
, showSilenced = Nothing
|
||||
, showInhibited = Nothing
|
||||
, group = Nothing
|
||||
, customGrouping = False
|
||||
, text = maybeFilter
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user