mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
ui: Reimplement message monitor as web component, closes #128
This commit is contained in:
@@ -111,9 +111,6 @@ pageSubscriptions page =
|
||||
Mailbox subModel ->
|
||||
Sub.map MailboxMsg (Mailbox.subscriptions subModel)
|
||||
|
||||
Monitor subModel ->
|
||||
Sub.map MonitorMsg (Monitor.subscriptions subModel)
|
||||
|
||||
Status subModel ->
|
||||
Sub.map StatusMsg (Status.subscriptions subModel)
|
||||
|
||||
@@ -251,8 +248,7 @@ changeRouteTo route model =
|
||||
let
|
||||
session =
|
||||
getSession model
|
||||
|
||||
( newModel, newCmd ) =
|
||||
in
|
||||
case route of
|
||||
Route.Unknown path ->
|
||||
let
|
||||
@@ -296,14 +292,6 @@ changeRouteTo route model =
|
||||
Route.Status ->
|
||||
Status.init session
|
||||
|> updateWith Status StatusMsg model
|
||||
in
|
||||
case model.page of
|
||||
Monitor _ ->
|
||||
-- Leaving Monitor page, shut down the web socket.
|
||||
( newModel, Cmd.batch [ Ports.monitorCommand False, newCmd ] )
|
||||
|
||||
_ ->
|
||||
( newModel, newCmd )
|
||||
|
||||
|
||||
getSession : Model -> Session
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module Page.Monitor exposing (Model, Msg, init, subscriptions, update, view)
|
||||
module Page.Monitor exposing (Model, Msg, init, update, view)
|
||||
|
||||
import Data.MessageHeader as MessageHeader exposing (MessageHeader)
|
||||
import Data.Session as Session exposing (Session)
|
||||
@@ -7,7 +7,6 @@ import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events as Events
|
||||
import Json.Decode as D
|
||||
import Ports
|
||||
import Route
|
||||
import Time exposing (Posix)
|
||||
|
||||
@@ -23,34 +22,9 @@ type alias Model =
|
||||
}
|
||||
|
||||
|
||||
type MonitorMessage
|
||||
= Connected Bool
|
||||
| Message MessageHeader
|
||||
|
||||
|
||||
init : Session -> ( Model, Cmd Msg )
|
||||
init session =
|
||||
( Model session False []
|
||||
, Ports.monitorCommand True
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
let
|
||||
monitorMessage =
|
||||
D.oneOf
|
||||
[ D.map Message MessageHeader.decoder
|
||||
, D.map Connected D.bool
|
||||
]
|
||||
|> D.decodeValue
|
||||
|> Ports.monitorMessage
|
||||
in
|
||||
Sub.map MessageReceived monitorMessage
|
||||
( Model session False [], Cmd.none )
|
||||
|
||||
|
||||
|
||||
@@ -58,23 +32,31 @@ subscriptions model =
|
||||
|
||||
|
||||
type Msg
|
||||
= MessageReceived (Result D.Error MonitorMessage)
|
||||
= Connected Bool
|
||||
| MessageReceived D.Value
|
||||
| OpenMessage MessageHeader
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
MessageReceived (Ok (Connected status)) ->
|
||||
( { model | connected = status }, Cmd.none )
|
||||
Connected True ->
|
||||
( { model | connected = True, messages = [] }, Cmd.none )
|
||||
|
||||
MessageReceived (Ok (Message header)) ->
|
||||
( { model | messages = header :: model.messages }, Cmd.none )
|
||||
Connected False ->
|
||||
( { model | connected = False }, Cmd.none )
|
||||
|
||||
MessageReceived (Err err) ->
|
||||
MessageReceived value ->
|
||||
case D.decodeValue (MessageHeader.decoder |> D.at [ "detail" ]) value of
|
||||
Ok header ->
|
||||
( { model | messages = header :: model.messages }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Err err ->
|
||||
let
|
||||
flash =
|
||||
{ title = "Decoding failed"
|
||||
{ title = "Message decoding failed"
|
||||
, table = [ ( "Error", D.errorToString err ) ]
|
||||
}
|
||||
in
|
||||
@@ -110,6 +92,11 @@ view model =
|
||||
)
|
||||
]
|
||||
]
|
||||
, node "monitor-messages"
|
||||
[ Events.on "connected" (D.map Connected <| D.at [ "detail" ] <| D.bool)
|
||||
, Events.on "message" (D.map MessageReceived D.value)
|
||||
]
|
||||
[]
|
||||
, table [ class "monitor" ]
|
||||
[ thead []
|
||||
[ th [] [ text "Date" ]
|
||||
@@ -143,6 +130,8 @@ shortDate zone date =
|
||||
, DF.hourNumber
|
||||
, DF.text ":"
|
||||
, DF.minuteFixed
|
||||
, DF.text ":"
|
||||
, DF.secondFixed
|
||||
, DF.text " "
|
||||
, DF.amPmUppercase
|
||||
]
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
port module Ports exposing
|
||||
( monitorCommand
|
||||
, monitorMessage
|
||||
, onSessionChange
|
||||
( onSessionChange
|
||||
, storeSession
|
||||
)
|
||||
|
||||
import Json.Encode exposing (Value)
|
||||
|
||||
|
||||
port monitorCommand : Bool -> Cmd msg
|
||||
|
||||
|
||||
port monitorMessage : (Value -> msg) -> Sub msg
|
||||
|
||||
|
||||
port onSessionChange : (Value -> msg) -> Sub msg
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import './main.css'
|
||||
import '@fortawesome/fontawesome-free/css/all.css'
|
||||
import { Elm } from './Main.elm'
|
||||
import registerMonitorPorts from './registerMonitor'
|
||||
import './monitorMessages'
|
||||
import './renderedHtml'
|
||||
|
||||
// Initial configuration from Inbucket server to Elm App.
|
||||
@@ -16,9 +16,6 @@ var app = Elm.Main.init({
|
||||
flags: flags,
|
||||
})
|
||||
|
||||
// Message monitor.
|
||||
registerMonitorPorts(app)
|
||||
|
||||
// Session storage.
|
||||
app.ports.storeSession.subscribe(function (session) {
|
||||
localStorage.session = JSON.stringify(session)
|
||||
|
||||
38
ui/src/monitorMessages.js
Normal file
38
ui/src/monitorMessages.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// monitor-messages connects to the Inbucket backend via WebSocket to monitor
|
||||
// incoming messages.
|
||||
customElements.define(
|
||||
'monitor-messages',
|
||||
class MonitorMessages extends HTMLElement {
|
||||
constructor() {
|
||||
const self = super()
|
||||
// TODO make URI/URL configurable.
|
||||
var uri = '/api/v1/monitor/messages'
|
||||
self._url = ((window.location.protocol === 'https:') ? 'wss://' : 'ws://') + window.location.host + uri
|
||||
self._socket = null
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const self = this
|
||||
self._socket = new WebSocket(self._url)
|
||||
var ws = self._socket
|
||||
ws.addEventListener('open', function (e) {
|
||||
self.dispatchEvent(new CustomEvent('connected', { detail: true }))
|
||||
})
|
||||
ws.addEventListener('close', function (e) {
|
||||
self.dispatchEvent(new CustomEvent('connected', { detail: false }))
|
||||
})
|
||||
ws.addEventListener('message', function (e) {
|
||||
self.dispatchEvent(new CustomEvent('message', {
|
||||
detail: JSON.parse(e.data),
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
var ws = this._socket
|
||||
if (ws) {
|
||||
ws.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1,46 +0,0 @@
|
||||
// Register the websocket listeners for the monitor API.
|
||||
export default function registerMonitorPorts(app) {
|
||||
var uri = '/api/v1/monitor/messages'
|
||||
var url = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + uri
|
||||
|
||||
// Current handler.
|
||||
var handler = null
|
||||
|
||||
app.ports.monitorCommand.subscribe(function (cmd) {
|
||||
if (handler != null) {
|
||||
handler.down()
|
||||
handler = null
|
||||
}
|
||||
if (cmd) {
|
||||
// Command is up.
|
||||
handler = websocketHandler(url, app.ports.monitorMessage)
|
||||
handler.up()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Creates a handler responsible for connecting, disconnecting from web socket.
|
||||
function websocketHandler(url, port) {
|
||||
var ws = null
|
||||
|
||||
return {
|
||||
up: () => {
|
||||
ws = new WebSocket(url)
|
||||
|
||||
ws.addEventListener('open', function (e) {
|
||||
port.send(true)
|
||||
})
|
||||
ws.addEventListener('close', function (e) {
|
||||
port.send(false)
|
||||
})
|
||||
ws.addEventListener('message', function (e) {
|
||||
var msg = JSON.parse(e.data)
|
||||
port.send(msg)
|
||||
})
|
||||
},
|
||||
|
||||
down: () => {
|
||||
ws.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user