mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-11 12:19:33 +00:00
It's more convenient to manage notification channels separately, as it is done with email settings. Notification hook and other forms are adopted to only select channels. Hooks can now use more than one channel.
455 lines
13 KiB
Elm
455 lines
13 KiB
Elm
{-
|
|
Copyright 2020 Eike K. & Contributors
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
-}
|
|
|
|
|
|
module Comp.NotificationChannelManage exposing
|
|
( Model
|
|
, Msg
|
|
, init
|
|
, update
|
|
, view
|
|
)
|
|
|
|
import Api
|
|
import Api.Model.BasicResult exposing (BasicResult)
|
|
import Comp.Basic as B
|
|
import Comp.ChannelForm
|
|
import Comp.ChannelMenu
|
|
import Comp.MenuBar as MB
|
|
import Comp.NotificationChannelTable
|
|
import Data.ChannelType exposing (ChannelType)
|
|
import Data.Flags exposing (Flags)
|
|
import Data.NotificationChannel exposing (NotificationChannel)
|
|
import Data.UiSettings exposing (UiSettings)
|
|
import Html exposing (..)
|
|
import Html.Attributes exposing (..)
|
|
import Html.Events exposing (onClick)
|
|
import Http
|
|
import Messages.Comp.NotificationChannelManage exposing (Texts)
|
|
import Styles as S
|
|
|
|
|
|
type alias Model =
|
|
{ listModel : Comp.NotificationChannelTable.Model
|
|
, detailModel : Maybe Comp.ChannelForm.Model
|
|
, items : List NotificationChannel
|
|
, deleteConfirm : DeleteConfirm
|
|
, loading : Bool
|
|
, formState : FormState
|
|
, newChannelMenuOpen : Bool
|
|
, jsonFilterError : Maybe String
|
|
}
|
|
|
|
|
|
type DeleteConfirm
|
|
= DeleteConfirmOff
|
|
| DeleteConfirmOn
|
|
|
|
|
|
type SubmitType
|
|
= SubmitDelete
|
|
| SubmitUpdate
|
|
| SubmitCreate
|
|
|
|
|
|
type FormState
|
|
= FormStateInitial
|
|
| FormErrorHttp Http.Error
|
|
| FormSubmitSuccessful SubmitType
|
|
| FormErrorSubmit String
|
|
| FormErrorInvalid
|
|
|
|
|
|
type Msg
|
|
= TableMsg Comp.NotificationChannelTable.Msg
|
|
| DetailMsg Comp.ChannelForm.Msg
|
|
| GetDataResp (Result Http.Error (List NotificationChannel))
|
|
| ToggleNewChannelMenu
|
|
| SubmitResp SubmitType (Result Http.Error BasicResult)
|
|
| NewChannelInit ChannelType
|
|
| BackToTable
|
|
| Submit
|
|
| RequestDelete
|
|
| CancelDelete
|
|
| DeleteChannelNow String
|
|
|
|
|
|
initModel : Model
|
|
initModel =
|
|
{ listModel = Comp.NotificationChannelTable.init
|
|
, detailModel = Nothing
|
|
, items = []
|
|
, loading = False
|
|
, formState = FormStateInitial
|
|
, newChannelMenuOpen = False
|
|
, deleteConfirm = DeleteConfirmOff
|
|
, jsonFilterError = Nothing
|
|
}
|
|
|
|
|
|
initCmd : Flags -> Cmd Msg
|
|
initCmd flags =
|
|
Api.getChannels flags GetDataResp
|
|
|
|
|
|
init : Flags -> ( Model, Cmd Msg )
|
|
init flags =
|
|
( initModel, initCmd flags )
|
|
|
|
|
|
|
|
--- Update
|
|
|
|
|
|
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
|
update flags msg model =
|
|
case msg of
|
|
GetDataResp (Ok res) ->
|
|
( { model
|
|
| items = res
|
|
, formState = FormStateInitial
|
|
}
|
|
, Cmd.none
|
|
)
|
|
|
|
GetDataResp (Err err) ->
|
|
( { model | formState = FormErrorHttp err }
|
|
, Cmd.none
|
|
)
|
|
|
|
TableMsg lm ->
|
|
let
|
|
( mm, action ) =
|
|
Comp.NotificationChannelTable.update flags lm model.listModel
|
|
|
|
( detail, cmd ) =
|
|
case action of
|
|
Comp.NotificationChannelTable.NoAction ->
|
|
( Nothing, Cmd.none )
|
|
|
|
Comp.NotificationChannelTable.EditAction channel ->
|
|
let
|
|
( dm, dc ) =
|
|
Comp.ChannelForm.initWith flags channel
|
|
in
|
|
( Just dm, Cmd.map DetailMsg dc )
|
|
in
|
|
( { model
|
|
| listModel = mm
|
|
, detailModel = detail
|
|
}
|
|
, cmd
|
|
)
|
|
|
|
DetailMsg lm ->
|
|
case model.detailModel of
|
|
Just dm ->
|
|
let
|
|
( mm, mc ) =
|
|
Comp.ChannelForm.update flags lm dm
|
|
in
|
|
( { model | detailModel = Just mm }
|
|
, Cmd.map DetailMsg mc
|
|
)
|
|
|
|
Nothing ->
|
|
( model, Cmd.none )
|
|
|
|
ToggleNewChannelMenu ->
|
|
( { model | newChannelMenuOpen = not model.newChannelMenuOpen }, Cmd.none )
|
|
|
|
SubmitResp submitType (Ok res) ->
|
|
( { model
|
|
| formState =
|
|
if res.success then
|
|
FormSubmitSuccessful submitType
|
|
|
|
else
|
|
FormErrorSubmit res.message
|
|
, detailModel =
|
|
if submitType == SubmitDelete then
|
|
Nothing
|
|
|
|
else
|
|
model.detailModel
|
|
, loading = False
|
|
}
|
|
, if submitType == SubmitDelete then
|
|
initCmd flags
|
|
|
|
else
|
|
Cmd.none
|
|
)
|
|
|
|
SubmitResp _ (Err err) ->
|
|
( { model | formState = FormErrorHttp err, loading = False }
|
|
, Cmd.none
|
|
)
|
|
|
|
NewChannelInit ct ->
|
|
let
|
|
( mm, mc ) =
|
|
Comp.ChannelForm.init flags ct
|
|
in
|
|
( { model | detailModel = Just mm, newChannelMenuOpen = False }, Cmd.map DetailMsg mc )
|
|
|
|
BackToTable ->
|
|
( { model | detailModel = Nothing }, initCmd flags )
|
|
|
|
Submit ->
|
|
case model.detailModel of
|
|
Just dm ->
|
|
case Comp.ChannelForm.getChannel dm of
|
|
Just data ->
|
|
postChannel flags data model
|
|
|
|
Nothing ->
|
|
( { model | formState = FormErrorInvalid }, Cmd.none )
|
|
|
|
Nothing ->
|
|
( model, Cmd.none )
|
|
|
|
RequestDelete ->
|
|
( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none )
|
|
|
|
CancelDelete ->
|
|
( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none )
|
|
|
|
DeleteChannelNow id ->
|
|
( { model | deleteConfirm = DeleteConfirmOff, loading = True }
|
|
, Api.deleteChannel flags id (SubmitResp SubmitDelete)
|
|
)
|
|
|
|
|
|
postChannel : Flags -> NotificationChannel -> Model -> ( Model, Cmd Msg )
|
|
postChannel flags channel model =
|
|
if (Data.NotificationChannel.getRef channel |> .id) == "" then
|
|
( { model | loading = True }, Api.createChannel flags channel (SubmitResp SubmitCreate) )
|
|
|
|
else
|
|
( { model | loading = True }, Api.updateChannel flags channel (SubmitResp SubmitUpdate) )
|
|
|
|
|
|
|
|
--- View2
|
|
|
|
|
|
view : Texts -> UiSettings -> Model -> Html Msg
|
|
view texts settings model =
|
|
div [ class "flex flex-col" ]
|
|
(case model.detailModel of
|
|
Just msett ->
|
|
viewForm texts settings model msett
|
|
|
|
Nothing ->
|
|
viewList texts model
|
|
)
|
|
|
|
|
|
viewState : Texts -> Model -> Html Msg
|
|
viewState texts model =
|
|
div
|
|
[ classList
|
|
[ ( S.errorMessage, not (isSuccess model.formState) )
|
|
, ( S.successMessage, isSuccess model.formState )
|
|
, ( "hidden", model.formState == FormStateInitial )
|
|
]
|
|
, class "mb-2"
|
|
]
|
|
[ case model.formState of
|
|
FormStateInitial ->
|
|
text ""
|
|
|
|
FormSubmitSuccessful SubmitCreate ->
|
|
text texts.channelCreated
|
|
|
|
FormSubmitSuccessful SubmitUpdate ->
|
|
text texts.channelUpdated
|
|
|
|
FormSubmitSuccessful SubmitDelete ->
|
|
text texts.channelDeleted
|
|
|
|
FormErrorSubmit m ->
|
|
text m
|
|
|
|
FormErrorHttp err ->
|
|
text (texts.httpError err)
|
|
|
|
FormErrorInvalid ->
|
|
text texts.formInvalid
|
|
]
|
|
|
|
|
|
isSuccess : FormState -> Bool
|
|
isSuccess state =
|
|
case state of
|
|
FormSubmitSuccessful _ ->
|
|
True
|
|
|
|
_ ->
|
|
False
|
|
|
|
|
|
viewForm : Texts -> UiSettings -> Model -> Comp.ChannelForm.Model -> List (Html Msg)
|
|
viewForm texts settings outerModel model =
|
|
let
|
|
channelId =
|
|
Comp.ChannelForm.getChannel model
|
|
|> Maybe.map Data.NotificationChannel.getRef
|
|
|> Maybe.map .id
|
|
|
|
newChannel =
|
|
channelId |> (==) (Just "")
|
|
|
|
headline =
|
|
case Comp.ChannelForm.channelType model of
|
|
Data.ChannelType.Matrix ->
|
|
span []
|
|
[ text texts.integrate
|
|
, a
|
|
[ href "https://matrix.org"
|
|
, target "_blank"
|
|
, class S.link
|
|
, class "mx-3"
|
|
]
|
|
[ i [ class "fa fa-external-link-alt mr-1" ] []
|
|
, text "Matrix"
|
|
]
|
|
, text texts.intoDocspell
|
|
]
|
|
|
|
Data.ChannelType.Mail ->
|
|
span []
|
|
[ text texts.notifyEmailInfo
|
|
]
|
|
|
|
Data.ChannelType.Gotify ->
|
|
span []
|
|
[ text texts.integrate
|
|
, a
|
|
[ href "https://gotify.net"
|
|
, target "_blank"
|
|
, class S.link
|
|
, class "mx-3"
|
|
]
|
|
[ i [ class "fa fa-external-link-alt mr-1" ] []
|
|
, text "Gotify"
|
|
]
|
|
, text texts.intoDocspell
|
|
]
|
|
|
|
Data.ChannelType.Http ->
|
|
span []
|
|
[ text texts.postRequestInfo
|
|
]
|
|
in
|
|
[ h1 [ class S.header2 ]
|
|
[ Data.ChannelType.icon (Comp.ChannelForm.channelType model) "w-8 h-8 inline-block mr-2"
|
|
, if newChannel then
|
|
text texts.addChannel
|
|
|
|
else
|
|
text texts.updateChannel
|
|
, div [ class "text-xs opacity-50 font-mono" ]
|
|
[ Maybe.withDefault "" channelId |> text
|
|
]
|
|
]
|
|
, div [ class "pt-2 pb-4 font-medium" ]
|
|
[ headline
|
|
]
|
|
, MB.view
|
|
{ start =
|
|
[ MB.CustomElement <|
|
|
B.primaryButton
|
|
{ handler = onClick Submit
|
|
, title = texts.basics.submitThisForm
|
|
, icon = "fa fa-save"
|
|
, label = texts.basics.submit
|
|
, disabled = False
|
|
, attrs = [ href "#" ]
|
|
}
|
|
, MB.SecondaryButton
|
|
{ tagger = BackToTable
|
|
, title = texts.basics.backToList
|
|
, icon = Just "fa fa-arrow-left"
|
|
, label = texts.basics.backToList
|
|
}
|
|
]
|
|
, end =
|
|
if not newChannel then
|
|
[ MB.DeleteButton
|
|
{ tagger = RequestDelete
|
|
, title = texts.deleteThisChannel
|
|
, icon = Just "fa fa-trash"
|
|
, label = texts.basics.delete
|
|
}
|
|
]
|
|
|
|
else
|
|
[]
|
|
, rootClasses = "mb-4"
|
|
}
|
|
, div [ class "mt-2" ]
|
|
[ viewState texts outerModel
|
|
]
|
|
, Html.map DetailMsg
|
|
(Comp.ChannelForm.view texts.notificationForm settings model)
|
|
, B.loadingDimmer
|
|
{ active = outerModel.loading
|
|
, label = texts.basics.loading
|
|
}
|
|
, B.contentDimmer
|
|
(outerModel.deleteConfirm == DeleteConfirmOn)
|
|
(div [ class "flex flex-col" ]
|
|
[ div [ class "text-lg" ]
|
|
[ i [ class "fa fa-info-circle mr-2" ] []
|
|
, text texts.reallyDeleteChannel
|
|
]
|
|
, div [ class "mt-4 flex flex-row items-center" ]
|
|
[ B.deleteButton
|
|
{ label = texts.basics.yes
|
|
, icon = "fa fa-check"
|
|
, disabled = False
|
|
, handler = onClick (DeleteChannelNow (Maybe.withDefault "" channelId))
|
|
, attrs = [ href "#" ]
|
|
}
|
|
, B.secondaryButton
|
|
{ label = texts.basics.no
|
|
, icon = "fa fa-times"
|
|
, disabled = False
|
|
, handler = onClick CancelDelete
|
|
, attrs = [ href "#", class "ml-2" ]
|
|
}
|
|
]
|
|
]
|
|
)
|
|
]
|
|
|
|
|
|
viewList : Texts -> Model -> List (Html Msg)
|
|
viewList texts model =
|
|
let
|
|
menuModel =
|
|
{ menuOpen = model.newChannelMenuOpen
|
|
, toggleMenu = ToggleNewChannelMenu
|
|
, menuLabel = texts.newChannel
|
|
, onItem = NewChannelInit
|
|
}
|
|
in
|
|
[ MB.view
|
|
{ start = []
|
|
, end =
|
|
[ Comp.ChannelMenu.channelMenu texts.channelType menuModel
|
|
]
|
|
, rootClasses = "mb-4"
|
|
}
|
|
, Html.map TableMsg
|
|
(Comp.NotificationChannelTable.view texts.notificationTable
|
|
model.listModel
|
|
model.items
|
|
)
|
|
]
|