1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2026-01-10 13:15:56 +00:00

ui: Add an Effect system to handle global state and Elm Cmds (#176)

All pages now leverage Effects for most of their Session and Cmd requests. More work required for routing and other lingering Cmd use.
This commit is contained in:
James Hillyerd
2020-09-12 19:45:14 -07:00
committed by GitHub
parent cf4c5a29bb
commit 2162a4caaa
8 changed files with 460 additions and 167 deletions

View File

@@ -1,12 +1,13 @@
module Page.Mailbox exposing (Model, Msg, init, load, subscriptions, update, view)
module Page.Mailbox exposing (Model, Msg, init, subscriptions, update, view)
import Api
import Browser.Navigation as Nav
import Data.Message as Message exposing (Message)
import Data.MessageHeader exposing (MessageHeader)
import Data.Session as Session exposing (Session)
import Data.Session exposing (Session)
import DateFormat as DF
import DateFormat.Relative as Relative
import Effect exposing (Effect)
import Html
exposing
( Attribute
@@ -54,7 +55,6 @@ import Json.Decode as D
import Json.Encode as E
import Modal
import Route
import Task
import Time exposing (Posix)
import Timer exposing (Timer)
@@ -103,7 +103,7 @@ type alias Model =
}
init : Session -> String -> Maybe MessageID -> ( Model, Cmd Msg )
init : Session -> String -> Maybe MessageID -> ( Model, Effect Msg )
init session mailboxName selection =
( { session = session
, mailboxName = mailboxName
@@ -114,16 +114,11 @@ init session mailboxName selection =
, markSeenTimer = Timer.empty
, now = Time.millisToPosix 0
}
, load session mailboxName
)
load : Session -> String -> Cmd Msg
load session mailboxName =
Cmd.batch
[ Task.perform Tick Time.now
, Api.getHeaderList session ListLoaded mailboxName
, Effect.batch
[ Effect.posixTime Tick
, Effect.getHeaderList ListLoaded mailboxName
]
)
@@ -159,38 +154,38 @@ type Msg
| ModalFocused Modal.Msg
update : Msg -> Model -> ( Model, Cmd Msg )
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
ClickMessage id ->
( updateSelected { model | session = Session.disableRouting model.session } id
, Cmd.batch
( updateSelected model id
, Effect.batch
[ -- Update browser location.
Route.Message model.mailboxName id
Effect.disableRouting
, Route.Message model.mailboxName id
|> model.session.router.toPath
|> Nav.replaceUrl model.session.key
, Api.getMessage model.session MessageLoaded model.mailboxName id
|> Effect.wrap
, Effect.getMessage MessageLoaded model.mailboxName id
]
)
CloseMessage ->
case model.state of
ShowingList list _ ->
( { model | state = ShowingList list NoMessage }, Cmd.none )
( { model | state = ShowingList list NoMessage }, Effect.none )
_ ->
( model, Cmd.none )
( model, Effect.none )
DeleteMessage message ->
updateDeleteMessage model message
DeletedMessage (Ok _) ->
( model, Cmd.none )
( model, Effect.none )
DeletedMessage (Err err) ->
( { model | session = Session.showFlash (HttpUtil.errorFlash err) model.session }
, Cmd.none
)
( model, Effect.showFlash (HttpUtil.errorFlash err) )
ListKeyPress id keyCode ->
case keyCode of
@@ -198,7 +193,7 @@ update msg model =
updateOpenMessage model id
_ ->
( model, Cmd.none )
( model, Effect.none )
ListLoaded (Ok headers) ->
case model.state of
@@ -214,63 +209,51 @@ update msg model =
updateOpenMessage newModel id
Nothing ->
( { newModel
| session = Session.addRecent model.mailboxName model.session
}
, Cmd.none
)
( newModel, Effect.addRecent newModel.mailboxName )
_ ->
( model, Cmd.none )
( model, Effect.none )
ListLoaded (Err err) ->
( { model | session = Session.showFlash (HttpUtil.errorFlash err) model.session }
, Cmd.none
)
( model, Effect.showFlash (HttpUtil.errorFlash err) )
MarkSeenLoaded (Ok _) ->
( model, Cmd.none )
( model, Effect.none )
MarkSeenLoaded (Err err) ->
( { model | session = Session.showFlash (HttpUtil.errorFlash err) model.session }
, Cmd.none
)
( model, Effect.showFlash (HttpUtil.errorFlash err) )
MessageLoaded (Ok message) ->
updateMessageResult model message
MessageLoaded (Err err) ->
( { model | session = Session.showFlash (HttpUtil.errorFlash err) model.session }
, Cmd.none
)
( model, Effect.showFlash (HttpUtil.errorFlash err) )
MessageBody bodyMode ->
( { model | bodyMode = bodyMode }, Cmd.none )
( { model | bodyMode = bodyMode }, Effect.none )
ModalFocused message ->
( { model | session = Modal.updateSession message model.session }
, Cmd.none
, Effect.none
)
OnSearchInput searchInput ->
updateSearchInput model searchInput
PurgeMailboxPrompt ->
( { model | promptPurge = True }, Modal.resetFocusCmd ModalFocused )
( { model | promptPurge = True }, Modal.resetFocusCmd ModalFocused |> Effect.wrap )
PurgeMailboxCanceled ->
( { model | promptPurge = False }, Cmd.none )
( { model | promptPurge = False }, Effect.none )
PurgeMailboxConfirmed ->
updateTriggerPurge model
PurgedMailbox (Ok _) ->
( model, Cmd.none )
( model, Effect.none )
PurgedMailbox (Err err) ->
( { model | session = Session.showFlash (HttpUtil.errorFlash err) model.session }
, Cmd.none
)
( model, Effect.showFlash (HttpUtil.errorFlash err) )
MarkSeenTriggered timer ->
if timer == model.markSeenTimer then
@@ -278,15 +261,15 @@ update msg model =
updateMarkMessageSeen model
else
( model, Cmd.none )
( model, Effect.none )
Tick now ->
( { model | now = now }, Cmd.none )
( { model | now = now }, Effect.none )
{-| Replace the currently displayed message.
-}
updateMessageResult : Model -> Message -> ( Model, Cmd Msg )
updateMessageResult : Model -> Message -> ( Model, Effect Msg )
updateMessageResult model message =
let
bodyMode =
@@ -298,7 +281,7 @@ updateMessageResult model message =
in
case model.state of
LoadingList _ ->
( model, Cmd.none )
( model, Effect.none )
ShowingList list _ ->
let
@@ -314,38 +297,38 @@ updateMessageResult model message =
, markSeenTimer = newTimer
}
-- Set 1500ms delay before reporting message as seen to backend.
, Timer.schedule MarkSeenTriggered newTimer 1500
, Effect.schedule MarkSeenTriggered newTimer 1500
)
{-| Updates model and triggers commands to purge this mailbox.
-}
updateTriggerPurge : Model -> ( Model, Cmd Msg )
updateTriggerPurge : Model -> ( Model, Effect Msg )
updateTriggerPurge model =
let
cmd =
Cmd.batch
effects =
Effect.batch
[ Route.Mailbox model.mailboxName
|> model.session.router.toPath
|> Nav.replaceUrl model.session.key
, Api.purgeMailbox model.session PurgedMailbox model.mailboxName
|> Effect.wrap
, Effect.purgeMailbox PurgedMailbox model.mailboxName
]
in
case model.state of
ShowingList _ _ ->
( { model
| promptPurge = False
, session = Session.disableRouting model.session
, state = ShowingList (MessageList [] Nothing "") NoMessage
}
, cmd
, Effect.batch [ Effect.disableRouting, effects ]
)
_ ->
( model, cmd )
( model, effects )
updateSearchInput : Model -> String -> ( Model, Cmd Msg )
updateSearchInput : Model -> String -> ( Model, Effect Msg )
updateSearchInput model searchInput =
let
searchFilter =
@@ -357,14 +340,14 @@ updateSearchInput model searchInput =
in
case model.state of
LoadingList _ ->
( model, Cmd.none )
( model, Effect.none )
ShowingList list messageState ->
( { model
| searchInput = searchInput
, state = ShowingList { list | searchFilter = searchFilter } messageState
}
, Cmd.none
, Effect.none
)
@@ -396,7 +379,7 @@ updateSelected model id =
{ model | state = ShowingList newList (Transitioning visible) }
updateDeleteMessage : Model -> Message -> ( Model, Cmd Msg )
updateDeleteMessage : Model -> Message -> ( Model, Effect Msg )
updateDeleteMessage model message =
let
filter f messageList =
@@ -404,26 +387,24 @@ updateDeleteMessage model message =
in
case model.state of
ShowingList list _ ->
( { model
| session = Session.disableRouting model.session
, state =
ShowingList (filter (\x -> x.id /= message.id) list) NoMessage
}
, Cmd.batch
[ Api.deleteMessage model.session DeletedMessage message.mailbox message.id
( { model | state = ShowingList (filter (\x -> x.id /= message.id) list) NoMessage }
, Effect.batch
[ Effect.deleteMessage DeletedMessage message.mailbox message.id
, Effect.disableRouting
, Route.Mailbox model.mailboxName
|> model.session.router.toPath
|> Nav.replaceUrl model.session.key
|> Effect.wrap
]
)
_ ->
( model, Cmd.none )
( model, Effect.none )
{-| Updates both the active message, and the message list to mark the currently viewed message as seen.
-}
updateMarkMessageSeen : Model -> ( Model, Cmd Msg )
updateMarkMessageSeen : Model -> ( Model, Effect Msg )
updateMarkMessageSeen model =
case model.state of
ShowingList messages (ShowingMessage visibleMessage) ->
@@ -442,21 +423,20 @@ updateMarkMessageSeen model =
| state =
ShowingList newMessages (ShowingMessage { visibleMessage | seen = True })
}
, Api.markMessageSeen model.session MarkSeenLoaded visibleMessage.mailbox visibleMessage.id
, Effect.markMessageSeen MarkSeenLoaded visibleMessage.mailbox visibleMessage.id
)
_ ->
( model, Cmd.none )
( model, Effect.none )
updateOpenMessage : Model -> String -> ( Model, Cmd Msg )
updateOpenMessage : Model -> String -> ( Model, Effect Msg )
updateOpenMessage model id =
let
newModel =
{ model | session = Session.addRecent model.mailboxName model.session }
in
( updateSelected newModel id
, Api.getMessage model.session MessageLoaded model.mailboxName id
( updateSelected model id
, Effect.batch
[ Effect.addRecent model.mailboxName
, Effect.getMessage MessageLoaded model.mailboxName id
]
)