Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added confirmation dialog when expiring silences #993

Merged
merged 1 commit into from
Sep 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion notify/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,6 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
fmt.Fprintf(wc, "Date: %s\r\n", time.Now().Format(time.RFC1123Z))
fmt.Fprintf(wc, "Content-Type: multipart/alternative; boundary=%s\r\n", multipartWriter.Boundary())


// TODO: Add some useful headers here, such as URL of the alertmanager
// and active/resolved.
fmt.Fprintf(wc, "\r\n")
Expand Down
1 change: 1 addition & 0 deletions ui/app/elm-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"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",
"krisajenkins/elm-dialog": "4.0.3 <= v < 5.0.0",
"rluiten/elm-date-extra": "8.5.0 <= v < 9.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
Expand Down
26 changes: 13 additions & 13 deletions ui/app/src/Updates.elm
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
module Updates exposing (update)

import Navigation
import String exposing (trim)
import Task
import Types
exposing
( Msg(..)
, Model
, Route(NotFoundRoute, SilenceFormEditRoute, SilenceFormNewRoute, SilenceViewRoute, StatusRoute, SilenceListRoute, AlertsRoute)
( Model
, Msg(..)
, Route(AlertsRoute, NotFoundRoute, SilenceFormEditRoute, SilenceFormNewRoute, SilenceListRoute, SilenceViewRoute, StatusRoute)
)
import Utils.Types exposing (ApiData(Loading, Failure, Success), Matcher)
import Views.AlertList.Updates
import Utils.Types exposing (ApiData(Failure, Loading, Success), Matcher)
import Views.AlertList.Types exposing (AlertListMsg(FetchAlerts))
import Views.SilenceView.Types exposing (SilenceViewMsg(SilenceFetched, InitSilenceView))
import Views.SilenceList.Types exposing (SilenceListMsg(FetchSilences))
import Views.SilenceView.Updates
import Views.SilenceForm.Types exposing (SilenceFormMsg(NewSilenceFromMatchers, FetchSilence))
import Views.AlertList.Updates
import Views.SilenceForm.Types exposing (SilenceFormMsg(FetchSilence, NewSilenceFromMatchers))
import Views.SilenceForm.Updates
import Views.SilenceList.Types exposing (SilenceListMsg(FetchSilences))
import Views.SilenceList.Updates
import Views.SilenceView.Types exposing (SilenceViewMsg(InitSilenceView, SilenceFetched))
import Views.SilenceView.Updates
import Views.Status.Types exposing (StatusMsg(InitStatusView))
import Views.Status.Updates
import String exposing (trim)


update : Msg -> Model -> ( Model, Cmd Msg )
Expand Down Expand Up @@ -52,12 +52,12 @@ update msg ({ basePath, apiUrl } as model) =
)

NavigateToStatus ->
( { model | route = StatusRoute }, Task.perform identity (Task.succeed <| (MsgForStatus InitStatusView)) )
( { model | route = StatusRoute }, Task.perform identity (Task.succeed <| MsgForStatus InitStatusView) )

NavigateToSilenceView silenceId ->
let
( silenceView, cmd ) =
Views.SilenceView.Updates.update (InitSilenceView silenceId) model.silenceView apiUrl
Views.SilenceView.Updates.update (InitSilenceView silenceId) model.silenceView apiUrl basePath
in
( { model | route = SilenceViewRoute silenceId, silenceView = silenceView }
, Cmd.map MsgForSilenceView cmd
Expand Down Expand Up @@ -116,7 +116,7 @@ update msg ({ basePath, apiUrl } as model) =
MsgForSilenceView msg ->
let
( silenceView, cmd ) =
Views.SilenceView.Updates.update msg model.silenceView apiUrl
Views.SilenceView.Updates.update msg model.silenceView basePath apiUrl
in
( { model | silenceView = silenceView }, Cmd.map MsgForSilenceView cmd )

Expand Down
53 changes: 38 additions & 15 deletions ui/app/src/Views/SilenceList/SilenceView.elm
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
module Views.SilenceList.SilenceView exposing (view, deleteButton, editButton)
module Views.SilenceList.SilenceView exposing (deleteButton, editButton, view)

import Html exposing (Html, div, a, p, text, b, i, span, small, button, li)
import Dialog
import Html exposing (Html, a, b, button, div, h3, i, li, p, small, span, text)
import Html.Attributes exposing (class, href, style)
import Html.Events exposing (onClick)
import Silences.Types exposing (Silence, State(Expired, Active, Pending))
import Types exposing (Msg(Noop, MsgForSilenceList, MsgForSilenceForm))
import Views.SilenceList.Types exposing (SilenceListMsg(DestroySilence, MsgForFilterBar))
import Silences.Types exposing (Silence, State(Active, Expired, Pending))
import Time exposing (Time)
import Types exposing (Msg(MsgForSilenceForm, MsgForSilenceList, Noop))
import Utils.Date
import Utils.Views exposing (buttonLink)
import Utils.Types exposing (Matcher)
import Utils.Filter
import Utils.List
import Utils.Types exposing (Matcher)
import Utils.Views exposing (buttonLink)
import Views.FilterBar.Types as FilterBarTypes
import Time exposing (Time)
import Views.SilenceForm.Types exposing (SilenceFormMsg(NewSilenceFromMatchers))
import Views.SilenceList.Types exposing (SilenceListMsg(ConfirmDestroySilence, DestroySilence, FetchSilences, MsgForFilterBar))


view : Silence -> Html Msg
view silence =
view : Bool -> Silence -> Html Msg
view showConfirmationDialog silence =
li [ 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" ]
[ case silence.status.state of
Expand All @@ -34,9 +35,32 @@ view silence =
, deleteButton silence False
]
, div [ class "" ] (List.map matcherButton silence.matchers)
, Dialog.view
(if showConfirmationDialog then
Just (confirmSilenceDeleteView silence False)
else
Nothing
)
]


confirmSilenceDeleteView : Silence -> Bool -> Dialog.Config Msg
confirmSilenceDeleteView silence refresh =
{ closeMessage = Just (MsgForSilenceList Views.SilenceList.Types.FetchSilences)
, containerClass = Nothing
, header = Just (h3 [] [ text "Expire Silence" ])
, body = Just (text "Are you sure you want to expire this silence?")
, footer =
Just
(button
[ class "btn btn-success"
, onClick (MsgForSilenceList (Views.SilenceList.Types.DestroySilence silence refresh))
]
[ text "Confirm" ]
)
}


dateView : String -> Time -> Html Msg
dateView string time =
span
Expand All @@ -56,14 +80,13 @@ matcherButton matcher =
Utils.Filter.Eq

msg =
(FilterBarTypes.AddFilterMatcher False
FilterBarTypes.AddFilterMatcher False
{ key = matcher.name
, op = op
, value = matcher.value
}
|> MsgForFilterBar
|> MsgForSilenceList
)
in
Utils.Views.labelButton (Just msg) (Utils.List.mstring matcher)

Expand All @@ -76,7 +99,7 @@ editButton silence =
Expired ->
a
[ class "btn btn-outline-info border-0"
, href ("#/silences/new?keep=1")
, href "#/silences/new?keep=1"
, onClick (NewSilenceFromMatchers silence.matchers |> MsgForSilenceForm)
]
[ text "Recreate"
Expand All @@ -101,15 +124,15 @@ deleteButton silence refresh =
Active ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (DestroySilence silence refresh))
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Expire"
]

Pending ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (DestroySilence silence refresh))
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Delete"
]
Expand Down
10 changes: 6 additions & 4 deletions ui/app/src/Views/SilenceList/Types.elm
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module Views.SilenceList.Types exposing (SilenceListMsg(..), Model, initSilenceList)
module Views.SilenceList.Types exposing (Model, SilenceListMsg(..), initSilenceList)

import Utils.Types exposing (ApiData(Initial))
import Silences.Types exposing (Silence, State(Active))
import Utils.Types exposing (ApiData)
import Utils.Types exposing (ApiData(Initial))
import Views.FilterBar.Types as FilterBar


type SilenceListMsg
= DestroySilence Silence Bool
= ConfirmDestroySilence Silence Bool
| DestroySilence Silence Bool
| SilencesFetch (ApiData (List Silence))
| FetchSilences
| MsgForFilterBar FilterBar.Msg
Expand All @@ -18,6 +18,7 @@ type alias Model =
{ silences : ApiData (List Silence)
, filterBar : FilterBar.Model
, tab : State
, showConfirmationDialog : Bool
}


Expand All @@ -26,4 +27,5 @@ initSilenceList =
{ silences = Initial
, filterBar = FilterBar.initFilterBar
, tab = Active
, showConfirmationDialog = False
}
14 changes: 10 additions & 4 deletions ui/app/src/Views/SilenceList/Updates.elm
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module Views.SilenceList.Updates exposing (update, urlUpdate)

import Navigation
import Silences.Api as Api
import Views.SilenceList.Types exposing (SilenceListMsg(..), Model)
import Utils.Types as Types exposing (ApiData(Failure, Loading, Success), Time, Matchers)
import Utils.Filter exposing (Filter, generateQueryString)
import Utils.Types as Types exposing (ApiData(Failure, Loading, Success), Matchers, Time)
import Views.FilterBar.Updates as FilterBar
import Navigation
import Views.SilenceList.Types exposing (Model, SilenceListMsg(..))


update : SilenceListMsg -> Model -> Filter -> String -> String -> ( Model, Cmd SilenceListMsg )
Expand All @@ -18,14 +18,20 @@ update msg model filter basePath apiUrl =
( { model
| filterBar = FilterBar.setMatchers filter model.filterBar
, silences = Loading
, showConfirmationDialog = False
}
, Api.getSilences apiUrl filter SilencesFetch
)

ConfirmDestroySilence silence refresh ->
( { model | showConfirmationDialog = True }
, Cmd.none
)

DestroySilence silence refresh ->
-- TODO: "Deleted id: ID" growl
-- TODO: Check why POST isn't there but is accepted
{ model | silences = Loading }
{ model | silences = Loading, showConfirmationDialog = False }
! [ Api.destroy apiUrl silence (always FetchSilences)
, if refresh then
Navigation.newUrl (basePath ++ "#/silences")
Expand Down
22 changes: 11 additions & 11 deletions ui/app/src/Views/SilenceList/Views.elm
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ module Views.SilenceList.Views exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Views.SilenceList.Types exposing (SilenceListMsg(..), Model)
import Views.SilenceList.SilenceView
import Silences.Types exposing (Silence, State(..), stateToString)
import Utils.Types exposing (Matcher, ApiData(..))
import Types exposing (Msg(MsgForSilenceList, Noop, UpdateFilter))
import Utils.Api exposing (withDefault)
import Utils.Views exposing (iconButtonMsg, checkbox, textField, formInput, formField, buttonLink, error, loading)
import Types exposing (Msg(UpdateFilter, MsgForSilenceList, Noop))
import Views.FilterBar.Views as FilterBar
import Utils.String as StringUtils
import Utils.Types exposing (ApiData(..), Matcher)
import Utils.Views exposing (buttonLink, checkbox, error, formField, formInput, iconButtonMsg, loading, textField)
import Views.FilterBar.Views as FilterBar
import Views.SilenceList.SilenceView
import Views.SilenceList.Types exposing (Model, SilenceListMsg(..))


view : Model -> Html Msg
view { filterBar, tab, silences } =
view { filterBar, tab, silences, showConfirmationDialog } =
div []
[ div [ class "mb-4" ]
[ label [ class "mb-2", for "filter-bar-matcher" ] [ text "Filter" ]
Expand All @@ -24,7 +24,7 @@ view { filterBar, tab, silences } =
(List.map (tabView tab) (groupSilencesByState (withDefault [] silences)))
, case silences of
Success sils ->
silencesView (filterSilencesByState tab sils)
silencesView showConfirmationDialog (filterSilencesByState tab sils)

Failure msg ->
error msg
Expand All @@ -49,13 +49,13 @@ tabView currentState ( state, silences ) =
]


silencesView : List Silence -> Html Msg
silencesView silences =
silencesView : Bool -> List Silence -> Html Msg
silencesView showConfirmationDialog silences =
if List.isEmpty silences then
div [] [ text "No silences found" ]
else
ul [ class "list-group" ]
(List.map Views.SilenceList.SilenceView.view silences)
(List.map (Views.SilenceList.SilenceView.view showConfirmationDialog) silences)


groupSilencesByState : List Silence -> List ( State, List Silence )
Expand Down
8 changes: 6 additions & 2 deletions ui/app/src/Views/SilenceView/Types.elm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Views.SilenceView.Types exposing (SilenceViewMsg(..), Model, initSilenceView)
module Views.SilenceView.Types exposing (Model, SilenceViewMsg(..), initSilenceView)

import Silences.Types exposing (Silence, SilenceId)
import Alerts.Types exposing (Alert)
import Silences.Types exposing (Silence, SilenceId)
import Utils.Types exposing (ApiData(Initial))


Expand All @@ -10,16 +10,20 @@ type SilenceViewMsg
| SilenceFetched (ApiData Silence)
| AlertGroupsPreview (ApiData (List Alert))
| InitSilenceView SilenceId
| ConfirmDestroySilence Silence Bool
| Reload String


type alias Model =
{ silence : ApiData Silence
, alerts : ApiData (List Alert)
, showConfirmationDialog : Bool
}


initSilenceView : Model
initSilenceView =
{ silence = Initial
, alerts = Initial
, showConfirmationDialog = False
}
23 changes: 16 additions & 7 deletions ui/app/src/Views/SilenceView/Updates.elm
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
module Views.SilenceView.Updates exposing (update)

import Views.SilenceView.Types exposing (Model, SilenceViewMsg(..))
import Silences.Api exposing (getSilence)
import Alerts.Api
import Navigation exposing (newUrl)
import Silences.Api exposing (getSilence)
import Utils.Filter exposing (nullFilter)
import Utils.List
import Utils.Types exposing (ApiData(..))
import Utils.Filter exposing (nullFilter)
import Views.SilenceView.Types exposing (Model, SilenceViewMsg(..))


update : SilenceViewMsg -> Model -> String -> ( Model, Cmd SilenceViewMsg )
update msg model apiUrl =
update : SilenceViewMsg -> Model -> String -> String -> ( Model, Cmd SilenceViewMsg )
update msg model apiUrl basePath =
case msg of
FetchSilence id ->
( model, getSilence apiUrl id SilenceFetched )
Expand All @@ -26,12 +27,20 @@ update msg model apiUrl =
}
, Alerts.Api.fetchAlerts
apiUrl
({ nullFilter | text = Just (Utils.List.mjoin silence.matchers), showSilenced = Just True })
{ nullFilter | text = Just (Utils.List.mjoin silence.matchers), showSilenced = Just True }
|> Cmd.map AlertGroupsPreview
)

ConfirmDestroySilence silence refresh ->
( { model | showConfirmationDialog = True }
, Cmd.none
)

SilenceFetched silence ->
( { model | silence = silence, alerts = Initial }, Cmd.none )

InitSilenceView silenceId ->
( model, getSilence apiUrl silenceId SilenceFetched )
( { model | showConfirmationDialog = False }, getSilence apiUrl silenceId SilenceFetched )

Reload silenceId ->
( { model | showConfirmationDialog = False }, newUrl ("#/silences/" ++ silenceId) )
Loading