docspell/modules/webapp/src/main/elm/Comp/ImapSettingsForm.elm
Eike Kettner dd935454c9 First version of new ui based on tailwind
This drops fomantic-ui as css toolkit and introduces tailwindcss. With
tailwind there are no predefined components, but it's very easy to
create those. So customizing the look&feel is much simpler, most of
the time no additional css is needed.

This requires a complete rewrite of the markup + styles. Luckily all
logic can be kept as is. The now old ui is not removed, it is still
available by using a request header `Docspell-Ui` with a value of `1`
for the old ui and `2` for the new ui.

Another addition is "dev mode", where docspell serves assets with a
no-cache header, to disable browser caching. This makes developing a
lot easier.
2021-02-14 01:46:13 +01:00

374 lines
11 KiB
Elm

module Comp.ImapSettingsForm exposing
( Model
, Msg
, emptyModel
, getSettings
, init
, isValid
, update
, view
, view2
)
import Api.Model.ImapSettings exposing (ImapSettings)
import Comp.Basic as B
import Comp.Dropdown
import Comp.IntField
import Comp.MenuBar as MB
import Comp.PasswordInput
import Data.DropdownStyle as DS
import Data.SSLType exposing (SSLType)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onInput)
import Styles as S
import Util.Maybe
type alias Model =
{ settings : ImapSettings
, name : String
, host : String
, portField : Comp.IntField.Model
, portNum : Maybe Int
, user : Maybe String
, passField : Comp.PasswordInput.Model
, password : Maybe String
, sslType : Comp.Dropdown.Model SSLType
, ignoreCertificates : Bool
, useOAuthToken : Bool
}
emptyModel : Model
emptyModel =
{ settings = Api.Model.ImapSettings.empty
, name = ""
, host = ""
, portField = Comp.IntField.init (Just 0) Nothing True "IMAP Port"
, portNum = Nothing
, user = Nothing
, passField = Comp.PasswordInput.init
, password = Nothing
, sslType =
Comp.Dropdown.makeSingleList
{ makeOption =
\s ->
{ value = Data.SSLType.toString s
, text = Data.SSLType.label s
, additional = ""
}
, placeholder = ""
, options = Data.SSLType.all
, selected = Just Data.SSLType.None
}
, ignoreCertificates = False
, useOAuthToken = False
}
init : ImapSettings -> Model
init ems =
{ settings = ems
, name = ems.name
, host = ems.imapHost
, portField = Comp.IntField.init (Just 0) Nothing True "IMAP Port"
, portNum = ems.imapPort
, user = ems.imapUser
, passField = Comp.PasswordInput.init
, password = ems.imapPassword
, sslType =
Comp.Dropdown.makeSingleList
{ makeOption =
\s ->
{ value = Data.SSLType.toString s
, text = Data.SSLType.label s
, additional = ""
}
, placeholder = ""
, options = Data.SSLType.all
, selected =
Data.SSLType.fromString ems.sslType
|> Maybe.withDefault Data.SSLType.None
|> Just
}
, ignoreCertificates = ems.ignoreCertificates
, useOAuthToken = ems.useOAuth
}
getSettings : Model -> ( Maybe String, ImapSettings )
getSettings model =
( Util.Maybe.fromString model.settings.name
, { name = model.name
, imapHost = model.host
, imapUser = model.user
, imapPort = model.portNum
, imapPassword = model.password
, sslType =
Comp.Dropdown.getSelected model.sslType
|> List.head
|> Maybe.withDefault Data.SSLType.None
|> Data.SSLType.toString
, ignoreCertificates = model.ignoreCertificates
, useOAuth = model.useOAuthToken
}
)
type Msg
= SetName String
| SetHost String
| PortMsg Comp.IntField.Msg
| SetUser String
| PassMsg Comp.PasswordInput.Msg
| SSLTypeMsg (Comp.Dropdown.Msg SSLType)
| ToggleCheckCert
| ToggleUseOAuth
isValid : Model -> Bool
isValid model =
model.host /= "" && model.name /= ""
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
SetName str ->
( { model | name = str }, Cmd.none )
SetHost str ->
( { model | host = str }, Cmd.none )
PortMsg m ->
let
( pm, val ) =
Comp.IntField.update m model.portField
in
( { model | portField = pm, portNum = val }, Cmd.none )
SetUser str ->
( { model | user = Util.Maybe.fromString str }, Cmd.none )
PassMsg m ->
let
( pm, val ) =
Comp.PasswordInput.update m model.passField
in
( { model | passField = pm, password = val }, Cmd.none )
SSLTypeMsg m ->
let
( sm, sc ) =
Comp.Dropdown.update m model.sslType
in
( { model | sslType = sm }, Cmd.map SSLTypeMsg sc )
ToggleCheckCert ->
( { model | ignoreCertificates = not model.ignoreCertificates }, Cmd.none )
ToggleUseOAuth ->
( { model | useOAuthToken = not model.useOAuthToken }, Cmd.none )
--- View
view : UiSettings -> Model -> Html Msg
view settings model =
div
[ classList
[ ( "ui form", True )
, ( "info error", not (isValid model) )
, ( "info success", isValid model )
]
]
[ div [ class "required field" ]
[ label [] [ text "Name" ]
, input
[ type_ "text"
, value model.name
, onInput SetName
, placeholder "Connection name, e.g. 'gmail.com'"
]
[]
, div [ class "ui info message" ]
[ text "The connection name must not contain whitespace or special characters."
]
]
, div [ class "fields" ]
[ div [ class "thirteen wide required field" ]
[ label [] [ text "IMAP Host" ]
, input
[ type_ "text"
, placeholder "IMAP host name, e.g. 'mail.gmail.com'"
, value model.host
, onInput SetHost
]
[]
]
, Html.map PortMsg
(Comp.IntField.view model.portNum
"three wide field"
model.portField
)
]
, div [ class "two fields" ]
[ div [ class "field" ]
[ label [] [ text "IMAP User" ]
, input
[ type_ "text"
, placeholder "IMAP Username, e.g. 'your.name@gmail.com'"
, Maybe.withDefault "" model.user |> value
, onInput SetUser
]
[]
]
, div [ class "field" ]
[ label [] [ text "IMAP Password" ]
, Html.map PassMsg (Comp.PasswordInput.view model.password model.passField)
]
]
, div [ class "two fields" ]
[ div [ class "inline field" ]
[ div [ class "ui checkbox" ]
[ input
[ type_ "checkbox"
, checked model.ignoreCertificates
, onCheck (\_ -> ToggleCheckCert)
]
[]
, label [] [ text "Ignore certificate check" ]
]
]
, div [ class "inline field" ]
[ div [ class "ui checkbox" ]
[ input
[ type_ "checkbox"
, checked model.useOAuthToken
, onCheck (\_ -> ToggleUseOAuth)
]
[]
, label [] [ text "Enable OAuth2 authentication using the password as access token" ]
]
]
]
, div [ class "two fields" ]
[ div [ class "field" ]
[ label [] [ text "SSL" ]
, Html.map SSLTypeMsg (Comp.Dropdown.view settings model.sslType)
]
]
]
--- View2
view2 : UiSettings -> Model -> Html Msg
view2 settings model =
div
[ class "grid grid-cols-4 gap-y-4 gap-x-2" ]
[ div [ class "col-span-4" ]
[ label [ class S.inputLabel ]
[ text "Name"
, B.inputRequired
]
, input
[ type_ "text"
, value model.name
, onInput SetName
, placeholder "Connection name, e.g. 'gmail.com'"
, class S.textInput
, classList [ ( S.inputErrorBorder, model.name == "" ) ]
]
[]
, div
[ class S.message
, class "mt-2"
]
[ text "The connection name must not contain whitespace or special characters."
]
]
, div [ class "col-span-3" ]
[ label [ class S.inputLabel ]
[ text "IMAP Host"
, B.inputRequired
]
, input
[ type_ "text"
, placeholder "IMAP host name, e.g. 'mail.gmail.com'"
, value model.host
, onInput SetHost
, class S.textInput
, classList [ ( S.inputErrorBorder, model.host == "" ) ]
]
[]
]
, Html.map PortMsg
(Comp.IntField.viewWithInfo2 ""
model.portNum
""
model.portField
)
, div [ class "col-span-4 sm:col-span-2" ]
[ label [ class S.inputLabel ]
[ text "IMAP User"
]
, input
[ type_ "text"
, placeholder "IMAP Username, e.g. 'your.name@gmail.com'"
, Maybe.withDefault "" model.user |> value
, onInput SetUser
, class S.textInput
]
[]
]
, div [ class "col-span-4 sm:col-span-2" ]
[ label [ class S.inputLabel ]
[ text "IMAP Password" ]
, Html.map PassMsg
(Comp.PasswordInput.view2
model.password
False
model.passField
)
]
, div [ class "col-span-4 sm:col-span-2" ]
[ label [ class S.inputLabel ]
[ text "SSL"
]
, Html.map SSLTypeMsg
(Comp.Dropdown.view2
DS.mainStyle
settings
model.sslType
)
]
, div [ class "col-span-4 sm:col-span-2 flex items-center" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleCheckCert
, label = "Ignore certificate check"
, value = model.ignoreCertificates
, id = "imap-no-cert-check"
}
]
, div [ class "col-span-4 sm:col-span-2 flex flex-col" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleUseOAuth
, label = "Enable OAuth2 authentication"
, value = model.useOAuthToken
, id = "imap-use-oauth"
}
, div [ class "opacity-50 text-sm" ]
[ text "Enabling this, allows to connect via XOAuth using the password as access token."
]
]
]