mirror of
https://github.com/prometheus/alertmanager
synced 2025-01-19 04:30:56 +00:00
Extract a model for the silence form (#22)
* Extract a model for the silence form * Use empty in initSilenceForm * Use plural silences in urls * Populate matchers from alert * Updating bindata.go file
This commit is contained in:
parent
b6243f55e4
commit
bdd65fdfd7
@ -7,14 +7,13 @@ import Utils.Types exposing (ApiData, Filter)
|
||||
import Utils.Filter exposing (generateQueryString)
|
||||
|
||||
|
||||
getAlertGroups : Filter -> (ApiData (List AlertGroup) -> msg) -> Cmd msg
|
||||
getAlertGroups filter msg =
|
||||
alertGroups : Filter -> Cmd (ApiData (List AlertGroup))
|
||||
alertGroups filter =
|
||||
let
|
||||
url =
|
||||
String.join "/" [ baseUrl, "alerts", "groups" ++ (generateQueryString filter) ]
|
||||
in
|
||||
Utils.Api.send (Utils.Api.get url alertGroupsDecoder)
|
||||
|> Cmd.map msg
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Alerts.Types exposing (Alert, AlertGroup, Block, RouteOpts)
|
||||
|
||||
import Utils.Types exposing (Labels, Time)
|
||||
import Utils.Types exposing (Labels)
|
||||
import Time exposing (Time)
|
||||
|
||||
|
||||
type alias Alert =
|
||||
|
@ -23,6 +23,7 @@ import Types
|
||||
)
|
||||
import Utils.Types exposing (..)
|
||||
import Views.SilenceList.Updates
|
||||
import Views.SilenceForm.Types exposing (initSilenceForm)
|
||||
import Views.Status.Types exposing (StatusModel, initStatusModel)
|
||||
import Updates exposing (update)
|
||||
|
||||
@ -55,7 +56,7 @@ init location =
|
||||
nullFilter
|
||||
|
||||
( model, msg ) =
|
||||
update (urlUpdate location) (Model Loading Loading Loading route filter 0 initStatusModel)
|
||||
update (urlUpdate location) (Model Loading Loading initSilenceForm Loading route filter 0 initStatusModel)
|
||||
in
|
||||
model ! [ msg, Task.perform UpdateCurrentTime Time.now ]
|
||||
|
||||
@ -76,8 +77,8 @@ urlUpdate location =
|
||||
SilenceFormEditRoute silenceId ->
|
||||
NavigateToSilenceFormEdit silenceId
|
||||
|
||||
SilenceFormNewRoute ->
|
||||
NavigateToSilenceFormNew
|
||||
SilenceFormNewRoute keep ->
|
||||
NavigateToSilenceFormNew keep
|
||||
|
||||
AlertsRoute filter ->
|
||||
NavigateToAlerts filter
|
||||
|
@ -51,9 +51,9 @@ routeParser =
|
||||
oneOf
|
||||
[ map SilenceListRoute silenceListParser
|
||||
, map StatusRoute statusParser
|
||||
, map SilenceFormNewRoute silenceFormNewParser
|
||||
, map SilenceRoute silenceParser
|
||||
, map SilenceFormEditRoute silenceFormEditParser
|
||||
, map SilenceFormNewRoute silenceFormNewParser
|
||||
, map AlertsRoute alertsParser
|
||||
, map TopLevelRoute top
|
||||
]
|
||||
|
@ -29,8 +29,8 @@ getSilence uuid msg =
|
||||
|> Cmd.map msg
|
||||
|
||||
|
||||
create : Silence -> (ApiData String -> msg) -> Cmd msg
|
||||
create silence msg =
|
||||
create : Silence -> Cmd (ApiData String)
|
||||
create silence =
|
||||
let
|
||||
url =
|
||||
String.join "/" [ baseUrl, "silences" ]
|
||||
@ -42,7 +42,6 @@ create silence msg =
|
||||
-- redirect to the silence show page.
|
||||
Utils.Api.send
|
||||
(Utils.Api.post url body Silences.Decoders.create)
|
||||
|> Cmd.map msg
|
||||
|
||||
|
||||
destroy : Silence -> (ApiData String -> msg) -> Cmd msg
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Silences.Decoders exposing (..)
|
||||
|
||||
import Json.Decode as Json exposing (field)
|
||||
import Utils.Api exposing (iso8601Time, duration, (|:))
|
||||
import Utils.Api exposing (iso8601Time, (|:))
|
||||
import Silences.Types exposing (Silence)
|
||||
import Utils.Types exposing (Matcher, Time, ApiResponse(Success))
|
||||
|
||||
@ -43,7 +43,6 @@ silence =
|
||||
)
|
||||
|: (field "startsAt" iso8601Time)
|
||||
|: (field "endsAt" iso8601Time)
|
||||
|: (duration "startsAt" "endsAt")
|
||||
|: (field "updatedAt" iso8601Time)
|
||||
|: (field "matchers" (Json.list matcher))
|
||||
|: (Json.succeed <| Success [])
|
||||
|
@ -8,7 +8,6 @@ import Utils.Date
|
||||
|
||||
silence : Silence -> Encode.Value
|
||||
silence silence =
|
||||
-- Todo: only submit validated date
|
||||
Encode.object
|
||||
[ ( "createdBy", Encode.string silence.createdBy )
|
||||
, ( "comment", Encode.string silence.comment )
|
||||
|
@ -1,8 +1,8 @@
|
||||
module Silences.Types exposing (Silence, nullSilence, nullMatcher, nullDuration, nullTime, SilenceId)
|
||||
module Silences.Types exposing (Silence, nullSilence, nullMatcher, nullTime, SilenceId)
|
||||
|
||||
import Utils.Date
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Utils.Types exposing (Duration, Time, Matcher, ApiData, ApiResponse(Success))
|
||||
import Utils.Types exposing (Matcher, ApiData, ApiResponse(Success))
|
||||
import Time exposing (Time)
|
||||
|
||||
|
||||
nullSilence : Silence
|
||||
@ -10,10 +10,9 @@ nullSilence =
|
||||
{ id = ""
|
||||
, createdBy = ""
|
||||
, comment = ""
|
||||
, startsAt = nullTime
|
||||
, endsAt = nullTime
|
||||
, duration = nullDuration
|
||||
, updatedAt = nullTime
|
||||
, startsAt = 0
|
||||
, endsAt = 0
|
||||
, updatedAt = 0
|
||||
, matchers = [ nullMatcher ]
|
||||
, silencedAlertGroups = Success []
|
||||
}
|
||||
@ -24,14 +23,9 @@ nullMatcher =
|
||||
Matcher "" "" False
|
||||
|
||||
|
||||
nullDuration : Duration
|
||||
nullDuration =
|
||||
Utils.Date.duration 0
|
||||
|
||||
|
||||
nullTime : Time
|
||||
nullTime =
|
||||
Utils.Date.fromTime 0
|
||||
0
|
||||
|
||||
|
||||
type alias Silence =
|
||||
@ -40,7 +34,6 @@ type alias Silence =
|
||||
, comment : String
|
||||
, startsAt : Time
|
||||
, endsAt : Time
|
||||
, duration : Duration
|
||||
, updatedAt : Time
|
||||
, matchers : List Matcher
|
||||
, silencedAlertGroups : ApiData (List AlertGroup)
|
||||
|
@ -4,7 +4,7 @@ import Alerts.Types exposing (AlertGroup, Alert)
|
||||
import Views.AlertList.Types exposing (AlertListMsg)
|
||||
import Views.SilenceList.Types exposing (SilenceListMsg)
|
||||
import Views.Silence.Types exposing (SilenceMsg)
|
||||
import Views.SilenceForm.Types exposing (SilenceFormMsg)
|
||||
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)
|
||||
@ -14,6 +14,7 @@ import Time
|
||||
type alias Model =
|
||||
{ silences : ApiData (List Silence)
|
||||
, silence : ApiData Silence
|
||||
, silenceForm : SilenceForm.Model
|
||||
, alertGroups : ApiData (List AlertGroup)
|
||||
, route : Route
|
||||
, filter : Filter
|
||||
@ -24,7 +25,6 @@ type alias Model =
|
||||
|
||||
type Msg
|
||||
= CreateSilenceFromAlert Alert
|
||||
| AlertGroupsPreview (ApiData (List AlertGroup))
|
||||
| MsgForAlertList AlertListMsg
|
||||
| MsgForSilence SilenceMsg
|
||||
| MsgForSilenceForm SilenceFormMsg
|
||||
@ -34,12 +34,10 @@ type Msg
|
||||
| NavigateToNotFound
|
||||
| NavigateToSilence String
|
||||
| NavigateToSilenceFormEdit String
|
||||
| NavigateToSilenceFormNew
|
||||
| NavigateToSilenceFormNew Bool
|
||||
| NavigateToSilenceList Filter
|
||||
| NavigateToStatus
|
||||
| NewUrl String
|
||||
| Noop
|
||||
| PreviewSilence Silence
|
||||
| RedirectAlerts
|
||||
| UpdateCurrentTime Time.Time
|
||||
| UpdateFilter Filter String
|
||||
@ -49,7 +47,7 @@ type Route
|
||||
= AlertsRoute Filter
|
||||
| NotFoundRoute
|
||||
| SilenceFormEditRoute String
|
||||
| SilenceFormNewRoute
|
||||
| SilenceFormNewRoute Bool
|
||||
| SilenceListRoute Filter
|
||||
| SilenceRoute String
|
||||
| StatusRoute
|
||||
|
@ -1,8 +1,6 @@
|
||||
module Updates exposing (update)
|
||||
|
||||
import Alerts.Api
|
||||
import Navigation
|
||||
import Silences.Types exposing (nullSilence)
|
||||
import Task
|
||||
import Types
|
||||
exposing
|
||||
@ -10,7 +8,6 @@ import Types
|
||||
, Model
|
||||
, Route(NotFoundRoute, SilenceFormEditRoute, SilenceFormNewRoute, SilenceRoute, StatusRoute, SilenceListRoute, AlertsRoute)
|
||||
)
|
||||
import Utils.List
|
||||
import Utils.Types
|
||||
exposing
|
||||
( ApiResponse(Loading, Failure, Success)
|
||||
@ -22,7 +19,7 @@ import Views.AlertList.Types exposing (AlertListMsg(FetchAlertGroups))
|
||||
import Views.Silence.Types exposing (SilenceMsg(SilenceFetched, InitSilenceView))
|
||||
import Views.SilenceList.Types exposing (SilenceListMsg(FetchSilences))
|
||||
import Views.Silence.Updates
|
||||
import Views.SilenceForm.Types exposing (SilenceFormMsg(NewSilence, FetchSilence))
|
||||
import Views.SilenceForm.Types exposing (SilenceFormMsg(NewSilenceFromMatchers, FetchSilence))
|
||||
import Views.SilenceForm.Updates
|
||||
import Views.SilenceList.Updates
|
||||
import Views.Status.Types exposing (StatusMsg(InitStatusView))
|
||||
@ -33,37 +30,15 @@ import String exposing (trim)
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
CreateSilenceFromAlert alert ->
|
||||
CreateSilenceFromAlert { labels } ->
|
||||
let
|
||||
silence =
|
||||
{ nullSilence | matchers = (List.map (\( k, v ) -> Matcher k v False) alert.labels) }
|
||||
matchers =
|
||||
List.map (\( k, v ) -> Matcher k v False) labels
|
||||
|
||||
( silenceForm, cmd ) =
|
||||
Views.SilenceForm.Updates.update (NewSilenceFromMatchers matchers) model.silenceForm
|
||||
in
|
||||
( { model | silence = Success silence }, Cmd.none )
|
||||
|
||||
PreviewSilence silence ->
|
||||
let
|
||||
s =
|
||||
{ silence | silencedAlertGroups = Loading }
|
||||
|
||||
filter =
|
||||
{ nullFilter | text = Just <| Utils.List.mjoin s.matchers }
|
||||
in
|
||||
( { model | silence = Success silence }, Alerts.Api.getAlertGroups filter AlertGroupsPreview )
|
||||
|
||||
AlertGroupsPreview alertGroups ->
|
||||
let
|
||||
silence =
|
||||
case model.silence of
|
||||
Success sil ->
|
||||
Success { sil | silencedAlertGroups = alertGroups }
|
||||
|
||||
Failure e ->
|
||||
Failure e
|
||||
|
||||
Loading ->
|
||||
Loading
|
||||
in
|
||||
( { model | silence = silence }, Cmd.none )
|
||||
( { model | silenceForm = silenceForm }, cmd )
|
||||
|
||||
NavigateToAlerts filter ->
|
||||
let
|
||||
@ -94,8 +69,13 @@ update msg model =
|
||||
in
|
||||
( { model | route = (SilenceRoute silenceId) }, cmd )
|
||||
|
||||
NavigateToSilenceFormNew ->
|
||||
( { model | route = SilenceFormNewRoute }, Task.perform identity (Task.succeed <| (MsgForSilenceForm NewSilence)) )
|
||||
NavigateToSilenceFormNew keep ->
|
||||
( { model | route = SilenceFormNewRoute keep }
|
||||
, if keep then
|
||||
Cmd.none
|
||||
else
|
||||
Task.perform (NewSilenceFromMatchers >> MsgForSilenceForm) (Task.succeed [])
|
||||
)
|
||||
|
||||
NavigateToSilenceFormEdit uuid ->
|
||||
( { model | route = SilenceFormEditRoute uuid }, Task.perform identity (Task.succeed <| (FetchSilence uuid |> MsgForSilenceForm)) )
|
||||
@ -104,7 +84,7 @@ update msg model =
|
||||
( { model | route = NotFoundRoute }, Cmd.none )
|
||||
|
||||
RedirectAlerts ->
|
||||
( model, Task.perform NewUrl (Task.succeed "/#/alerts") )
|
||||
( model, Navigation.newUrl "/#/alerts" )
|
||||
|
||||
UpdateFilter filter text ->
|
||||
let
|
||||
@ -116,9 +96,6 @@ update msg model =
|
||||
in
|
||||
( { model | filter = { filter | text = t } }, Cmd.none )
|
||||
|
||||
NewUrl url ->
|
||||
( model, Navigation.newUrl url )
|
||||
|
||||
Noop ->
|
||||
( model, Cmd.none )
|
||||
|
||||
@ -146,4 +123,8 @@ update msg model =
|
||||
Views.Silence.Updates.update msg model
|
||||
|
||||
MsgForSilenceForm msg ->
|
||||
Views.SilenceForm.Updates.update msg model
|
||||
let
|
||||
( silenceForm, cmd ) =
|
||||
Views.SilenceForm.Updates.update msg model.silenceForm
|
||||
in
|
||||
( { model | silenceForm = silenceForm }, cmd )
|
||||
|
@ -1,10 +1,10 @@
|
||||
module Utils.Api exposing (..)
|
||||
|
||||
import Json.Decode as Json exposing (field)
|
||||
import Utils.Types exposing (ApiResponse(..), ApiData, Time, Duration)
|
||||
import Http
|
||||
import Time
|
||||
import Json.Decode as Json exposing (field)
|
||||
import Time exposing (Time)
|
||||
import Utils.Date
|
||||
import Utils.Types exposing (ApiData, ApiResponse(..))
|
||||
|
||||
|
||||
fromResult : Result e a -> ApiResponse e a
|
||||
@ -50,24 +50,18 @@ request method headers url body decoder =
|
||||
}
|
||||
|
||||
|
||||
duration : String -> String -> Json.Decoder Duration
|
||||
duration startsAt endsAt =
|
||||
Json.map2
|
||||
(\t1 t2 ->
|
||||
case ( t1.t, t2.t ) of
|
||||
( Just time1, Just time2 ) ->
|
||||
Utils.Date.duration (time2 - time1)
|
||||
|
||||
_ ->
|
||||
Utils.Date.duration 0
|
||||
)
|
||||
(Json.field startsAt iso8601Time)
|
||||
(Json.field endsAt iso8601Time)
|
||||
|
||||
|
||||
iso8601Time : Json.Decoder Time
|
||||
iso8601Time =
|
||||
Json.map Utils.Date.timeFromString Json.string
|
||||
Json.andThen
|
||||
(\strTime ->
|
||||
case Utils.Date.timeFromString strTime of
|
||||
Just time ->
|
||||
Json.succeed time
|
||||
|
||||
Nothing ->
|
||||
Json.fail ("Could not decode time " ++ strTime)
|
||||
)
|
||||
Json.string
|
||||
|
||||
|
||||
baseUrl : String
|
||||
|
@ -7,9 +7,9 @@ import Utils.Types as Types
|
||||
import Tuple
|
||||
|
||||
|
||||
parseDuration : String -> Result Parser.Error Time.Time
|
||||
parseDuration : String -> Maybe Time.Time
|
||||
parseDuration =
|
||||
Parser.run durationParser
|
||||
Parser.run durationParser >> Result.toMaybe
|
||||
|
||||
|
||||
durationParser : Parser Time.Time
|
||||
@ -29,6 +29,11 @@ units =
|
||||
]
|
||||
|
||||
|
||||
timeToString : Time.Time -> String
|
||||
timeToString =
|
||||
round >> ISO8601.fromTime >> ISO8601.toString
|
||||
|
||||
|
||||
term : Parser Time.Time
|
||||
term =
|
||||
Parser.map2 (*)
|
||||
@ -62,45 +67,21 @@ dateFormat t =
|
||||
String.join "/" <| List.map toString [ ISO8601.month t, ISO8601.day t, ISO8601.year t ]
|
||||
|
||||
|
||||
timeFormat : Types.Time -> String
|
||||
timeFormat { t, s } =
|
||||
t
|
||||
|> Maybe.map (round >> ISO8601.fromTime >> dateFormat)
|
||||
|> Maybe.withDefault s
|
||||
timeFormat : Time.Time -> String
|
||||
timeFormat =
|
||||
round >> ISO8601.fromTime >> dateFormat
|
||||
|
||||
|
||||
encode : Types.Time -> String
|
||||
encode { t, s } =
|
||||
t
|
||||
|> Maybe.map (round >> ISO8601.fromTime >> ISO8601.toString)
|
||||
|> Maybe.withDefault s
|
||||
encode : Time.Time -> String
|
||||
encode =
|
||||
round >> ISO8601.fromTime >> ISO8601.toString
|
||||
|
||||
|
||||
timeFromString : String -> Types.Time
|
||||
timeFromString toParse =
|
||||
{ s = toParse
|
||||
, t =
|
||||
toParse
|
||||
|> ISO8601.fromString
|
||||
|> Result.toMaybe
|
||||
|> Maybe.map (ISO8601.toTime >> toFloat)
|
||||
}
|
||||
|
||||
|
||||
durationFromString : String -> Types.Duration
|
||||
durationFromString toParse =
|
||||
{ s = toParse
|
||||
, d =
|
||||
toParse
|
||||
|> parseDuration
|
||||
|> Result.mapError (Debug.log "error")
|
||||
|> Result.toMaybe
|
||||
}
|
||||
|
||||
|
||||
duration : Time.Time -> Types.Duration
|
||||
duration time =
|
||||
{ d = Just time, s = durationFormat time }
|
||||
timeFromString : String -> Maybe Time.Time
|
||||
timeFromString =
|
||||
ISO8601.fromString
|
||||
>> Result.toMaybe
|
||||
>> Maybe.map (ISO8601.toTime >> toFloat)
|
||||
|
||||
|
||||
fromTime : Time.Time -> Types.Time
|
||||
|
@ -15,6 +15,18 @@ replaceIf predicate replacement list =
|
||||
list
|
||||
|
||||
|
||||
replaceIndex : Int -> (a -> a) -> List a -> List a
|
||||
replaceIndex index replacement list =
|
||||
List.indexedMap
|
||||
(\currentIndex item ->
|
||||
if index == currentIndex then
|
||||
replacement item
|
||||
else
|
||||
item
|
||||
)
|
||||
list
|
||||
|
||||
|
||||
mjoin : Matchers -> String
|
||||
mjoin m =
|
||||
String.join "," (List.map mstring m)
|
||||
|
@ -2,7 +2,7 @@ module Views exposing (..)
|
||||
|
||||
import Html exposing (Html, text, div)
|
||||
import Html.Attributes exposing (class)
|
||||
import Types exposing (Msg, Model, Route(..))
|
||||
import Types exposing (Msg(MsgForSilenceForm), Model, Route(..))
|
||||
import Utils.Types exposing (ApiResponse(..))
|
||||
import Utils.Views exposing (error, loading)
|
||||
import Views.SilenceList.Views as SilenceList
|
||||
@ -55,11 +55,11 @@ appBody model =
|
||||
SilenceListRoute route ->
|
||||
SilenceList.view model.silences model.silence model.currentTime model.filter
|
||||
|
||||
SilenceFormNewRoute ->
|
||||
SilenceForm.new model.silence
|
||||
SilenceFormNewRoute keep ->
|
||||
SilenceForm.view Nothing model.silenceForm |> Html.map MsgForSilenceForm
|
||||
|
||||
SilenceFormEditRoute silenceId ->
|
||||
SilenceForm.edit model.silence
|
||||
SilenceForm.view (Just silenceId) model.silenceForm |> Html.map MsgForSilenceForm
|
||||
|
||||
TopLevelRoute ->
|
||||
Utils.Views.loading
|
||||
|
@ -3,10 +3,10 @@ module Views.AlertList.Updates exposing (..)
|
||||
import Alerts.Api as Api
|
||||
import Views.AlertList.Types exposing (AlertListMsg(..))
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Task
|
||||
import Navigation
|
||||
import Utils.Types exposing (ApiData, ApiResponse(..), Filter)
|
||||
import Utils.Filter exposing (generateQueryString)
|
||||
import Types exposing (Msg(MsgForAlertList, NewUrl))
|
||||
import Types exposing (Msg(MsgForAlertList))
|
||||
|
||||
|
||||
update : AlertListMsg -> ApiData (List AlertGroup) -> Filter -> ( ApiData (List AlertGroup), Cmd Types.Msg )
|
||||
@ -16,11 +16,7 @@ update msg groups filter =
|
||||
( alertGroups, Cmd.none )
|
||||
|
||||
FetchAlertGroups ->
|
||||
( groups, Api.getAlertGroups filter (AlertGroupsFetch >> MsgForAlertList) )
|
||||
( groups, Api.alertGroups filter |> Cmd.map (AlertGroupsFetch >> MsgForAlertList) )
|
||||
|
||||
FilterAlerts ->
|
||||
let
|
||||
url =
|
||||
"/#/alerts" ++ generateQueryString filter
|
||||
in
|
||||
( groups, Task.perform identity (Task.succeed (Types.NewUrl url)) )
|
||||
( groups, Navigation.newUrl ("/#/alerts" ++ generateQueryString filter) )
|
||||
|
@ -68,9 +68,9 @@ alertView alert =
|
||||
|
||||
b =
|
||||
if alert.silenced then
|
||||
buttonLink "fa-deaf" ("#/silences/" ++ id) "blue" (Types.Noop)
|
||||
buttonLink "fa-deaf" ("#/silences/" ++ id) "blue" Types.Noop
|
||||
else
|
||||
buttonLink "fa-exclamation-triangle" "#/silences/new" "dark-red" (CreateSilenceFromAlert alert)
|
||||
buttonLink "fa-exclamation-triangle" "#/silences/new?keep=1" "dark-red" (CreateSilenceFromAlert alert)
|
||||
in
|
||||
div [ class "f6 mb3" ]
|
||||
[ div [ class "mb1" ]
|
||||
|
@ -5,9 +5,10 @@ import Html exposing (Html, ul)
|
||||
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" ]
|
||||
blocks
|
||||
|> List.concatMap .alerts
|
||||
|> List.indexedMap Views.Shared.AlertCompact.view
|
||||
|> ul [ class "list pa0" ]
|
||||
|
@ -27,7 +27,7 @@ view silence =
|
||||
div [ class "f6 mb3" ]
|
||||
[ a
|
||||
[ class "db link blue mb3"
|
||||
, href ("#/silence/" ++ silence.id)
|
||||
, href ("#/silences/" ++ silence.id)
|
||||
]
|
||||
[ b [ class "db f4 mb1" ]
|
||||
[ text alertName ]
|
||||
|
@ -5,4 +5,4 @@ import UrlParser exposing (Parser, s, string, (</>))
|
||||
|
||||
silenceParser : Parser (String -> a) a
|
||||
silenceParser =
|
||||
s "silence" </> string
|
||||
s "silences" </> string
|
||||
|
@ -1,10 +1,12 @@
|
||||
module Views.Silence.Types exposing (SilenceMsg(..))
|
||||
|
||||
import Silences.Types exposing (Silence, SilenceId)
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Utils.Types exposing (ApiData)
|
||||
|
||||
|
||||
type SilenceMsg
|
||||
= FetchSilence String
|
||||
| SilenceFetched (ApiData Silence)
|
||||
| AlertGroupsPreview (ApiData (List AlertGroup))
|
||||
| InitSilenceView SilenceId
|
||||
|
@ -3,9 +3,9 @@ module Views.Silence.Updates exposing (update)
|
||||
import Views.Silence.Types exposing (SilenceMsg(..))
|
||||
import Types exposing (Model, Msg(MsgForSilence))
|
||||
import Silences.Api exposing (getSilence)
|
||||
import Utils.Types exposing (ApiResponse(Success))
|
||||
import Task
|
||||
import Types exposing (Msg(PreviewSilence))
|
||||
import Alerts.Api
|
||||
import Utils.List
|
||||
import Utils.Types exposing (ApiResponse(..), nullFilter)
|
||||
|
||||
|
||||
update : SilenceMsg -> Model -> ( Model, Cmd Msg )
|
||||
@ -14,9 +14,27 @@ update msg model =
|
||||
FetchSilence id ->
|
||||
( model, getSilence id (SilenceFetched >> MsgForSilence) )
|
||||
|
||||
SilenceFetched (Success sil) ->
|
||||
( { model | silence = Success sil }
|
||||
, Task.perform PreviewSilence (Task.succeed sil)
|
||||
AlertGroupsPreview alertGroups ->
|
||||
case model.silence of
|
||||
Success silence ->
|
||||
( { model
|
||||
| silence =
|
||||
Success
|
||||
{ silence | silencedAlertGroups = alertGroups }
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
_ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
SilenceFetched (Success silence) ->
|
||||
( { model
|
||||
| silence = Success { silence | silencedAlertGroups = Loading }
|
||||
}
|
||||
, Alerts.Api.alertGroups
|
||||
({ nullFilter | text = Just (Utils.List.mjoin silence.matchers) })
|
||||
|> Cmd.map (AlertGroupsPreview >> MsgForSilence)
|
||||
)
|
||||
|
||||
SilenceFetched silence ->
|
||||
|
@ -3,7 +3,7 @@ module Views.Silence.Views exposing (view)
|
||||
import Silences.Types exposing (Silence)
|
||||
import Html exposing (Html, div, h2, p, text, label)
|
||||
import Html.Attributes exposing (class)
|
||||
import Time
|
||||
import Time exposing (Time)
|
||||
import Types exposing (Model, Msg)
|
||||
import Utils.Types exposing (ApiResponse(Success, Loading, Failure))
|
||||
import Utils.Views exposing (loading, error)
|
||||
@ -24,7 +24,7 @@ view model =
|
||||
error msg
|
||||
|
||||
|
||||
silence : Silence -> Time.Time -> Html Msg
|
||||
silence : Silence -> Time -> Html Msg
|
||||
silence silence currentTime =
|
||||
div []
|
||||
[ Views.Shared.SilenceBase.view silence
|
||||
@ -34,7 +34,7 @@ silence silence currentTime =
|
||||
]
|
||||
|
||||
|
||||
silenceExtra : Silence -> Time.Time -> Html msg
|
||||
silenceExtra : Silence -> Time -> Html msg
|
||||
silenceExtra silence currentTime =
|
||||
div [ class "f6" ]
|
||||
[ div [ class "mb1" ]
|
||||
@ -54,18 +54,11 @@ silenceExtra silence currentTime =
|
||||
]
|
||||
|
||||
|
||||
status : Silence -> Time.Time -> String
|
||||
status silence currentTime =
|
||||
let
|
||||
et =
|
||||
Maybe.withDefault currentTime silence.endsAt.t
|
||||
|
||||
st =
|
||||
Maybe.withDefault currentTime silence.startsAt.t
|
||||
in
|
||||
if et <= currentTime then
|
||||
"expired"
|
||||
else if st > currentTime then
|
||||
"pending"
|
||||
else
|
||||
"active"
|
||||
status : Silence -> Time -> String
|
||||
status { endsAt, startsAt } currentTime =
|
||||
if endsAt <= currentTime then
|
||||
"expired"
|
||||
else if startsAt > currentTime then
|
||||
"pending"
|
||||
else
|
||||
"active"
|
||||
|
@ -1,11 +1,14 @@
|
||||
module Views.SilenceForm.Parsing exposing (silenceFormNewParser, silenceFormEditParser)
|
||||
|
||||
import UrlParser exposing (Parser, s, (</>), string, oneOf, map)
|
||||
import UrlParser exposing (Parser, s, (</>), (<?>), string, stringParam, oneOf, map)
|
||||
|
||||
|
||||
silenceFormNewParser : Parser a a
|
||||
silenceFormNewParser : Parser (Bool -> a) a
|
||||
silenceFormNewParser =
|
||||
s "silences" </> s "new"
|
||||
s "silences"
|
||||
</> s "new"
|
||||
<?> stringParam "keep"
|
||||
|> map (Maybe.map (always True) >> Maybe.withDefault False)
|
||||
|
||||
|
||||
silenceFormEditParser : Parser (String -> a) a
|
||||
|
@ -1,24 +1,120 @@
|
||||
module Views.SilenceForm.Types exposing (SilenceFormMsg(..))
|
||||
module Views.SilenceForm.Types
|
||||
exposing
|
||||
( SilenceFormMsg(..)
|
||||
, SilenceFormFieldMsg(..)
|
||||
, Model
|
||||
, SilenceForm
|
||||
, fromMatchersAndTime
|
||||
, fromSilence
|
||||
, toSilence
|
||||
, initSilenceForm
|
||||
)
|
||||
|
||||
import Silences.Types exposing (Silence)
|
||||
import Utils.Types exposing (Matcher, ApiData)
|
||||
import Time
|
||||
import Silences.Types exposing (Silence, SilenceId)
|
||||
import Alerts.Types exposing (AlertGroup)
|
||||
import Utils.Types exposing (Matcher, ApiData, Duration, ApiResponse(..))
|
||||
import Time exposing (Time)
|
||||
import Utils.Date exposing (timeToString, timeFromString, durationFormat)
|
||||
|
||||
|
||||
initSilenceForm : Model
|
||||
initSilenceForm =
|
||||
{ form = empty
|
||||
, silence = Err "Empty"
|
||||
}
|
||||
|
||||
|
||||
toSilence : SilenceForm -> Result String Silence
|
||||
toSilence { createdBy, comment, startsAt, endsAt, matchers } =
|
||||
Maybe.map2
|
||||
(\parsedStartsAt parsedEndsAt ->
|
||||
{ comment = comment
|
||||
, matchers = matchers
|
||||
, createdBy = createdBy
|
||||
, startsAt = parsedStartsAt
|
||||
, endsAt = parsedEndsAt
|
||||
, silencedAlertGroups = Success [] {- ignored -}
|
||||
, updatedAt = 0 {- ignored -}
|
||||
, id = "" {- ignored -}
|
||||
}
|
||||
)
|
||||
(timeFromString startsAt)
|
||||
(timeFromString endsAt)
|
||||
|> Result.fromMaybe "Wrong datetime format"
|
||||
|
||||
|
||||
fromSilence : Silence -> SilenceForm
|
||||
fromSilence { createdBy, comment, startsAt, endsAt, matchers } =
|
||||
{ createdBy = createdBy
|
||||
, comment = comment
|
||||
, startsAt = timeToString startsAt
|
||||
, endsAt = timeToString endsAt
|
||||
, duration = durationFormat (endsAt - startsAt)
|
||||
, matchers = matchers
|
||||
}
|
||||
|
||||
|
||||
empty : SilenceForm
|
||||
empty =
|
||||
{ createdBy = ""
|
||||
, comment = ""
|
||||
, startsAt = ""
|
||||
, endsAt = ""
|
||||
, duration = ""
|
||||
, matchers = []
|
||||
}
|
||||
|
||||
|
||||
fromMatchersAndTime : List Matcher -> Time -> SilenceForm
|
||||
fromMatchersAndTime matchers now =
|
||||
let
|
||||
duration =
|
||||
2 * Time.hour
|
||||
in
|
||||
{ empty
|
||||
| startsAt = timeToString now
|
||||
, endsAt = timeToString (now + duration)
|
||||
, duration = durationFormat duration
|
||||
, matchers = matchers
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ silence : Result String Silence
|
||||
, form : SilenceForm
|
||||
}
|
||||
|
||||
|
||||
type alias SilenceForm =
|
||||
{ createdBy : String
|
||||
, comment : String
|
||||
, startsAt : String
|
||||
, endsAt : String
|
||||
, duration : String
|
||||
, matchers : List Matcher
|
||||
}
|
||||
|
||||
|
||||
type SilenceFormMsg
|
||||
= AddMatcher Silence
|
||||
| NewDefaultTimeRange Time.Time
|
||||
= UpdateField SilenceFormFieldMsg
|
||||
| CreateSilence Silence
|
||||
| PreviewSilence Silence
|
||||
| AlertGroupsPreview (ApiData (List AlertGroup))
|
||||
| FetchSilence String
|
||||
| NewSilence
|
||||
| NewSilenceFromMatchers (List Matcher)
|
||||
| NewSilenceFromMatchersAndTime (List Matcher) Time
|
||||
| SilenceFetch (ApiData Silence)
|
||||
| UpdateCreatedBy Silence String
|
||||
| DeleteMatcher Silence Matcher
|
||||
| UpdateDuration Silence String
|
||||
| UpdateEndsAt Silence String
|
||||
| UpdateMatcherName Silence Matcher String
|
||||
| UpdateMatcherRegex Silence Matcher Bool
|
||||
| UpdateMatcherValue Silence Matcher String
|
||||
| UpdateStartsAt Silence String
|
||||
| SilenceCreate (ApiData String)
|
||||
| UpdateComment Silence String
|
||||
|
||||
|
||||
type SilenceFormFieldMsg
|
||||
= AddMatcher
|
||||
| UpdateStartsAt String
|
||||
| UpdateEndsAt String
|
||||
| UpdateDuration String
|
||||
| UpdateCreatedBy String
|
||||
| UpdateComment String
|
||||
| DeleteMatcher Int
|
||||
| UpdateMatcherName Int String
|
||||
| UpdateMatcherValue Int String
|
||||
| UpdateMatcherRegex Int Bool
|
||||
|
@ -1,29 +1,34 @@
|
||||
module Views.SilenceForm.Updates exposing (update)
|
||||
|
||||
import Views.SilenceForm.Types exposing (SilenceFormMsg(..))
|
||||
import Types exposing (Model, Msg(MsgForSilenceForm, NewUrl, PreviewSilence))
|
||||
import Utils.Types exposing (ApiResponse(Success, Loading, Failure))
|
||||
import Utils.List
|
||||
import Utils.Date
|
||||
import Alerts.Api
|
||||
import Silences.Api
|
||||
import Silences.Types exposing (nullMatcher, nullSilence)
|
||||
import Task
|
||||
import Time
|
||||
import Navigation
|
||||
import Types exposing (Msg(MsgForSilenceForm))
|
||||
import Utils.Date
|
||||
import Utils.List
|
||||
import Utils.Types exposing (ApiResponse(..), nullFilter)
|
||||
import Views.SilenceForm.Types
|
||||
exposing
|
||||
( Model
|
||||
, SilenceForm
|
||||
, SilenceFormMsg(..)
|
||||
, SilenceFormFieldMsg(..)
|
||||
, fromMatchersAndTime
|
||||
, fromSilence
|
||||
, toSilence
|
||||
)
|
||||
|
||||
|
||||
update : SilenceFormMsg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
updateForm : SilenceFormFieldMsg -> SilenceForm -> SilenceForm
|
||||
updateForm msg form =
|
||||
case msg of
|
||||
AddMatcher silence ->
|
||||
-- TODO: If a user adds two blank matchers and attempts to update
|
||||
-- one, both are updated because they are identical. Maybe add a
|
||||
-- unique identifier on creation so this doesn't happen.
|
||||
( { model | silence = Success { silence | matchers = silence.matchers ++ [ nullMatcher ] } }, Cmd.none )
|
||||
AddMatcher ->
|
||||
{ form | matchers = form.matchers ++ [ nullMatcher ] }
|
||||
|
||||
CreateSilence silence ->
|
||||
( { model | silence = Loading }, Silences.Api.create silence (SilenceCreate >> MsgForSilenceForm) )
|
||||
|
||||
UpdateStartsAt silence time ->
|
||||
UpdateStartsAt time ->
|
||||
-- TODO:
|
||||
-- Update silence to hold datetime as string, on each pass through
|
||||
-- here update an error message "this is invalid", but let them put
|
||||
@ -32,119 +37,142 @@ update msg model =
|
||||
startsAt =
|
||||
Utils.Date.timeFromString time
|
||||
|
||||
duration =
|
||||
Maybe.map2 (-) silence.endsAt.t startsAt.t
|
||||
|> Maybe.map Utils.Date.duration
|
||||
|> Maybe.withDefault silence.duration
|
||||
in
|
||||
( { model | silence = Success { silence | startsAt = startsAt, duration = duration } }, Cmd.none )
|
||||
endsAt =
|
||||
Utils.Date.timeFromString form.endsAt
|
||||
|
||||
UpdateEndsAt silence time ->
|
||||
duration =
|
||||
Maybe.map2 (-) endsAt startsAt
|
||||
|> Maybe.map Utils.Date.durationFormat
|
||||
|> Maybe.withDefault ""
|
||||
in
|
||||
{ form | startsAt = time, duration = duration }
|
||||
|
||||
UpdateEndsAt time ->
|
||||
let
|
||||
startsAt =
|
||||
Utils.Date.timeFromString form.startsAt
|
||||
|
||||
endsAt =
|
||||
Utils.Date.timeFromString time
|
||||
|
||||
duration =
|
||||
Maybe.map2 (-) endsAt.t silence.startsAt.t
|
||||
|> Maybe.map Utils.Date.duration
|
||||
|> Maybe.withDefault silence.duration
|
||||
Maybe.map2 (-) endsAt startsAt
|
||||
|> Maybe.map Utils.Date.durationFormat
|
||||
|> Maybe.withDefault ""
|
||||
in
|
||||
( { model | silence = Success { silence | endsAt = endsAt, duration = duration } }, Cmd.none )
|
||||
{ form | endsAt = time, duration = duration }
|
||||
|
||||
UpdateDuration silence time ->
|
||||
UpdateDuration time ->
|
||||
let
|
||||
startsAt =
|
||||
Utils.Date.timeFromString form.startsAt
|
||||
|
||||
duration =
|
||||
Utils.Date.durationFromString time
|
||||
Utils.Date.parseDuration time
|
||||
|
||||
endsAt =
|
||||
Maybe.map2 (+) silence.startsAt.t duration.d
|
||||
|> Maybe.map Utils.Date.fromTime
|
||||
|> Maybe.withDefault silence.endsAt
|
||||
Maybe.map2 (+) startsAt duration
|
||||
|> Maybe.map Utils.Date.timeToString
|
||||
|> Maybe.withDefault form.endsAt
|
||||
in
|
||||
( { model | silence = Success { silence | duration = duration, endsAt = endsAt } }, Cmd.none )
|
||||
{ form | endsAt = endsAt, duration = time }
|
||||
|
||||
UpdateCreatedBy silence by ->
|
||||
( { model | silence = Success { silence | createdBy = by } }, Cmd.none )
|
||||
UpdateCreatedBy createdBy ->
|
||||
{ form | createdBy = createdBy }
|
||||
|
||||
UpdateComment comment ->
|
||||
{ form | comment = comment }
|
||||
|
||||
DeleteMatcher index ->
|
||||
{ form | matchers = List.take index form.matchers ++ List.drop (index + 1) form.matchers }
|
||||
|
||||
UpdateMatcherName index name ->
|
||||
{ form
|
||||
| matchers =
|
||||
Utils.List.replaceIndex index
|
||||
(\matcher -> { matcher | name = name })
|
||||
form.matchers
|
||||
}
|
||||
|
||||
UpdateMatcherValue index value ->
|
||||
{ form
|
||||
| matchers =
|
||||
Utils.List.replaceIndex index
|
||||
(\matcher -> { matcher | value = value })
|
||||
form.matchers
|
||||
}
|
||||
|
||||
UpdateMatcherRegex index isRegex ->
|
||||
{ form
|
||||
| matchers =
|
||||
Utils.List.replaceIndex index
|
||||
(\matcher -> { matcher | isRegex = isRegex })
|
||||
form.matchers
|
||||
}
|
||||
|
||||
|
||||
update : SilenceFormMsg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
CreateSilence silence ->
|
||||
( model
|
||||
, Silences.Api.create silence
|
||||
|> Cmd.map (SilenceCreate >> MsgForSilenceForm)
|
||||
)
|
||||
|
||||
SilenceCreate silence ->
|
||||
case silence of
|
||||
Success id ->
|
||||
( { model | silence = Loading }, Task.perform identity (Task.succeed <| NewUrl ("/#/silence/" ++ id)) )
|
||||
( model, Navigation.newUrl ("/#/silences/" ++ id) )
|
||||
|
||||
Failure err ->
|
||||
( { model | silence = Failure err }, Task.perform identity (Task.succeed <| NewUrl "/#/silence") )
|
||||
( model, Navigation.newUrl "/#/silences" )
|
||||
|
||||
Loading ->
|
||||
( { model | silence = Loading }, Task.perform identity (Task.succeed <| NewUrl "/#/silence") )
|
||||
( model, Navigation.newUrl "/#/silences" )
|
||||
|
||||
UpdateComment silence comment ->
|
||||
( { model | silence = Success { silence | comment = comment } }, Cmd.none )
|
||||
NewSilenceFromMatchers matchers ->
|
||||
( model, Task.perform (NewSilenceFromMatchersAndTime matchers >> MsgForSilenceForm) Time.now )
|
||||
|
||||
DeleteMatcher silence matcher ->
|
||||
let
|
||||
-- TODO: This removes all empty matchers. Maybe just remove the
|
||||
-- one that was clicked.
|
||||
newSil =
|
||||
{ silence | matchers = (List.filter (\x -> x /= matcher) silence.matchers) }
|
||||
in
|
||||
( { model | silence = Success newSil }, Cmd.none )
|
||||
|
||||
UpdateMatcherName silence matcher name ->
|
||||
let
|
||||
matchers =
|
||||
Utils.List.replaceIf (\x -> x == matcher) { matcher | name = name } silence.matchers
|
||||
in
|
||||
( { model | silence = Success { silence | matchers = matchers } }, Cmd.none )
|
||||
|
||||
UpdateMatcherValue silence matcher value ->
|
||||
let
|
||||
matchers =
|
||||
Utils.List.replaceIf (\x -> x == matcher) { matcher | value = value } silence.matchers
|
||||
in
|
||||
( { model | silence = Success { silence | matchers = matchers } }, Cmd.none )
|
||||
|
||||
UpdateMatcherRegex silence matcher bool ->
|
||||
let
|
||||
matchers =
|
||||
Utils.List.replaceIf (\x -> x == matcher) { matcher | isRegex = bool } silence.matchers
|
||||
in
|
||||
( { model | silence = Success { silence | matchers = matchers } }, Cmd.none )
|
||||
|
||||
NewDefaultTimeRange time ->
|
||||
let
|
||||
startsAt =
|
||||
Utils.Date.fromTime time
|
||||
|
||||
duration =
|
||||
Utils.Date.duration (2 * Time.hour)
|
||||
|
||||
endsAt =
|
||||
Utils.Date.fromTime (time + 2 * Time.hour)
|
||||
|
||||
sil =
|
||||
case model.silence of
|
||||
Success s ->
|
||||
s
|
||||
|
||||
_ ->
|
||||
nullSilence
|
||||
in
|
||||
( { model | silence = Success { sil | startsAt = startsAt, duration = duration, endsAt = endsAt } }, Cmd.none )
|
||||
NewSilenceFromMatchersAndTime matchers time ->
|
||||
( { model | form = fromMatchersAndTime matchers time }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
FetchSilence silenceId ->
|
||||
( { model | silence = model.silence }, Silences.Api.getSilence silenceId (SilenceFetch >> MsgForSilenceForm) )
|
||||
( model, Silences.Api.getSilence silenceId (SilenceFetch >> MsgForSilenceForm) )
|
||||
|
||||
NewSilence ->
|
||||
( { model | silence = model.silence }, Cmd.map MsgForSilenceForm (Task.perform NewDefaultTimeRange Time.now) )
|
||||
SilenceFetch (Success silence) ->
|
||||
( { model | form = fromSilence silence, silence = Ok silence }
|
||||
, Task.perform (PreviewSilence >> MsgForSilenceForm) (Task.succeed silence)
|
||||
)
|
||||
|
||||
SilenceFetch sil ->
|
||||
SilenceFetch _ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
PreviewSilence silence ->
|
||||
( { model | silence = Ok { silence | silencedAlertGroups = Loading } }
|
||||
, Alerts.Api.alertGroups
|
||||
{ nullFilter | text = Just (Utils.List.mjoin silence.matchers) }
|
||||
|> Cmd.map (AlertGroupsPreview >> MsgForSilenceForm)
|
||||
)
|
||||
|
||||
AlertGroupsPreview alertGroups ->
|
||||
case model.silence of
|
||||
Ok sil ->
|
||||
( { model | silence = Ok { sil | silencedAlertGroups = alertGroups } }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Err _ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
UpdateField fieldMsg ->
|
||||
let
|
||||
cmd =
|
||||
case sil of
|
||||
Success sil ->
|
||||
Task.perform identity (Task.succeed (PreviewSilence sil))
|
||||
newForm =
|
||||
updateForm fieldMsg model.form
|
||||
|
||||
_ ->
|
||||
Cmd.none
|
||||
newSilence =
|
||||
toSilence newForm
|
||||
in
|
||||
( { model | silence = sil }, cmd )
|
||||
( { form = newForm, silence = newSilence }, Cmd.none )
|
||||
|
@ -1,74 +1,36 @@
|
||||
module Views.SilenceForm.Views exposing (edit, new)
|
||||
module Views.SilenceForm.Views exposing (view)
|
||||
|
||||
import Html exposing (Html, div, text, fieldset, legend, label, span, a)
|
||||
import Html exposing (Html, a, div, fieldset, label, legend, span, text)
|
||||
import Html.Attributes exposing (class, href)
|
||||
import Html.Events exposing (onClick)
|
||||
import Silences.Types exposing (Silence)
|
||||
import Types exposing (Msg(MsgForSilenceList, PreviewSilence, MsgForSilenceForm), Model)
|
||||
import Utils.Types exposing (Matcher, ApiResponse(Success, Loading, Failure), ApiData)
|
||||
import Utils.Views exposing (loading, error, checkbox)
|
||||
import Silences.Types exposing (Silence, SilenceId)
|
||||
import Utils.Types exposing (ApiData, ApiResponse(..), Matcher)
|
||||
import Utils.Views exposing (checkbox, error, formField, formInput, iconButtonMsg, textField)
|
||||
import Views.Shared.SilencePreview
|
||||
import Utils.Views exposing (formField, iconButtonMsg, textField, formInput)
|
||||
import Views.SilenceForm.Types
|
||||
exposing
|
||||
( SilenceFormMsg(UpdateStartsAt, UpdateCreatedBy, UpdateDuration, UpdateEndsAt, UpdateComment, AddMatcher, CreateSilence, DeleteMatcher, UpdateMatcherRegex, UpdateMatcherValue, UpdateMatcherName)
|
||||
)
|
||||
import Views.SilenceForm.Types exposing (Model, SilenceFormMsg(..))
|
||||
import Utils.Views exposing (checkbox, formField, formInput, iconButtonMsg, textField)
|
||||
import Views.Shared.SilencePreview
|
||||
import Views.SilenceForm.Types exposing (Model, SilenceFormMsg(..), SilenceFormFieldMsg(..))
|
||||
|
||||
|
||||
edit : ApiData Silence -> Html Msg
|
||||
edit silence =
|
||||
case silence of
|
||||
Success silence ->
|
||||
silenceForm "Edit" silence
|
||||
|
||||
Loading ->
|
||||
loading
|
||||
|
||||
Failure msg ->
|
||||
error msg
|
||||
|
||||
|
||||
new : ApiData Silence -> Html Msg
|
||||
new silence =
|
||||
case silence of
|
||||
Success silence ->
|
||||
silenceForm "New" silence
|
||||
|
||||
Loading ->
|
||||
loading
|
||||
|
||||
Failure msg ->
|
||||
error msg
|
||||
|
||||
|
||||
silenceForm : String -> Silence -> Html Msg
|
||||
silenceForm kind silence =
|
||||
-- TODO: Add field validations.
|
||||
view : Maybe SilenceId -> Model -> Html SilenceFormMsg
|
||||
view maybeId { silence, form } =
|
||||
let
|
||||
base =
|
||||
"/#/silence/"
|
||||
( title, resetClick ) =
|
||||
case maybeId of
|
||||
Just silenceId ->
|
||||
( "Edit Silence", FetchSilence silenceId )
|
||||
|
||||
boundMatcherForm =
|
||||
matcherForm silence
|
||||
|
||||
url =
|
||||
case kind of
|
||||
"New" ->
|
||||
base ++ "new"
|
||||
|
||||
"Edit" ->
|
||||
base ++ (toString silence.id) ++ "/edit"
|
||||
|
||||
_ ->
|
||||
"/#/silences"
|
||||
Nothing ->
|
||||
( "New Silence", NewSilenceFromMatchers [] )
|
||||
in
|
||||
div []
|
||||
[ div [ class "pa4 black-80" ]
|
||||
[ fieldset [ class "ba b--transparent ph0 mh0" ]
|
||||
[ legend [ class "ph0 mh0 fw6" ] [ text <| kind ++ " Silence" ]
|
||||
, (formField "Start" silence.startsAt.s (UpdateStartsAt silence))
|
||||
, div [ class "dib mb2 mr2 w-40" ] [ formField "End" silence.endsAt.s (UpdateEndsAt silence) ]
|
||||
, div [ class "dib mb2 mr2 w-40" ] [ formField "Duration" silence.duration.s (UpdateDuration silence) ]
|
||||
[ legend [ class "ph0 mh0 fw6" ] [ text title ]
|
||||
, (formField "Start" form.startsAt (UpdateStartsAt >> UpdateField))
|
||||
, div [ class "dib mb2 mr2 w-40" ] [ formField "End" form.endsAt (UpdateEndsAt >> UpdateField) ]
|
||||
, div [ class "dib mb2 mr2 w-40" ] [ formField "Duration" form.duration (UpdateDuration >> UpdateField) ]
|
||||
, div [ class "mt3" ]
|
||||
[ label [ class "f6 b db mb2" ]
|
||||
[ text "Matchers "
|
||||
@ -77,30 +39,65 @@ silenceForm kind silence =
|
||||
, label [ class "f6 dib mb2 mr2 w-40" ] [ text "Name" ]
|
||||
, label [ class "f6 dib mb2 mr2 w-40" ] [ text "Value" ]
|
||||
]
|
||||
, div [] (List.map boundMatcherForm silence.matchers)
|
||||
, iconButtonMsg "blue" "fa-plus" (AddMatcher silence)
|
||||
, formField "Creator" silence.createdBy (UpdateCreatedBy silence)
|
||||
, textField "Comment" silence.comment (UpdateComment silence)
|
||||
, div [] (List.indexedMap matcherForm form.matchers)
|
||||
, iconButtonMsg "blue" "fa-plus" (AddMatcher |> UpdateField)
|
||||
, formField "Creator" form.createdBy (UpdateCreatedBy >> UpdateField)
|
||||
, textField "Comment" form.comment (UpdateComment >> UpdateField)
|
||||
, div [ class "mt3" ]
|
||||
[ a [ class "f6 link br2 ba ph3 pv2 mr2 dib blue", onClick (CreateSilence silence) ] [ text "Create" ]
|
||||
-- Reset isn't working for "New" -- just updates time.
|
||||
, a [ class "f6 link br2 ba ph3 pv2 mr2 dib dark-red", href url ] [ text "Reset" ]
|
||||
[ createSilence silence
|
||||
, a
|
||||
[ class "f6 link br2 ba ph3 pv2 mr2 dib dark-red"
|
||||
, onClick resetClick
|
||||
]
|
||||
[ text "Reset" ]
|
||||
]
|
||||
]
|
||||
|> (Html.map MsgForSilenceForm)
|
||||
, div [ class "mt3" ]
|
||||
[ a [ class "f6 link br2 ba ph3 pv2 mr2 dib dark-green", onClick <| PreviewSilence silence ] [ text "Show Affected Alerts" ]
|
||||
]
|
||||
, Views.Shared.SilencePreview.view silence
|
||||
, preview silence
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
matcherForm : Silence -> Matcher -> Html SilenceFormMsg
|
||||
matcherForm silence matcher =
|
||||
createSilence : Result String Silence -> Html SilenceFormMsg
|
||||
createSilence silenceResult =
|
||||
case silenceResult of
|
||||
Ok silence ->
|
||||
a
|
||||
[ class "f6 link br2 ba ph3 pv2 mr2 dib blue"
|
||||
, onClick (CreateSilence silence)
|
||||
]
|
||||
[ text "Create" ]
|
||||
|
||||
Err msg ->
|
||||
span
|
||||
[ class "f6 link br2 ba ph3 pv2 mr2 dib red" ]
|
||||
[ text "Create" ]
|
||||
|
||||
|
||||
preview : Result String Silence -> Html SilenceFormMsg
|
||||
preview silenceResult =
|
||||
case silenceResult of
|
||||
Ok silence ->
|
||||
div []
|
||||
[ div [ class "mt3" ]
|
||||
[ a
|
||||
[ class "f6 link br2 ba ph3 pv2 mr2 dib dark-green"
|
||||
, onClick (PreviewSilence silence)
|
||||
]
|
||||
[ text "Show Affected Alerts" ]
|
||||
]
|
||||
, Views.Shared.SilencePreview.view silence
|
||||
]
|
||||
|
||||
Err message ->
|
||||
text message
|
||||
|
||||
|
||||
matcherForm : Int -> Matcher -> Html SilenceFormMsg
|
||||
matcherForm index { name, value, isRegex } =
|
||||
div []
|
||||
[ formInput matcher.name (UpdateMatcherName silence matcher)
|
||||
, formInput matcher.value (UpdateMatcherValue silence matcher)
|
||||
, checkbox "Regex" matcher.isRegex (UpdateMatcherRegex silence matcher)
|
||||
, iconButtonMsg "dark-red" "fa-trash-o" (DeleteMatcher silence matcher)
|
||||
[ formInput name (UpdateMatcherName index)
|
||||
, formInput value (UpdateMatcherValue index)
|
||||
, checkbox "Regex" isRegex (UpdateMatcherRegex index)
|
||||
, iconButtonMsg "dark-red" "fa-trash-o" (DeleteMatcher index)
|
||||
]
|
||||
|> Html.map UpdateField
|
||||
|
@ -3,13 +3,12 @@ module Views.SilenceList.Updates exposing (..)
|
||||
import Silences.Api as Api
|
||||
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 Time
|
||||
import Types exposing (Msg(NewUrl, UpdateCurrentTime, PreviewSilence, MsgForSilenceList, Noop), Route(SilenceListRoute))
|
||||
import Utils.Date
|
||||
import Utils.List
|
||||
import Types exposing (Msg(UpdateCurrentTime, MsgForSilenceList), Route(SilenceListRoute))
|
||||
import Utils.Filter exposing (generateQueryString)
|
||||
|
||||
|
||||
@ -29,17 +28,10 @@ update msg silences silence filter =
|
||||
-- TODO: "Deleted id: ID" growl
|
||||
-- TODO: Add DELETE to accepted CORS methods in alertmanager
|
||||
-- TODO: Check why POST isn't there but is accepted
|
||||
( silences, Loading, Task.perform identity (Task.succeed <| NewUrl "/#/silences") )
|
||||
( silences, Loading, Navigation.newUrl "/#/silences" )
|
||||
|
||||
FilterSilences ->
|
||||
let
|
||||
url =
|
||||
"/#/silences" ++ generateQueryString filter
|
||||
|
||||
cmds =
|
||||
Task.perform identity (Task.succeed (NewUrl url))
|
||||
in
|
||||
( silences, silence, Task.perform identity (Task.succeed <| NewUrl url) )
|
||||
( silences, silence, Navigation.newUrl ("/#/silences" ++ generateQueryString filter) )
|
||||
|
||||
|
||||
urlUpdate : Maybe String -> ( SilenceListMsg, Filter )
|
||||
|
@ -7,15 +7,11 @@ import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Views.SilenceList.Types exposing (SilenceListMsg(..))
|
||||
import Views.Shared.SilenceBase
|
||||
import Views.Shared.SilencePreview
|
||||
import Silences.Types exposing (Silence)
|
||||
import Utils.Types exposing (Matcher, ApiResponse(..), Filter, ApiData)
|
||||
import Utils.Views exposing (iconButtonMsg, checkbox, textField, formInput, formField, buttonLink, error, loading)
|
||||
import Utils.Date
|
||||
import Utils.List
|
||||
import Time
|
||||
import Views.AlertList.Views
|
||||
import Types exposing (Msg(UpdateFilter, PreviewSilence, MsgForSilenceList, Noop))
|
||||
import Types exposing (Msg(UpdateFilter, MsgForSilenceList, Noop))
|
||||
|
||||
|
||||
view : ApiData (List Silence) -> ApiData Silence -> Time.Time -> Filter -> Html Msg
|
||||
|
@ -4,7 +4,6 @@ import Html exposing (Html, text, button, div, li, ul, b)
|
||||
import Status.Types exposing (StatusResponse)
|
||||
import Types exposing (Msg(MsgForStatus), Model)
|
||||
import Utils.Types exposing (ApiResponse(Failure, Success, Loading), ApiData)
|
||||
import Utils.Views exposing (loading)
|
||||
|
||||
|
||||
view : Model -> Html Types.Msg
|
||||
|
@ -104,7 +104,7 @@ func uiAppScriptJs() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "ui/app/script.js", size: 398073, mode: os.FileMode(420), modTime: time.Unix(1490373277, 0)}
|
||||
info := bindataFileInfo{name: "ui/app/script.js", size: 398073, mode: os.FileMode(420), modTime: time.Unix(1490373820, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user