From 51ce48997c8d8670089f52240614b47a0599ba35 Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Wed, 8 Jan 2020 01:26:39 +0100 Subject: [PATCH] Start with send-mail widget --- .../src/main/resources/docspell-openapi.yml | 16 +- modules/webapp/src/main/elm/Comp/Dropdown.elm | 4 +- .../src/main/elm/Comp/EmailSettingsForm.elm | 5 +- .../webapp/src/main/elm/Comp/ItemDetail.elm | 66 ++++- modules/webapp/src/main/elm/Comp/ItemMail.elm | 225 ++++++++++++++++++ modules/webapp/src/main/webjar/docspell.css | 6 + 6 files changed, 317 insertions(+), 5 deletions(-) create mode 100644 modules/webapp/src/main/elm/Comp/ItemMail.elm diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index 039cbca7..f78744a9 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -1325,11 +1325,18 @@ components: schemas: SimpleMail: description: | - A simple e-mail. + A simple e-mail related to an item. + + The mail may contain the item attachments as mail attachments. + If all item attachments should be send, set + `addAllAttachments` to `true`. Otherwise set it to `false` and + specify a list of file-ids that you want to include. required: - recipients - subject - body + - addAllAttachments + - attachmentIds properties: recipients: type: array @@ -1339,6 +1346,13 @@ components: type: string body: type: string + addAllAttachments: + type: boolean + attachemntIds: + type: array + items: + type: string + format: ident EmailSettingsList: description: | A list of user email settings. diff --git a/modules/webapp/src/main/elm/Comp/Dropdown.elm b/modules/webapp/src/main/elm/Comp/Dropdown.elm index 99f44933..3ab318e9 100644 --- a/modules/webapp/src/main/elm/Comp/Dropdown.elm +++ b/modules/webapp/src/main/elm/Comp/Dropdown.elm @@ -395,7 +395,9 @@ viewSingle model = ] renderDefault = - [ List.head model.selected |> Maybe.map renderClosed |> Maybe.withDefault (renderPlaceholder model) + [ List.head model.selected + |> Maybe.map renderClosed + |> Maybe.withDefault (renderPlaceholder model) , renderMenu model ] diff --git a/modules/webapp/src/main/elm/Comp/EmailSettingsForm.elm b/modules/webapp/src/main/elm/Comp/EmailSettingsForm.elm index 461be387..fa85576e 100644 --- a/modules/webapp/src/main/elm/Comp/EmailSettingsForm.elm +++ b/modules/webapp/src/main/elm/Comp/EmailSettingsForm.elm @@ -76,7 +76,10 @@ init ems = { makeOption = \s -> { value = Data.SSLType.toString s, text = Data.SSLType.label s } , placeholder = "" , options = Data.SSLType.all - , selected = Data.SSLType.fromString ems.sslType + , selected = + Data.SSLType.fromString ems.sslType + |> Maybe.withDefault Data.SSLType.None + |> Just } , ignoreCertificates = ems.ignoreCertificates } diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail.elm b/modules/webapp/src/main/elm/Comp/ItemDetail.elm index 182ca64e..3773bee3 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail.elm @@ -22,6 +22,7 @@ import Api.Model.TagList exposing (TagList) import Browser.Navigation as Nav import Comp.DatePicker import Comp.Dropdown exposing (isDropdownChangeMsg) +import Comp.ItemMail import Comp.YesNoDimmer import Data.Direction exposing (Direction) import Data.Flags exposing (Flags) @@ -57,6 +58,8 @@ type alias Model = , itemProposals : ItemProposals , dueDate : Maybe Int , dueDatePicker : DatePicker + , itemMail : Comp.ItemMail.Model + , mailOpen : Bool } @@ -116,6 +119,8 @@ emptyModel = , itemProposals = Api.Model.ItemProposals.empty , dueDate = Nothing , dueDatePicker = Comp.DatePicker.emptyModel + , itemMail = Comp.ItemMail.emptyModel + , mailOpen = False } @@ -158,6 +163,8 @@ type Msg | GetProposalResp (Result Http.Error ItemProposals) | RemoveDueDate | RemoveDate + | ItemMailMsg Comp.ItemMail.Msg + | ToggleMail @@ -282,12 +289,16 @@ update key flags next msg model = let ( dp, dpc ) = Comp.DatePicker.init + + ( im, ic ) = + Comp.ItemMail.init flags in - ( { model | itemDatePicker = dp, dueDatePicker = dp } + ( { model | itemDatePicker = dp, dueDatePicker = dp, itemMail = im } , Cmd.batch [ getOptions flags , Cmd.map ItemDatePickerMsg dpc , Cmd.map DueDatePickerMsg dpc + , Cmd.map ItemMailMsg ic ] ) @@ -690,6 +701,29 @@ update key flags next msg model = GetProposalResp (Err _) -> ( model, Cmd.none ) + ItemMailMsg m -> + let + ( im, fa ) = + Comp.ItemMail.update m model.itemMail + in + case fa of + Comp.ItemMail.FormNone -> + ( { model | itemMail = im }, Cmd.none ) + + Comp.ItemMail.FormCancel -> + ( { model + | itemMail = Comp.ItemMail.clear im + , mailOpen = False + } + , Cmd.none + ) + + Comp.ItemMail.FormSend sm -> + Debug.todo "implement send" + + ToggleMail -> + ( { model | mailOpen = not model.mailOpen }, Cmd.none ) + -- view @@ -711,6 +745,7 @@ view inav model = , div [ classList [ ( "ui ablue-comp menu", True ) + , ( "top attached", model.mailOpen ) ] ] [ a [ class "item", Page.href HomePage ] @@ -743,13 +778,25 @@ view inav model = [ ( "toggle item", True ) , ( "active", model.menuOpen ) ] - , title "Expand Menu" + , title "Edit item" , onClick ToggleMenu , href "" ] [ i [ class "edit icon" ] [] ] + , a + [ classList + [ ( "toggle item", True ) + , ( "active", model.mailOpen ) + ] + , title "Send Mail" + , onClick ToggleMail + , href "#" + ] + [ i [ class "mail icon" ] [] + ] ] + , renderMailForm model , div [ class "ui grid" ] [ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm) , div @@ -1197,3 +1244,18 @@ renderDueDateSuggestions model = Util.Time.formatDate (List.take 5 model.itemProposals.dueDate) SetDueDateSuggestion + + +renderMailForm : Model -> Html Msg +renderMailForm model = + div + [ classList + [ ( "ui bottom attached segment", True ) + , ( "invisible hidden", not model.mailOpen ) + ] + ] + [ h4 [ class "ui header" ] + [ text "Send this item via E-Mail" + ] + , Html.map ItemMailMsg (Comp.ItemMail.view model.itemMail) + ] diff --git a/modules/webapp/src/main/elm/Comp/ItemMail.elm b/modules/webapp/src/main/elm/Comp/ItemMail.elm new file mode 100644 index 00000000..99e643ae --- /dev/null +++ b/modules/webapp/src/main/elm/Comp/ItemMail.elm @@ -0,0 +1,225 @@ +module Comp.ItemMail exposing + ( FormAction(..) + , Model + , Msg + , clear + , emptyModel + , init + , update + , view + ) + +import Api +import Api.Model.EmailSettingsList exposing (EmailSettingsList) +import Api.Model.SimpleMail exposing (SimpleMail) +import Comp.Dropdown +import Data.Flags exposing (Flags) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onCheck, onClick, onInput) +import Http +import Util.Http + + +type alias Model = + { connectionModel : Comp.Dropdown.Model String + , subject : String + , receiver : String + , body : String + , attachAll : Bool + , formError : Maybe String + } + + +type Msg + = SetSubject String + | SetReceiver String + | SetBody String + | ConnMsg (Comp.Dropdown.Msg String) + | ConnResp (Result Http.Error EmailSettingsList) + | ToggleAttachAll + | Cancel + | Send + + +type FormAction + = FormSend SimpleMail + | FormCancel + | FormNone + + +emptyModel : Model +emptyModel = + { connectionModel = + Comp.Dropdown.makeSingle + { makeOption = \a -> { value = a, text = a } + , placeholder = "Select connection..." + } + , subject = "" + , receiver = "" + , body = "" + , attachAll = True + , formError = Nothing + } + + +init : Flags -> ( Model, Cmd Msg ) +init flags = + ( emptyModel, Api.getMailSettings flags "" ConnResp ) + + +clear : Model -> Model +clear model = + { model + | subject = "" + , receiver = "" + , body = "" + } + + +update : Msg -> Model -> ( Model, FormAction ) +update msg model = + case msg of + SetSubject str -> + ( { model | subject = str }, FormNone ) + + SetReceiver str -> + ( { model | receiver = str }, FormNone ) + + SetBody str -> + ( { model | body = str }, FormNone ) + + ConnMsg m -> + let + ( cm, _ ) = + --TODO dropdown doesn't use cmd!! + Comp.Dropdown.update m model.connectionModel + in + ( { model | connectionModel = cm }, FormNone ) + + ToggleAttachAll -> + ( { model | attachAll = not model.attachAll }, FormNone ) + + ConnResp (Ok list) -> + let + names = + List.map .name list.items + + cm = + Comp.Dropdown.makeSingleList + { makeOption = \a -> { value = a, text = a } + , placeholder = "Select Connection..." + , options = names + , selected = List.head names + } + in + ( { model + | connectionModel = cm + , formError = + if names == [] then + Just "No E-Mail connections configured. Goto user settings to add one." + + else + Nothing + } + , FormNone + ) + + ConnResp (Err err) -> + ( { model | formError = Just (Util.Http.errorToString err) }, FormNone ) + + Cancel -> + ( model, FormCancel ) + + Send -> + let + rec = + String.split "," model.receiver + + sm = + SimpleMail rec model.subject model.body model.attachAll [] + in + ( model, FormSend sm ) + + +isValid : Model -> Bool +isValid model = + model.receiver + /= "" + && model.subject + /= "" + && model.body + /= "" + && model.formError + == Nothing + + +view : Model -> Html Msg +view model = + div + [ classList + [ ( "ui form", True ) + , ( "error", model.formError /= Nothing ) + ] + ] + [ div [ class "field" ] + [ label [] [ text "Send via" ] + , Html.map ConnMsg (Comp.Dropdown.view model.connectionModel) + ] + , div [ class "ui error message" ] + [ Maybe.withDefault "" model.formError |> text + ] + , div [ class "field" ] + [ label [] + [ text "Receiver(s)" + , span [ class "muted" ] + [ text "Separate multiple recipients by comma" ] + ] + , input + [ type_ "text" + , onInput SetReceiver + , value model.receiver + ] + [] + ] + , div [ class "field" ] + [ label [] [ text "Subject" ] + , input + [ type_ "text" + , onInput SetSubject + , value model.subject + ] + [] + ] + , div [ class "field" ] + [ label [] [ text "Body" ] + , textarea [ onInput SetBody ] + [ text model.body ] + ] + , div [ class "inline field" ] + [ div [ class "ui checkbox" ] + [ input + [ type_ "checkbox" + , checked model.attachAll + , onCheck (\_ -> ToggleAttachAll) + ] + [] + , label [] [ text "Include all item attachments" ] + ] + ] + , button + [ classList + [ ( "ui primary button", True ) + , ( "disabled", not (isValid model) ) + ] + , onClick Send + ] + [ text "Send" + ] + , button + [ class "ui secondary button" + , onClick Cancel + ] + [ text "Cancel" + ] + ] diff --git a/modules/webapp/src/main/webjar/docspell.css b/modules/webapp/src/main/webjar/docspell.css index b96f9d27..e3c47eb9 100644 --- a/modules/webapp/src/main/webjar/docspell.css +++ b/modules/webapp/src/main/webjar/docspell.css @@ -65,6 +65,12 @@ padding-right: 1em; } +label span.muted { + font-size: smaller; + color: rgba(0,0,0,0.6); + margin-left: 0.5em; +} + .ui.search.dropdown.open { z-index: 20; }