mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
ui: Friendly date format for mailbox list, monitor
This commit is contained in:
@@ -29,7 +29,8 @@
|
||||
"elm-lang/svg": "2.0.0 <= v < 3.0.0",
|
||||
"elm-lang/websocket": "1.0.2 <= v < 2.0.0",
|
||||
"evancz/url-parser": "2.0.1 <= v < 3.0.0",
|
||||
"jweir/sparkline": "3.0.0 <= v < 4.0.0"
|
||||
"jweir/sparkline": "3.0.0 <= v < 4.0.0",
|
||||
"ryannhg/elm-date-format": "2.1.2 <= v < 3.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module Data.MessageHeader exposing (..)
|
||||
|
||||
import Date exposing (Date)
|
||||
import Json.Decode as Decode exposing (..)
|
||||
import Json.Decode.Pipeline exposing (..)
|
||||
|
||||
@@ -10,7 +11,7 @@ type alias MessageHeader =
|
||||
, from : String
|
||||
, to : List String
|
||||
, subject : String
|
||||
, date : String
|
||||
, date : Date
|
||||
, size : Int
|
||||
, seen : Bool
|
||||
}
|
||||
@@ -24,6 +25,21 @@ decoder =
|
||||
|> optional "from" string ""
|
||||
|> required "to" (list string)
|
||||
|> optional "subject" string ""
|
||||
|> required "date" string
|
||||
|> required "date" date
|
||||
|> required "size" int
|
||||
|> required "seen" bool
|
||||
|
||||
|
||||
date : Decoder Date
|
||||
date =
|
||||
let
|
||||
convert : String -> Decoder Date
|
||||
convert raw =
|
||||
case Date.fromString raw of
|
||||
Ok date ->
|
||||
succeed date
|
||||
|
||||
Err error ->
|
||||
fail error
|
||||
in
|
||||
string |> andThen convert
|
||||
|
||||
@@ -188,16 +188,24 @@ setRoute route model =
|
||||
)
|
||||
|
||||
Route.Mailbox name ->
|
||||
( { model | page = Mailbox (Mailbox.init name Nothing) }
|
||||
, Cmd.map MailboxMsg (Mailbox.load name)
|
||||
, Session.none
|
||||
)
|
||||
let
|
||||
( subModel, subCmd ) =
|
||||
Mailbox.init name Nothing
|
||||
in
|
||||
( { model | page = Mailbox subModel }
|
||||
, Cmd.map MailboxMsg subCmd
|
||||
, Session.none
|
||||
)
|
||||
|
||||
Route.Message mailbox id ->
|
||||
( { model | page = Mailbox (Mailbox.init mailbox (Just id)) }
|
||||
, Cmd.map MailboxMsg (Mailbox.load mailbox)
|
||||
, Session.none
|
||||
)
|
||||
let
|
||||
( subModel, subCmd ) =
|
||||
Mailbox.init mailbox (Just id)
|
||||
in
|
||||
( { model | page = Mailbox subModel }
|
||||
, Cmd.map MailboxMsg subCmd
|
||||
, Session.none
|
||||
)
|
||||
|
||||
Route.Monitor ->
|
||||
( { model | page = Monitor (Monitor.init model.session.host) }
|
||||
|
||||
@@ -3,6 +3,8 @@ module Page.Mailbox exposing (Model, Msg, init, load, subscriptions, update, vie
|
||||
import Data.Message as Message exposing (Message)
|
||||
import Data.MessageHeader as MessageHeader exposing (MessageHeader)
|
||||
import Data.Session as Session exposing (Session)
|
||||
import Date exposing (Date)
|
||||
import DateFormat.Relative as Relative
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes
|
||||
@@ -70,18 +72,22 @@ type alias Model =
|
||||
, state : State
|
||||
, bodyMode : Body
|
||||
, searchInput : String
|
||||
, now : Date
|
||||
}
|
||||
|
||||
|
||||
init : String -> Maybe MessageID -> Model
|
||||
init : String -> Maybe MessageID -> ( Model, Cmd Msg )
|
||||
init mailboxName selection =
|
||||
Model mailboxName (LoadingList selection) SafeHtmlBody ""
|
||||
( Model mailboxName (LoadingList selection) SafeHtmlBody "" (Date.fromTime 0)
|
||||
, load mailboxName
|
||||
)
|
||||
|
||||
|
||||
load : String -> Cmd Msg
|
||||
load mailboxName =
|
||||
Cmd.batch
|
||||
[ Ports.windowTitle (mailboxName ++ " - Inbucket")
|
||||
, Task.perform Tick Time.now
|
||||
, getList mailboxName
|
||||
]
|
||||
|
||||
@@ -92,15 +98,22 @@ load mailboxName =
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
case model.state of
|
||||
ShowingList _ (ShowingMessage { message }) ->
|
||||
if message.seen then
|
||||
Sub.none
|
||||
else
|
||||
Time.every (250 * Time.millisecond) Tick
|
||||
let
|
||||
subSeen =
|
||||
case model.state of
|
||||
ShowingList _ (ShowingMessage { message }) ->
|
||||
if message.seen then
|
||||
Sub.none
|
||||
else
|
||||
Time.every (250 * Time.millisecond) SeenTick
|
||||
|
||||
_ ->
|
||||
Sub.none
|
||||
_ ->
|
||||
Sub.none
|
||||
in
|
||||
Sub.batch
|
||||
[ Time.every (30 * Time.second) Tick
|
||||
, subSeen
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -119,6 +132,7 @@ type Msg
|
||||
| Purge
|
||||
| PurgeResult (Result Http.Error ())
|
||||
| SearchInput String
|
||||
| SeenTick Time
|
||||
| Tick Time
|
||||
| ViewMessage MessageID
|
||||
|
||||
@@ -224,7 +238,7 @@ update session msg model =
|
||||
PurgeResult (Err err) ->
|
||||
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
||||
|
||||
Tick now ->
|
||||
SeenTick now ->
|
||||
case model.state of
|
||||
ShowingList _ (ShowingMessage { message, markSeenAt }) ->
|
||||
case markSeenAt of
|
||||
@@ -240,6 +254,9 @@ update session msg model =
|
||||
_ ->
|
||||
( model, Cmd.none, Session.none )
|
||||
|
||||
Tick now ->
|
||||
( { model | now = Date.fromTime now }, Cmd.none, Session.none )
|
||||
|
||||
|
||||
{-| Replace the currently displayed message.
|
||||
-}
|
||||
@@ -481,13 +498,13 @@ viewMessageList session model =
|
||||
(list
|
||||
|> filterMessageList
|
||||
|> List.reverse
|
||||
|> List.map (messageChip list.selected)
|
||||
|> List.map (messageChip model list.selected)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
messageChip : Maybe MessageID -> MessageHeader -> Html Msg
|
||||
messageChip selected message =
|
||||
messageChip : Model -> Maybe MessageID -> MessageHeader -> Html Msg
|
||||
messageChip model selected message =
|
||||
div
|
||||
[ classList
|
||||
[ ( "message-list-entry", True )
|
||||
@@ -498,7 +515,7 @@ messageChip selected message =
|
||||
]
|
||||
[ div [ class "subject" ] [ text message.subject ]
|
||||
, div [ class "from" ] [ text message.from ]
|
||||
, div [ class "date" ] [ text message.date ]
|
||||
, div [ class "date" ] [ relativeDate model message.date ]
|
||||
]
|
||||
|
||||
|
||||
@@ -593,6 +610,11 @@ attachmentRow baseUrl attach =
|
||||
]
|
||||
|
||||
|
||||
relativeDate : Model -> Date -> Html Msg
|
||||
relativeDate model date =
|
||||
Relative.relativeTime model.now date |> text
|
||||
|
||||
|
||||
|
||||
-- UTILITY
|
||||
|
||||
|
||||
@@ -2,6 +2,16 @@ module Page.Monitor exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Data.MessageHeader as MessageHeader exposing (MessageHeader)
|
||||
import Data.Session as Session exposing (Session)
|
||||
import Date exposing (Date)
|
||||
import DateFormat
|
||||
exposing
|
||||
( format
|
||||
, monthNameFirstThree
|
||||
, dayOfMonthFixed
|
||||
, hourNumber
|
||||
, minuteFixed
|
||||
, amPmUppercase
|
||||
)
|
||||
import Json.Decode exposing (decodeString)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
@@ -32,8 +42,7 @@ init host =
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
WebSocket.listen model.wsUrl
|
||||
(decodeString MessageHeader.decoder >> NewMessage)
|
||||
WebSocket.listen model.wsUrl (decodeString MessageHeader.decoder >> NewMessage)
|
||||
|
||||
|
||||
|
||||
@@ -85,8 +94,27 @@ view session model =
|
||||
viewMessage : MessageHeader -> Html Msg
|
||||
viewMessage message =
|
||||
tr [ Events.onClick (OpenMessage message) ]
|
||||
[ td [] [ text message.date ]
|
||||
[ td [] [ text (timestamp message.date) ]
|
||||
, td [ class "desktop" ] [ text message.from ]
|
||||
, td [] [ text message.mailbox ]
|
||||
, td [] [ text message.subject ]
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- UTILITY
|
||||
|
||||
|
||||
timestamp : Date -> String
|
||||
timestamp =
|
||||
format
|
||||
[ dayOfMonthFixed
|
||||
, DateFormat.text "-"
|
||||
, monthNameFirstThree
|
||||
, DateFormat.text " "
|
||||
, hourNumber
|
||||
, DateFormat.text ":"
|
||||
, minuteFixed
|
||||
, DateFormat.text " "
|
||||
, amPmUppercase
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user