Allow filtering receiver with a regex

e.g.:
http://localhost:5000/#/alerts?receiver=~(backend|ops)-warn
This commit is contained in:
stuart nelson 2017-04-23 20:15:33 +02:00
parent 88ec956973
commit dc90e8dec3
17 changed files with 79 additions and 45 deletions

View File

@ -3,8 +3,8 @@ module Alerts.Api exposing (..)
import Alerts.Types exposing (Alert, RouteOpts, Block, AlertGroup)
import Json.Decode as Json exposing (..)
import Utils.Api exposing (baseUrl, iso8601Time)
import Utils.Types exposing (ApiData, Filter)
import Utils.Filter exposing (generateQueryString)
import Utils.Types exposing (ApiData)
import Utils.Filter exposing (Filter, generateQueryString)
alertGroups : Filter -> Cmd (ApiData (List AlertGroup))

View File

@ -22,6 +22,7 @@ import Types
, Model
)
import Utils.Types exposing (..)
import Utils.Filter exposing (nullFilter)
import Views.SilenceForm.Types exposing (initSilenceForm)
import Views.Status.Types exposing (StatusModel, initStatusModel)
import Views.AlertList.Types exposing (initAlertList)

View File

@ -2,7 +2,8 @@ module Silences.Api exposing (..)
import Http
import Silences.Types exposing (Silence)
import Utils.Types exposing (Filter, ApiResponse(..), ApiData)
import Utils.Types exposing (ApiResponse(..), ApiData)
import Utils.Filter exposing (Filter)
import Silences.Decoders exposing (..)
import Silences.Encoders
import Utils.Api exposing (baseUrl)

View File

@ -7,7 +7,8 @@ import Views.Silence.Types exposing (SilenceMsg)
import Views.SilenceForm.Types as SilenceForm exposing (SilenceFormMsg)
import Views.Status.Types exposing (StatusModel, StatusMsg)
import Silences.Types exposing (Silence)
import Utils.Types exposing (ApiData, Filter, Label)
import Utils.Types exposing (ApiData, Label)
import Utils.Filter exposing (Filter)
import Time

View File

@ -12,8 +12,8 @@ import Utils.Types
exposing
( ApiResponse(Loading, Failure, Success)
, Matcher
, nullFilter
)
import Utils.Filter exposing (nullFilter)
import Views.AlertList.Updates
import Views.AlertList.Types exposing (AlertListMsg(FetchAlertGroups))
import Views.Silence.Types exposing (SilenceMsg(SilenceFetched, InitSilenceView))

View File

@ -2,6 +2,8 @@ module Utils.Filter
exposing
( Matcher
, MatchOperator(..)
, Filter
, nullFilter
, generateQueryParam
, generateQueryString
, stringifyMatcher
@ -10,7 +12,6 @@ module Utils.Filter
, parseMatcher
)
import Utils.Types exposing (Filter)
import Http exposing (encodeUri)
import Parser exposing (Parser, (|.), (|=), zeroOrMore, ignore)
import Parser.LanguageKit as Parser exposing (Trailing(..))
@ -18,6 +19,21 @@ import Char
import Set
type alias Filter =
{ text : Maybe String
, receiver : Maybe Matcher
, showSilenced : Maybe Bool
}
nullFilter : Filter
nullFilter =
{ text = Nothing
, receiver = Nothing
, showSilenced = Nothing
}
generateQueryParam : String -> Maybe String -> Maybe String
generateQueryParam name =
Maybe.map (encodeUri >> (++) (name ++ "="))
@ -25,8 +41,8 @@ generateQueryParam name =
generateQueryString : Filter -> String
generateQueryString { receiver, showSilenced, text } =
[ ( "receiver", receiver )
, ( "silenced", Maybe.map (toString >> String.toLower) showSilenced )
-- TODO: Re-add receiver once it is parsed on the server side.
[ ( "silenced", Maybe.map (toString >> String.toLower) showSilenced )
, ( "filter", text )
]
|> List.filterMap (uncurry generateQueryParam)

View File

@ -10,21 +10,6 @@ type ApiResponse e a
| Success a
type alias Filter =
{ text : Maybe String
, receiver : Maybe String
, showSilenced : Maybe Bool
}
nullFilter : Filter
nullFilter =
{ text = Nothing
, receiver = Nothing
, showSilenced = Nothing
}
type alias Matcher =
{ name : String
, value : String

View File

@ -2,14 +2,26 @@ module Views.AlertList.Filter exposing (receiver, silenced, matchers)
import Alerts.Types exposing (Alert, AlertGroup, Block)
import Utils.Types exposing (Matchers)
import Regex
import Utils.Filter exposing (Matcher, MatchOperator(Eq, NotEq, RegexMatch, NotRegexMatch))
import Regex exposing (regex, contains)
receiver : Maybe String -> List AlertGroup -> List AlertGroup
receiver : Maybe Matcher -> List AlertGroup -> List AlertGroup
receiver maybeReceiver groups =
case maybeReceiver of
Just receiver ->
by (filterAlertGroup receiver) groups
Just { key, op, value } ->
case op of
Eq ->
by (filterAlertGroup ((==) value)) groups
RegexMatch ->
by (filterAlertGroup ((regex >> contains) value)) groups
NotEq ->
groups
NotRegexMatch ->
groups
Nothing ->
groups
@ -37,11 +49,11 @@ silenced maybeShowSilenced groups =
by alertGroupsSilenced groups
filterAlertGroup : String -> AlertGroup -> Maybe AlertGroup
filterAlertGroup receiver alertGroup =
filterAlertGroup : (String -> Bool) -> AlertGroup -> Maybe AlertGroup
filterAlertGroup fn alertGroup =
let
blocks =
List.filter (\b -> receiver == b.routeOpts.receiver) alertGroup.blocks
List.filter (\b -> fn b.routeOpts.receiver) alertGroup.blocks
in
if not <| List.isEmpty blocks then
Just { alertGroup | blocks = blocks }

View File

@ -1,7 +1,7 @@
module Views.AlertList.Parsing exposing (alertsParser)
import UrlParser exposing ((</>), (<?>), Parser, int, map, oneOf, parseHash, s, string, stringParam)
import Utils.Types exposing (Filter)
import Utils.Filter exposing (Filter, parseMatcher, MatchOperator(Eq, RegexMatch))
boolParam : String -> UrlParser.QueryParser (Maybe Bool -> a) a
@ -22,4 +22,20 @@ boolParam name =
alertsParser : Parser (Filter -> a) a
alertsParser =
map Filter (s "alerts" <?> stringParam "filter" <?> stringParam "receiver" <?> boolParam "silenced")
map
(\filter receiver silenced ->
let
parsed =
case receiver of
Nothing ->
Nothing
Just receiver ->
if String.startsWith "~" receiver then
Just { key = "receiver", op = RegexMatch, value = String.dropLeft 1 receiver }
else
Just { key = "receiver", op = Eq, value = receiver }
in
Filter filter parsed silenced
)
(s "alerts" <?> stringParam "filter" <?> stringParam "receiver" <?> boolParam "silenced")

View File

@ -1,8 +1,8 @@
module Views.AlertList.Types exposing (AlertListMsg(..), Model, initAlertList)
import Utils.Types exposing (ApiData, Filter, ApiResponse(Loading))
import Utils.Types exposing (ApiData, ApiResponse(Loading))
import Alerts.Types exposing (Alert, AlertGroup)
import Utils.Filter
import Utils.Filter exposing (Filter)
type AlertListMsg

View File

@ -3,8 +3,8 @@ module Views.AlertList.Updates exposing (..)
import Alerts.Api as Api
import Views.AlertList.Types exposing (AlertListMsg(..), Model)
import Navigation
import Utils.Types exposing (ApiData, ApiResponse(Loading), Filter)
import Utils.Filter exposing (generateQueryString, stringifyFilter, parseFilter)
import Utils.Types exposing (ApiData, ApiResponse(Loading))
import Utils.Filter exposing (Filter, generateQueryString, stringifyFilter, parseFilter)
import Types exposing (Msg(MsgForAlertList, Noop))
import Dom
import Task

View File

@ -6,8 +6,8 @@ import Views.AlertList.FilterBar
import Html exposing (..)
import Html.Attributes exposing (..)
import Utils.Date
import Utils.Types exposing (ApiResponse(Success, Loading, Failure), Filter)
import Utils.Filter
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))

View File

@ -5,7 +5,8 @@ import Types exposing (Model, Msg(MsgForSilence))
import Silences.Api exposing (getSilence)
import Alerts.Api
import Utils.List
import Utils.Types exposing (ApiResponse(..), nullFilter)
import Utils.Types exposing (ApiResponse(..))
import Utils.Filter exposing (nullFilter)
update : SilenceMsg -> Model -> ( Model, Cmd Msg )

View File

@ -9,7 +9,8 @@ import Navigation
import Types exposing (Msg(MsgForSilenceForm))
import Utils.Date
import Utils.List
import Utils.Types exposing (ApiResponse(..), nullFilter)
import Utils.Types exposing (ApiResponse(..))
import Utils.Filter exposing (nullFilter)
import Views.SilenceForm.Types
exposing
( Model

View File

@ -1,7 +1,7 @@
module Views.SilenceList.Parsing exposing (silenceListParser)
import UrlParser exposing ((<?>), Parser, s, stringParam, map)
import Utils.Types exposing (Filter)
import Utils.Filter exposing (Filter)
silenceListParser : Parser (Filter -> a) a

View File

@ -5,11 +5,10 @@ import Views.SilenceList.Types exposing (SilenceListMsg(..))
import Silences.Types exposing (Silence, nullSilence, nullMatcher)
import Navigation
import Task
import Utils.Types exposing (ApiData, ApiResponse(..), Filter, Matchers)
import Utils.Types as Types exposing (ApiData, ApiResponse(Failure, Loading, Success), Time, Filter, Matchers)
import Utils.Types as Types exposing (ApiData, ApiResponse(Failure, Loading, Success), Time, Matchers)
import Time
import Types exposing (Msg(UpdateCurrentTime, MsgForSilenceList), Route(SilenceListRoute))
import Utils.Filter exposing (generateQueryString)
import Utils.Filter exposing (Filter, generateQueryString)
update : SilenceListMsg -> ApiData (List Silence) -> ApiData Silence -> Filter -> ( ApiData (List Silence), ApiData Silence, Cmd Types.Msg )

View File

@ -8,7 +8,8 @@ import Html.Events exposing (onClick, onInput)
import Views.SilenceList.Types exposing (SilenceListMsg(..))
import Views.Shared.SilenceBase
import Silences.Types exposing (Silence)
import Utils.Types exposing (Matcher, ApiResponse(..), Filter, ApiData)
import Utils.Types exposing (Matcher, ApiResponse(..), ApiData)
import Utils.Filter exposing (Filter)
import Utils.Views exposing (iconButtonMsg, checkbox, textField, formInput, formField, buttonLink, error, loading)
import Time
import Types exposing (Msg(UpdateFilter, MsgForSilenceList, Noop))