mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-08-05 02:24:52 +00:00
Using elm-format for all files
This commit is contained in:
@ -1,32 +1,36 @@
|
||||
module Comp.AddressForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, getAddress)
|
||||
module Comp.AddressForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getAddress
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Address exposing (Address)
|
||||
import Comp.Dropdown
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Address exposing (Address)
|
||||
import Comp.Dropdown
|
||||
import Util.List
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ address: Address
|
||||
, street: String
|
||||
, zip: String
|
||||
, city: String
|
||||
, country: Comp.Dropdown.Model Country
|
||||
{ address : Address
|
||||
, street : String
|
||||
, zip : String
|
||||
, city : String
|
||||
, country : Comp.Dropdown.Model Country
|
||||
}
|
||||
|
||||
|
||||
type alias Country =
|
||||
{ code: String
|
||||
, label: String
|
||||
{ code : String
|
||||
, label : String
|
||||
}
|
||||
|
||||
countries: List Country
|
||||
|
||||
countries : List Country
|
||||
countries =
|
||||
[ Country "DE" "Germany"
|
||||
, Country "CH" "Switzerland"
|
||||
@ -35,22 +39,24 @@ countries =
|
||||
, Country "AU" "Austria"
|
||||
]
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ address = Api.Model.Address.empty
|
||||
, street = ""
|
||||
, zip = ""
|
||||
, city = ""
|
||||
, country = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \c -> { value = c.code, text = c.label }
|
||||
, placeholder = "Select Country"
|
||||
, options = countries
|
||||
, selected = Nothing
|
||||
}
|
||||
, country =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \c -> { value = c.code, text = c.label }
|
||||
, placeholder = "Select Country"
|
||||
, options = countries
|
||||
, selected = Nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getAddress: Model -> Address
|
||||
getAddress : Model -> Address
|
||||
getAddress model =
|
||||
{ street = model.street
|
||||
, zip = model.zip
|
||||
@ -58,6 +64,7 @@ getAddress model =
|
||||
, country = Comp.Dropdown.getSelected model.country |> List.head |> Maybe.map .code |> Maybe.withDefault ""
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetStreet String
|
||||
| SetCity String
|
||||
@ -65,65 +72,80 @@ type Msg
|
||||
| SetAddress Address
|
||||
| CountryMsg (Comp.Dropdown.Msg Country)
|
||||
|
||||
update: Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
SetAddress a ->
|
||||
let
|
||||
selection = Util.List.find (\c -> c.code == a.country) countries
|
||||
|> Maybe.map List.singleton
|
||||
|> Maybe.withDefault []
|
||||
(m2, c2) = Comp.Dropdown.update (Comp.Dropdown.SetSelection selection) model.country
|
||||
selection =
|
||||
Util.List.find (\c -> c.code == a.country) countries
|
||||
|> Maybe.map List.singleton
|
||||
|> Maybe.withDefault []
|
||||
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update (Comp.Dropdown.SetSelection selection) model.country
|
||||
in
|
||||
({model | address = a, street = a.street, city = a.city, zip = a.zip, country = m2 }, Cmd.map CountryMsg c2)
|
||||
( { model | address = a, street = a.street, city = a.city, zip = a.zip, country = m2 }, Cmd.map CountryMsg c2 )
|
||||
|
||||
SetStreet n ->
|
||||
({model | street = n}, Cmd.none)
|
||||
( { model | street = n }, Cmd.none )
|
||||
|
||||
SetCity c ->
|
||||
({model | city = c }, Cmd.none)
|
||||
( { model | city = c }, Cmd.none )
|
||||
|
||||
SetZip z ->
|
||||
({model | zip = z }, Cmd.none)
|
||||
( { model | zip = z }, Cmd.none )
|
||||
|
||||
CountryMsg m ->
|
||||
let
|
||||
(m1, c1) = Comp.Dropdown.update m model.country
|
||||
( m1, c1 ) =
|
||||
Comp.Dropdown.update m model.country
|
||||
in
|
||||
({model | country = m1}, Cmd.map CountryMsg c1)
|
||||
( { model | country = m1 }, Cmd.map CountryMsg c1 )
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [class "field"
|
||||
]
|
||||
[label [][text "Street"]
|
||||
,input [type_ "text"
|
||||
,onInput SetStreet
|
||||
,placeholder "Street"
|
||||
,value model.street
|
||||
][]
|
||||
]
|
||||
,div [class "field"
|
||||
]
|
||||
[label [][text "Zip Code"]
|
||||
,input [type_ "text"
|
||||
,onInput SetZip
|
||||
,placeholder "Zip"
|
||||
,value model.zip
|
||||
][]
|
||||
]
|
||||
,div [class "field"
|
||||
]
|
||||
[label [][text "City"]
|
||||
,input [type_ "text"
|
||||
,onInput SetCity
|
||||
,placeholder "City"
|
||||
,value model.city
|
||||
][]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Country"]
|
||||
,Html.map CountryMsg (Comp.Dropdown.view model.country)
|
||||
]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ class "field"
|
||||
]
|
||||
[ label [] [ text "Street" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetStreet
|
||||
, placeholder "Street"
|
||||
, value model.street
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div
|
||||
[ class "field"
|
||||
]
|
||||
[ label [] [ text "Zip Code" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetZip
|
||||
, placeholder "Zip"
|
||||
, value model.zip
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div
|
||||
[ class "field"
|
||||
]
|
||||
[ label [] [ text "City" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetCity
|
||||
, placeholder "City"
|
||||
, value model.city
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Country" ]
|
||||
, Html.map CountryMsg (Comp.Dropdown.view model.country)
|
||||
]
|
||||
]
|
||||
|
@ -1,45 +1,49 @@
|
||||
module Comp.ChangePasswordForm exposing (Model
|
||||
,emptyModel
|
||||
,Msg(..)
|
||||
,update
|
||||
,view
|
||||
)
|
||||
import Http
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onClick)
|
||||
module Comp.ChangePasswordForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api
|
||||
import Api.Model.PasswordChange exposing (PasswordChange)
|
||||
import Util.Http
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.PasswordChange exposing (PasswordChange)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Http
|
||||
import Util.Http
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ current: String
|
||||
, newPass1: String
|
||||
, newPass2: String
|
||||
, showCurrent: Bool
|
||||
, showPass1: Bool
|
||||
, showPass2: Bool
|
||||
, errors: List String
|
||||
, loading: Bool
|
||||
, successMsg: String
|
||||
{ current : String
|
||||
, newPass1 : String
|
||||
, newPass2 : String
|
||||
, showCurrent : Bool
|
||||
, showPass1 : Bool
|
||||
, showPass2 : Bool
|
||||
, errors : List String
|
||||
, loading : Bool
|
||||
, successMsg : String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
validateModel
|
||||
{ current = ""
|
||||
, newPass1 = ""
|
||||
, newPass2 = ""
|
||||
, showCurrent = False
|
||||
, showPass1 = False
|
||||
, showPass2 = False
|
||||
, errors = []
|
||||
, loading = False
|
||||
, successMsg = ""
|
||||
}
|
||||
{ current = ""
|
||||
, newPass1 = ""
|
||||
, newPass2 = ""
|
||||
, showCurrent = False
|
||||
, showPass1 = False
|
||||
, showPass2 = False
|
||||
, errors = []
|
||||
, loading = False
|
||||
, successMsg = ""
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetCurrent String
|
||||
@ -52,147 +56,205 @@ type Msg
|
||||
| SubmitResp (Result Http.Error BasicResult)
|
||||
|
||||
|
||||
validate: Model -> List String
|
||||
validate : Model -> List String
|
||||
validate model =
|
||||
List.concat
|
||||
[ if model.newPass1 /= "" && model.newPass2 /= "" && model.newPass1 /= model.newPass2
|
||||
then ["New passwords do not match."]
|
||||
else []
|
||||
, if model.newPass1 == "" || model.newPass2 == "" || model.current == ""
|
||||
then ["Please fill in required fields."]
|
||||
else []
|
||||
[ if model.newPass1 /= "" && model.newPass2 /= "" && model.newPass1 /= model.newPass2 then
|
||||
[ "New passwords do not match." ]
|
||||
|
||||
else
|
||||
[]
|
||||
, if model.newPass1 == "" || model.newPass2 == "" || model.current == "" then
|
||||
[ "Please fill in required fields." ]
|
||||
|
||||
else
|
||||
[]
|
||||
]
|
||||
|
||||
validateModel: Model -> Model
|
||||
|
||||
validateModel : Model -> Model
|
||||
validateModel model =
|
||||
let
|
||||
err = validate model
|
||||
err =
|
||||
validate model
|
||||
in
|
||||
{model | errors = err, successMsg = if err == [] then model.successMsg else "" }
|
||||
{ model
|
||||
| errors = err
|
||||
, successMsg =
|
||||
if err == [] then
|
||||
model.successMsg
|
||||
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- Update
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetCurrent s ->
|
||||
(validateModel {model | current = s}, Cmd.none)
|
||||
( validateModel { model | current = s }, Cmd.none )
|
||||
|
||||
SetNew1 s ->
|
||||
(validateModel {model | newPass1 = s}, Cmd.none)
|
||||
( validateModel { model | newPass1 = s }, Cmd.none )
|
||||
|
||||
SetNew2 s ->
|
||||
(validateModel {model | newPass2 = s}, Cmd.none)
|
||||
( validateModel { model | newPass2 = s }, Cmd.none )
|
||||
|
||||
ToggleShowCurrent ->
|
||||
({model | showCurrent = not model.showCurrent}, Cmd.none)
|
||||
( { model | showCurrent = not model.showCurrent }, Cmd.none )
|
||||
|
||||
ToggleShowPass1 ->
|
||||
({model | showPass1 = not model.showPass1}, Cmd.none)
|
||||
( { model | showPass1 = not model.showPass1 }, Cmd.none )
|
||||
|
||||
ToggleShowPass2 ->
|
||||
({model | showPass2 = not model.showPass2}, Cmd.none)
|
||||
|
||||
( { model | showPass2 = not model.showPass2 }, Cmd.none )
|
||||
|
||||
Submit ->
|
||||
let
|
||||
valid = validate model
|
||||
cp = PasswordChange model.current model.newPass1
|
||||
valid =
|
||||
validate model
|
||||
|
||||
cp =
|
||||
PasswordChange model.current model.newPass1
|
||||
in
|
||||
if List.isEmpty valid then
|
||||
({model | loading = True, errors = [], successMsg = ""}, Api.changePassword flags cp SubmitResp)
|
||||
else
|
||||
(model, Cmd.none)
|
||||
if List.isEmpty valid then
|
||||
( { model | loading = True, errors = [], successMsg = "" }, Api.changePassword flags cp SubmitResp )
|
||||
|
||||
else
|
||||
( model, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
let
|
||||
em = { emptyModel | errors = [], successMsg = "Password has been changed."}
|
||||
em =
|
||||
{ emptyModel | errors = [], successMsg = "Password has been changed." }
|
||||
in
|
||||
if res.success then
|
||||
(em, Cmd.none)
|
||||
else
|
||||
({model | errors = [res.message], loading = False, successMsg = ""}, Cmd.none)
|
||||
if res.success then
|
||||
( em, Cmd.none )
|
||||
|
||||
else
|
||||
( { model | errors = [ res.message ], loading = False, successMsg = "" }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
let
|
||||
str = Util.Http.errorToString err
|
||||
str =
|
||||
Util.Http.errorToString err
|
||||
in
|
||||
({model | errors = [str], loading = False, successMsg = ""}, Cmd.none)
|
||||
( { model | errors = [ str ], loading = False, successMsg = "" }, Cmd.none )
|
||||
|
||||
|
||||
|
||||
-- View
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [classList [("ui form", True)
|
||||
,("error", List.isEmpty model.errors |> not)
|
||||
,("success", model.successMsg /= "")
|
||||
]
|
||||
]
|
||||
[div [classList [("field", True)
|
||||
,("error", model.current == "")
|
||||
]
|
||||
]
|
||||
[label [][text "Current Password*"]
|
||||
,div [class "ui action input"]
|
||||
[input [type_ <| if model.showCurrent then "text" else "password"
|
||||
,onInput SetCurrent
|
||||
,value model.current
|
||||
][]
|
||||
,button [class "ui icon button", onClick ToggleShowCurrent]
|
||||
[i [class "eye icon"][]
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [classList [("field", True)
|
||||
,("error", model.newPass1 == "")
|
||||
]
|
||||
]
|
||||
[label [][text "New Password*"]
|
||||
,div [class "ui action input"]
|
||||
[input [type_ <| if model.showPass1 then "text" else "password"
|
||||
,onInput SetNew1
|
||||
,value model.newPass1
|
||||
][]
|
||||
,button [class "ui icon button", onClick ToggleShowPass1]
|
||||
[i [class "eye icon"][]
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [classList [("field", True)
|
||||
,("error", model.newPass2 == "")
|
||||
]
|
||||
]
|
||||
[label [][text "New Password (repeat)*"]
|
||||
,div [class "ui action input"]
|
||||
[input [type_ <| if model.showPass2 then "text" else "password"
|
||||
,onInput SetNew2
|
||||
,value model.newPass2
|
||||
][]
|
||||
,button [class "ui icon button", onClick ToggleShowPass2]
|
||||
[i [class "eye icon"][]
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,div [class "ui success message"]
|
||||
[text model.successMsg
|
||||
]
|
||||
,div [class "ui error message"]
|
||||
[case model.errors of
|
||||
a :: [] ->
|
||||
text a
|
||||
_ ->
|
||||
ul [class "ui list"]
|
||||
(List.map (\em -> li[][text em]) model.errors)
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", onClick Submit]
|
||||
[text "Submit"
|
||||
]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui form", True )
|
||||
, ( "error", List.isEmpty model.errors |> not )
|
||||
, ( "success", model.successMsg /= "" )
|
||||
]
|
||||
]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", model.current == "" )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "Current Password*" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ input
|
||||
[ type_ <|
|
||||
if model.showCurrent then
|
||||
"text"
|
||||
|
||||
else
|
||||
"password"
|
||||
, onInput SetCurrent
|
||||
, value model.current
|
||||
]
|
||||
[]
|
||||
, button [ class "ui icon button", onClick ToggleShowCurrent ]
|
||||
[ i [ class "eye icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", model.newPass1 == "" )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "New Password*" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ input
|
||||
[ type_ <|
|
||||
if model.showPass1 then
|
||||
"text"
|
||||
|
||||
else
|
||||
"password"
|
||||
, onInput SetNew1
|
||||
, value model.newPass1
|
||||
]
|
||||
[]
|
||||
, button [ class "ui icon button", onClick ToggleShowPass1 ]
|
||||
[ i [ class "eye icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", model.newPass2 == "" )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "New Password (repeat)*" ]
|
||||
, div [ class "ui action input" ]
|
||||
[ input
|
||||
[ type_ <|
|
||||
if model.showPass2 then
|
||||
"text"
|
||||
|
||||
else
|
||||
"password"
|
||||
, onInput SetNew2
|
||||
, value model.newPass2
|
||||
]
|
||||
[]
|
||||
, button [ class "ui icon button", onClick ToggleShowPass2 ]
|
||||
[ i [ class "eye icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, div [ class "ui success message" ]
|
||||
[ text model.successMsg
|
||||
]
|
||||
, div [ class "ui error message" ]
|
||||
[ case model.errors of
|
||||
a :: [] ->
|
||||
text a
|
||||
|
||||
_ ->
|
||||
ul [ class "ui list" ]
|
||||
(List.map (\em -> li [] [ text em ]) model.errors)
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", onClick Submit ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,40 +1,50 @@
|
||||
module Comp.ContactField exposing (Model
|
||||
,emptyModel
|
||||
,getContacts
|
||||
,Msg(..)
|
||||
,update
|
||||
,view
|
||||
)
|
||||
module Comp.ContactField exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getContacts
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Contact exposing (Contact)
|
||||
import Comp.Dropdown
|
||||
import Data.ContactType exposing (ContactType)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onClick)
|
||||
import Api.Model.Contact exposing (Contact)
|
||||
import Data.ContactType exposing (ContactType)
|
||||
import Comp.Dropdown
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ items: List Contact
|
||||
, kind: Comp.Dropdown.Model ContactType
|
||||
, value: String
|
||||
{ items : List Contact
|
||||
, kind : Comp.Dropdown.Model ContactType
|
||||
, value : String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ items = []
|
||||
, kind = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \ct -> { value = Data.ContactType.toString ct, text = Data.ContactType.toString ct }
|
||||
, placeholder = ""
|
||||
, options = Data.ContactType.all
|
||||
, selected = List.head Data.ContactType.all
|
||||
}
|
||||
, kind =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption =
|
||||
\ct ->
|
||||
{ value = Data.ContactType.toString ct
|
||||
, text = Data.ContactType.toString ct
|
||||
}
|
||||
, placeholder = ""
|
||||
, options = Data.ContactType.all
|
||||
, selected = List.head Data.ContactType.all
|
||||
}
|
||||
, value = ""
|
||||
}
|
||||
|
||||
getContacts: Model -> List Contact
|
||||
|
||||
getContacts : Model -> List Contact
|
||||
getContacts model =
|
||||
List.filter (\c -> c.value /= "") model.items
|
||||
|
||||
|
||||
type Msg
|
||||
= SetValue String
|
||||
| TypeMsg (Comp.Dropdown.Msg ContactType)
|
||||
@ -42,76 +52,89 @@ type Msg
|
||||
| Select Contact
|
||||
| SetItems (List Contact)
|
||||
|
||||
update: Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
SetItems contacts ->
|
||||
({model | items = contacts, value = "" }, Cmd.none)
|
||||
( { model | items = contacts, value = "" }, Cmd.none )
|
||||
|
||||
SetValue v ->
|
||||
({model | value = v}, Cmd.none)
|
||||
( { model | value = v }, Cmd.none )
|
||||
|
||||
TypeMsg m ->
|
||||
let
|
||||
(m1, c1) = Comp.Dropdown.update m model.kind
|
||||
( m1, c1 ) =
|
||||
Comp.Dropdown.update m model.kind
|
||||
in
|
||||
({model|kind = m1}, Cmd.map TypeMsg c1)
|
||||
( { model | kind = m1 }, Cmd.map TypeMsg c1 )
|
||||
|
||||
AddContact ->
|
||||
if model.value == "" then (model, Cmd.none)
|
||||
if model.value == "" then
|
||||
( model, Cmd.none )
|
||||
|
||||
else
|
||||
let
|
||||
kind = Comp.Dropdown.getSelected model.kind
|
||||
|> List.head
|
||||
|> Maybe.map Data.ContactType.toString
|
||||
|> Maybe.withDefault ""
|
||||
kind =
|
||||
Comp.Dropdown.getSelected model.kind
|
||||
|> List.head
|
||||
|> Maybe.map Data.ContactType.toString
|
||||
|> Maybe.withDefault ""
|
||||
in
|
||||
({model| items = (Contact "" model.value kind) :: model.items, value = ""}, Cmd.none)
|
||||
( { model | items = Contact "" model.value kind :: model.items, value = "" }, Cmd.none )
|
||||
|
||||
Select contact ->
|
||||
let
|
||||
newItems = List.filter (\c -> c /= contact) model.items
|
||||
(m1, c1) = Data.ContactType.fromString contact.kind
|
||||
|> Maybe.map (\ct -> update (TypeMsg (Comp.Dropdown.SetSelection [ct])) model)
|
||||
|> Maybe.withDefault (model, Cmd.none)
|
||||
in
|
||||
({m1 | value = contact.value, items = newItems}, c1)
|
||||
newItems =
|
||||
List.filter (\c -> c /= contact) model.items
|
||||
|
||||
view: Model -> Html Msg
|
||||
( m1, c1 ) =
|
||||
Data.ContactType.fromString contact.kind
|
||||
|> Maybe.map (\ct -> update (TypeMsg (Comp.Dropdown.SetSelection [ ct ])) model)
|
||||
|> Maybe.withDefault ( model, Cmd.none )
|
||||
in
|
||||
( { m1 | value = contact.value, items = newItems }, c1 )
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[div [class "fields"]
|
||||
[div [class "four wide field"]
|
||||
[Html.map TypeMsg (Comp.Dropdown.view model.kind)
|
||||
]
|
||||
,div [class "twelve wide field"]
|
||||
[div [class "ui action input"]
|
||||
[input [type_ "text"
|
||||
,onInput SetValue
|
||||
,value model.value
|
||||
][]
|
||||
,a [class "ui button", onClick AddContact, href ""]
|
||||
[text "Add"
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [classList [("field", True)
|
||||
,("invisible", List.isEmpty model.items)
|
||||
[ div [ class "fields" ]
|
||||
[ div [ class "four wide field" ]
|
||||
[ Html.map TypeMsg (Comp.Dropdown.view model.kind)
|
||||
]
|
||||
, div [ class "twelve wide field" ]
|
||||
[ div [ class "ui action input" ]
|
||||
[ input
|
||||
[ type_ "text"
|
||||
, onInput SetValue
|
||||
, value model.value
|
||||
]
|
||||
]
|
||||
[div [class "ui vertical secondary fluid menu"]
|
||||
(List.map renderItem model.items)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
renderItem: Contact -> Html Msg
|
||||
renderItem contact =
|
||||
div [class "link item", onClick (Select contact) ]
|
||||
[i [class "delete icon"][]
|
||||
,div [class "ui blue label"]
|
||||
[text contact.kind
|
||||
[]
|
||||
, a [ class "ui button", onClick AddContact, href "" ]
|
||||
[ text "Add"
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "invisible", List.isEmpty model.items )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui vertical secondary fluid menu" ]
|
||||
(List.map renderItem model.items)
|
||||
]
|
||||
,text contact.value
|
||||
]
|
||||
|
||||
|
||||
renderItem : Contact -> Html Msg
|
||||
renderItem contact =
|
||||
div [ class "link item", onClick (Select contact) ]
|
||||
[ i [ class "delete icon" ] []
|
||||
, div [ class "ui blue label" ]
|
||||
[ text contact.kind
|
||||
]
|
||||
, text contact.value
|
||||
]
|
||||
|
@ -1,65 +1,94 @@
|
||||
module Comp.DatePicker exposing (..)
|
||||
module Comp.DatePicker exposing
|
||||
( Msg
|
||||
, defaultSettings
|
||||
, emptyModel
|
||||
, endOfDay
|
||||
, init
|
||||
, midOfDay
|
||||
, startOfDay
|
||||
, update
|
||||
, updateDefault
|
||||
, view
|
||||
, viewTime
|
||||
, viewTimeDefault
|
||||
)
|
||||
|
||||
import Html exposing (Html)
|
||||
import DatePicker exposing (DatePicker, DateEvent, Settings)
|
||||
import Date exposing (Date)
|
||||
import Time exposing (Posix, Zone, utc, Month(..))
|
||||
import DatePicker exposing (DateEvent, DatePicker, Settings)
|
||||
import Html exposing (Html)
|
||||
import Time exposing (Month(..), Posix, Zone, utc)
|
||||
|
||||
type alias Msg = DatePicker.Msg
|
||||
|
||||
init: (DatePicker, Cmd Msg)
|
||||
type alias Msg =
|
||||
DatePicker.Msg
|
||||
|
||||
|
||||
init : ( DatePicker, Cmd Msg )
|
||||
init =
|
||||
DatePicker.init
|
||||
|
||||
emptyModel: DatePicker
|
||||
|
||||
emptyModel : DatePicker
|
||||
emptyModel =
|
||||
DatePicker.initFromDate (Date.fromCalendarDate 2019 Aug 21)
|
||||
|
||||
defaultSettings: Settings
|
||||
|
||||
defaultSettings : Settings
|
||||
defaultSettings =
|
||||
let
|
||||
ds = DatePicker.defaultSettings
|
||||
ds =
|
||||
DatePicker.defaultSettings
|
||||
in
|
||||
{ds | changeYear = DatePicker.from 2010}
|
||||
{ ds | changeYear = DatePicker.from 2010 }
|
||||
|
||||
update: Settings -> Msg -> DatePicker -> (DatePicker, DateEvent)
|
||||
|
||||
update : Settings -> Msg -> DatePicker -> ( DatePicker, DateEvent )
|
||||
update settings msg model =
|
||||
DatePicker.update settings msg model
|
||||
|
||||
updateDefault: Msg -> DatePicker -> (DatePicker, DateEvent)
|
||||
|
||||
updateDefault : Msg -> DatePicker -> ( DatePicker, DateEvent )
|
||||
updateDefault msg model =
|
||||
DatePicker.update defaultSettings msg model
|
||||
|
||||
|
||||
view : Maybe Date -> Settings -> DatePicker -> Html Msg
|
||||
view md settings model =
|
||||
view md settings model =
|
||||
DatePicker.view md settings model
|
||||
|
||||
|
||||
viewTime : Maybe Int -> Settings -> DatePicker -> Html Msg
|
||||
viewTime md settings model =
|
||||
viewTime md settings model =
|
||||
let
|
||||
date = Maybe.map Time.millisToPosix md
|
||||
date =
|
||||
Maybe.map Time.millisToPosix md
|
||||
|> Maybe.map (Date.fromPosix Time.utc)
|
||||
in
|
||||
view date settings model
|
||||
view date settings model
|
||||
|
||||
viewTimeDefault: Maybe Int -> DatePicker -> Html Msg
|
||||
|
||||
viewTimeDefault : Maybe Int -> DatePicker -> Html Msg
|
||||
viewTimeDefault md model =
|
||||
viewTime md defaultSettings model
|
||||
|
||||
|
||||
startOfDay: Date -> Int
|
||||
startOfDay : Date -> Int
|
||||
startOfDay date =
|
||||
let
|
||||
unix0 = Date.fromPosix Time.utc (Time.millisToPosix 0)
|
||||
days = Date.diff Date.Days unix0 date
|
||||
unix0 =
|
||||
Date.fromPosix Time.utc (Time.millisToPosix 0)
|
||||
|
||||
days =
|
||||
Date.diff Date.Days unix0 date
|
||||
in
|
||||
days * 24 * 60 * 60 * 1000
|
||||
days * 24 * 60 * 60 * 1000
|
||||
|
||||
endOfDay: Date -> Int
|
||||
|
||||
endOfDay : Date -> Int
|
||||
endOfDay date =
|
||||
(startOfDay date) + ((24 * 60) - 1) * 60 * 1000
|
||||
startOfDay date + ((24 * 60) - 1) * 60 * 1000
|
||||
|
||||
midOfDay: Date -> Int
|
||||
|
||||
midOfDay : Date -> Int
|
||||
midOfDay date =
|
||||
(startOfDay date) + (12 * 60 * 60 * 1000)
|
||||
startOfDay date + (12 * 60 * 60 * 1000)
|
||||
|
@ -1,39 +1,41 @@
|
||||
module Comp.Dropdown exposing ( Model
|
||||
, Option
|
||||
, makeModel
|
||||
, makeSingle
|
||||
, makeSingleList
|
||||
, makeMultiple
|
||||
, update
|
||||
, isDropdownChangeMsg
|
||||
, view
|
||||
, getSelected
|
||||
, Msg(..))
|
||||
module Comp.Dropdown exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, Option
|
||||
, getSelected
|
||||
, isDropdownChangeMsg
|
||||
, makeModel
|
||||
, makeMultiple
|
||||
, makeSingle
|
||||
, makeSingleList
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Task
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onClick, onFocus, onBlur)
|
||||
import Json.Decode as Decode
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Simple.Fuzzy
|
||||
import Util.Html exposing (onKeyUp)
|
||||
import Util.List
|
||||
|
||||
|
||||
type alias Option =
|
||||
{ value: String
|
||||
, text: String
|
||||
{ value : String
|
||||
, text : String
|
||||
}
|
||||
|
||||
|
||||
type alias Item a =
|
||||
{ value: a
|
||||
, option: Option
|
||||
, visible: Bool
|
||||
, selected: Bool
|
||||
, active: Bool
|
||||
{ value : a
|
||||
, option : Option
|
||||
, visible : Bool
|
||||
, selected : Bool
|
||||
, active : Bool
|
||||
}
|
||||
|
||||
makeItem: Model a -> a -> Item a
|
||||
|
||||
makeItem : Model a -> a -> Item a
|
||||
makeItem model val =
|
||||
{ value = val
|
||||
, option = model.makeOption val
|
||||
@ -42,25 +44,28 @@ makeItem model val =
|
||||
, active = False
|
||||
}
|
||||
|
||||
|
||||
type alias Model a =
|
||||
{ multiple: Bool
|
||||
, selected: List (Item a)
|
||||
, available: List (Item a)
|
||||
, makeOption: a -> Option
|
||||
, menuOpen: Bool
|
||||
, filterString: String
|
||||
, labelColor: a -> String
|
||||
, searchable: Int -> Bool
|
||||
, placeholder: String
|
||||
{ multiple : Bool
|
||||
, selected : List (Item a)
|
||||
, available : List (Item a)
|
||||
, makeOption : a -> Option
|
||||
, menuOpen : Bool
|
||||
, filterString : String
|
||||
, labelColor : a -> String
|
||||
, searchable : Int -> Bool
|
||||
, placeholder : String
|
||||
}
|
||||
|
||||
makeModel:
|
||||
{ multiple: Bool
|
||||
, searchable: Int -> Bool
|
||||
, makeOption: a -> Option
|
||||
, labelColor: a -> String
|
||||
, placeholder: String
|
||||
} -> Model a
|
||||
|
||||
makeModel :
|
||||
{ multiple : Bool
|
||||
, searchable : Int -> Bool
|
||||
, makeOption : a -> Option
|
||||
, labelColor : a -> String
|
||||
, placeholder : String
|
||||
}
|
||||
-> Model a
|
||||
makeModel input =
|
||||
{ multiple = input.multiple
|
||||
, searchable = input.searchable
|
||||
@ -73,10 +78,12 @@ makeModel input =
|
||||
, placeholder = input.placeholder
|
||||
}
|
||||
|
||||
makeSingle:
|
||||
{ makeOption: a -> Option
|
||||
, placeholder: String
|
||||
} -> Model a
|
||||
|
||||
makeSingle :
|
||||
{ makeOption : a -> Option
|
||||
, placeholder : String
|
||||
}
|
||||
-> Model a
|
||||
makeSingle opts =
|
||||
makeModel
|
||||
{ multiple = False
|
||||
@ -86,26 +93,35 @@ makeSingle opts =
|
||||
, placeholder = opts.placeholder
|
||||
}
|
||||
|
||||
makeSingleList:
|
||||
{ makeOption: a -> Option
|
||||
, placeholder: String
|
||||
, options: List a
|
||||
, selected: Maybe a
|
||||
} -> Model a
|
||||
|
||||
makeSingleList :
|
||||
{ makeOption : a -> Option
|
||||
, placeholder : String
|
||||
, options : List a
|
||||
, selected : Maybe a
|
||||
}
|
||||
-> Model a
|
||||
makeSingleList opts =
|
||||
let
|
||||
m = makeSingle {makeOption = opts.makeOption, placeholder = opts.placeholder}
|
||||
m2 = {m | available = List.map (makeItem m) opts.options}
|
||||
m3 = Maybe.map (makeItem m2) opts.selected
|
||||
|> Maybe.map (selectItem m2)
|
||||
|> Maybe.withDefault m2
|
||||
in
|
||||
m3
|
||||
m =
|
||||
makeSingle { makeOption = opts.makeOption, placeholder = opts.placeholder }
|
||||
|
||||
makeMultiple:
|
||||
{ makeOption: a -> Option
|
||||
, labelColor: a -> String
|
||||
} -> Model a
|
||||
m2 =
|
||||
{ m | available = List.map (makeItem m) opts.options }
|
||||
|
||||
m3 =
|
||||
Maybe.map (makeItem m2) opts.selected
|
||||
|> Maybe.map (selectItem m2)
|
||||
|> Maybe.withDefault m2
|
||||
in
|
||||
m3
|
||||
|
||||
|
||||
makeMultiple :
|
||||
{ makeOption : a -> Option
|
||||
, labelColor : a -> String
|
||||
}
|
||||
-> Model a
|
||||
makeMultiple opts =
|
||||
makeModel
|
||||
{ multiple = True
|
||||
@ -115,10 +131,12 @@ makeMultiple opts =
|
||||
, placeholder = ""
|
||||
}
|
||||
|
||||
getSelected: Model a -> List a
|
||||
|
||||
getSelected : Model a -> List a
|
||||
getSelected model =
|
||||
List.map .value model.selected
|
||||
|
||||
|
||||
type Msg a
|
||||
= SetOptions (List a)
|
||||
| SetSelection (List a)
|
||||
@ -129,265 +147,367 @@ type Msg a
|
||||
| ShowMenu Bool
|
||||
| KeyPress Int
|
||||
|
||||
getOptions: Model a -> List (Item a)
|
||||
getOptions model =
|
||||
if not model.multiple && isSearchable model && model.menuOpen
|
||||
then List.filter .visible model.available
|
||||
else List.filter (\e -> e.visible && (not e.selected)) model.available
|
||||
|
||||
isSearchable: Model a -> Bool
|
||||
getOptions : Model a -> List (Item a)
|
||||
getOptions model =
|
||||
if not model.multiple && isSearchable model && model.menuOpen then
|
||||
List.filter .visible model.available
|
||||
|
||||
else
|
||||
List.filter (\e -> e.visible && not e.selected) model.available
|
||||
|
||||
|
||||
isSearchable : Model a -> Bool
|
||||
isSearchable model =
|
||||
List.length model.available |> model.searchable
|
||||
|
||||
|
||||
|
||||
-- Update
|
||||
|
||||
deselectItem: Model a -> Item a -> Model a
|
||||
|
||||
deselectItem : Model a -> Item a -> Model a
|
||||
deselectItem model item =
|
||||
let
|
||||
value = item.option.value
|
||||
sel = if model.multiple then List.filter (\e -> e.option.value /= value) model.selected
|
||||
else []
|
||||
value =
|
||||
item.option.value
|
||||
|
||||
show e = if e.option.value == value then {e | selected = False } else e
|
||||
avail = List.map show model.available
|
||||
sel =
|
||||
if model.multiple then
|
||||
List.filter (\e -> e.option.value /= value) model.selected
|
||||
|
||||
else
|
||||
[]
|
||||
|
||||
show e =
|
||||
if e.option.value == value then
|
||||
{ e | selected = False }
|
||||
|
||||
else
|
||||
e
|
||||
|
||||
avail =
|
||||
List.map show model.available
|
||||
in
|
||||
{ model | selected = sel, available = avail }
|
||||
{ model | selected = sel, available = avail }
|
||||
|
||||
selectItem: Model a -> Item a -> Model a
|
||||
|
||||
selectItem : Model a -> Item a -> Model a
|
||||
selectItem model item =
|
||||
let
|
||||
value = item.option.value
|
||||
sel = if model.multiple
|
||||
then List.concat [ model.selected, [ item ] ]
|
||||
else [ item ]
|
||||
value =
|
||||
item.option.value
|
||||
|
||||
hide e = if e.option.value == value
|
||||
then {e | selected = True }
|
||||
else if model.multiple then e else {e | selected = False}
|
||||
avail = List.map hide model.available
|
||||
sel =
|
||||
if model.multiple then
|
||||
List.concat [ model.selected, [ item ] ]
|
||||
|
||||
else
|
||||
[ item ]
|
||||
|
||||
hide e =
|
||||
if e.option.value == value then
|
||||
{ e | selected = True }
|
||||
|
||||
else if model.multiple then
|
||||
e
|
||||
|
||||
else
|
||||
{ e | selected = False }
|
||||
|
||||
avail =
|
||||
List.map hide model.available
|
||||
in
|
||||
{ model | selected = sel, available = avail }
|
||||
{ model | selected = sel, available = avail }
|
||||
|
||||
|
||||
filterOptions: String -> List (Item a) -> List (Item a)
|
||||
filterOptions : String -> List (Item a) -> List (Item a)
|
||||
filterOptions str list =
|
||||
List.map (\e -> {e | visible = Simple.Fuzzy.match str e.option.text, active = False}) list
|
||||
List.map (\e -> { e | visible = Simple.Fuzzy.match str e.option.text, active = False }) list
|
||||
|
||||
applyFilter: String -> Model a -> Model a
|
||||
|
||||
applyFilter : String -> Model a -> Model a
|
||||
applyFilter str model =
|
||||
{ model | filterString = str, available = filterOptions str model.available }
|
||||
|
||||
|
||||
makeNextActive: (Int -> Int) -> Model a -> Model a
|
||||
makeNextActive : (Int -> Int) -> Model a -> Model a
|
||||
makeNextActive nextEl model =
|
||||
let
|
||||
opts = getOptions model
|
||||
current = Util.List.findIndexed .active opts
|
||||
next = Maybe.map Tuple.second current
|
||||
|> Maybe.map nextEl
|
||||
|> Maybe.andThen (Util.List.get opts)
|
||||
merge item1 item2 = { item2 | active = item1.option.value == item2.option.value }
|
||||
updateModel item = { model | available = List.map (merge item) model.available, menuOpen = True }
|
||||
in
|
||||
case next of
|
||||
Just item -> updateModel item
|
||||
Nothing ->
|
||||
case List.head opts of
|
||||
Just item -> updateModel item
|
||||
Nothing -> model
|
||||
opts =
|
||||
getOptions model
|
||||
|
||||
selectActive: Model a -> Model a
|
||||
current =
|
||||
Util.List.findIndexed .active opts
|
||||
|
||||
next =
|
||||
Maybe.map Tuple.second current
|
||||
|> Maybe.map nextEl
|
||||
|> Maybe.andThen (Util.List.get opts)
|
||||
|
||||
merge item1 item2 =
|
||||
{ item2 | active = item1.option.value == item2.option.value }
|
||||
|
||||
updateModel item =
|
||||
{ model | available = List.map (merge item) model.available, menuOpen = True }
|
||||
in
|
||||
case next of
|
||||
Just item ->
|
||||
updateModel item
|
||||
|
||||
Nothing ->
|
||||
case List.head opts of
|
||||
Just item ->
|
||||
updateModel item
|
||||
|
||||
Nothing ->
|
||||
model
|
||||
|
||||
|
||||
selectActive : Model a -> Model a
|
||||
selectActive model =
|
||||
let
|
||||
current = getOptions model |> Util.List.find .active
|
||||
current =
|
||||
getOptions model |> Util.List.find .active
|
||||
in
|
||||
case current of
|
||||
Just item ->
|
||||
selectItem model item |> applyFilter ""
|
||||
Nothing ->
|
||||
model
|
||||
case current of
|
||||
Just item ->
|
||||
selectItem model item |> applyFilter ""
|
||||
|
||||
clearActive: Model a -> Model a
|
||||
Nothing ->
|
||||
model
|
||||
|
||||
|
||||
clearActive : Model a -> Model a
|
||||
clearActive model =
|
||||
{ model | available = List.map (\e -> {e | active = False}) model.available }
|
||||
{ model | available = List.map (\e -> { e | active = False }) model.available }
|
||||
|
||||
|
||||
|
||||
-- TODO enhance update function to return this info
|
||||
isDropdownChangeMsg: Msg a -> Bool
|
||||
|
||||
|
||||
isDropdownChangeMsg : Msg a -> Bool
|
||||
isDropdownChangeMsg cm =
|
||||
case cm of
|
||||
AddItem _ -> True
|
||||
RemoveItem _ -> True
|
||||
AddItem _ ->
|
||||
True
|
||||
|
||||
RemoveItem _ ->
|
||||
True
|
||||
|
||||
KeyPress code ->
|
||||
Util.Html.intToKeyCode code
|
||||
|> Maybe.map (\c -> c == Util.Html.Enter)
|
||||
|> Maybe.withDefault False
|
||||
_ -> False
|
||||
Util.Html.intToKeyCode code
|
||||
|> Maybe.map (\c -> c == Util.Html.Enter)
|
||||
|> Maybe.withDefault False
|
||||
|
||||
_ ->
|
||||
False
|
||||
|
||||
|
||||
update: Msg a -> Model a -> (Model a, Cmd (Msg a))
|
||||
update : Msg a -> Model a -> ( Model a, Cmd (Msg a) )
|
||||
update msg model =
|
||||
case msg of
|
||||
SetOptions list ->
|
||||
({model | available = List.map (makeItem model) list}, Cmd.none)
|
||||
( { model | available = List.map (makeItem model) list }, Cmd.none )
|
||||
|
||||
SetSelection list ->
|
||||
let
|
||||
m0 = List.foldl (\item -> \m -> deselectItem m item) model model.selected
|
||||
m1 = List.map (makeItem model) list
|
||||
|> List.foldl (\item -> \m -> selectItem m item) m0
|
||||
m0 =
|
||||
List.foldl (\item -> \m -> deselectItem m item) model model.selected
|
||||
|
||||
m1 =
|
||||
List.map (makeItem model) list
|
||||
|> List.foldl (\item -> \m -> selectItem m item) m0
|
||||
in
|
||||
(m1, Cmd.none)
|
||||
( m1, Cmd.none )
|
||||
|
||||
ToggleMenu ->
|
||||
({model | menuOpen = not model.menuOpen}, Cmd.none)
|
||||
( { model | menuOpen = not model.menuOpen }, Cmd.none )
|
||||
|
||||
AddItem e ->
|
||||
let
|
||||
m = selectItem model e |> applyFilter ""
|
||||
m =
|
||||
selectItem model e |> applyFilter ""
|
||||
in
|
||||
({ m | menuOpen = False }, Cmd.none)
|
||||
( { m | menuOpen = False }, Cmd.none )
|
||||
|
||||
RemoveItem e ->
|
||||
let
|
||||
m = deselectItem model e |> applyFilter ""
|
||||
m =
|
||||
deselectItem model e |> applyFilter ""
|
||||
in
|
||||
({ m | menuOpen = False }, Cmd.none)
|
||||
( { m | menuOpen = False }, Cmd.none )
|
||||
|
||||
Filter str ->
|
||||
let
|
||||
m = applyFilter str model
|
||||
m =
|
||||
applyFilter str model
|
||||
in
|
||||
({ m | menuOpen = True}, Cmd.none)
|
||||
( { m | menuOpen = True }, Cmd.none )
|
||||
|
||||
ShowMenu flag ->
|
||||
({ model | menuOpen = flag }, Cmd.none)
|
||||
( { model | menuOpen = flag }, Cmd.none )
|
||||
|
||||
KeyPress code ->
|
||||
case Util.Html.intToKeyCode code of
|
||||
Just Util.Html.Up ->
|
||||
(makeNextActive (\n -> n - 1) model, Cmd.none)
|
||||
( makeNextActive (\n -> n - 1) model, Cmd.none )
|
||||
|
||||
Just Util.Html.Down ->
|
||||
(makeNextActive ((+) 1) model, Cmd.none)
|
||||
( makeNextActive ((+) 1) model, Cmd.none )
|
||||
|
||||
Just Util.Html.Enter ->
|
||||
let
|
||||
m = selectActive model
|
||||
m =
|
||||
selectActive model
|
||||
in
|
||||
({m | menuOpen = False }, Cmd.none)
|
||||
( { m | menuOpen = False }, Cmd.none )
|
||||
|
||||
_ ->
|
||||
(model, Cmd.none)
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
|
||||
-- View
|
||||
|
||||
view: Model a -> Html (Msg a)
|
||||
|
||||
view : Model a -> Html (Msg a)
|
||||
view model =
|
||||
if model.multiple then viewMultiple model else viewSingle model
|
||||
if model.multiple then
|
||||
viewMultiple model
|
||||
|
||||
else
|
||||
viewSingle model
|
||||
|
||||
|
||||
viewSingle: Model a -> Html (Msg a)
|
||||
viewSingle : Model a -> Html (Msg a)
|
||||
viewSingle model =
|
||||
let
|
||||
renderClosed item =
|
||||
div [class "message"
|
||||
,style "display" "inline-block !important"
|
||||
,onClick ToggleMenu
|
||||
div
|
||||
[ class "message"
|
||||
, style "display" "inline-block !important"
|
||||
, onClick ToggleMenu
|
||||
]
|
||||
[i [class "delete icon", onClick (RemoveItem item)][]
|
||||
,text item.option.text
|
||||
[ i [ class "delete icon", onClick (RemoveItem item) ] []
|
||||
, text item.option.text
|
||||
]
|
||||
|
||||
renderDefault =
|
||||
[ List.head model.selected |> Maybe.map renderClosed |> Maybe.withDefault (renderPlaceholder model)
|
||||
, renderMenu model
|
||||
]
|
||||
|
||||
|
||||
openSearch =
|
||||
[ input [ class "search"
|
||||
[ input
|
||||
[ class "search"
|
||||
, placeholder "Search…"
|
||||
, onInput Filter
|
||||
, onKeyUp KeyPress
|
||||
, value model.filterString
|
||||
]
|
||||
[]
|
||||
, renderMenu model
|
||||
]
|
||||
in
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui search dropdown selection", True )
|
||||
, ( "open", model.menuOpen )
|
||||
]
|
||||
]
|
||||
(List.append
|
||||
[ i [ class "dropdown icon", onClick ToggleMenu ] []
|
||||
]
|
||||
<|
|
||||
if model.menuOpen && isSearchable model then
|
||||
openSearch
|
||||
|
||||
else
|
||||
renderDefault
|
||||
)
|
||||
|
||||
|
||||
viewMultiple : Model a -> Html (Msg a)
|
||||
viewMultiple model =
|
||||
let
|
||||
renderSelectMultiple : Item a -> Html (Msg a)
|
||||
renderSelectMultiple item =
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui label", True )
|
||||
, ( model.labelColor item.value, True )
|
||||
]
|
||||
, style "display" "inline-block !important"
|
||||
, onClick (RemoveItem item)
|
||||
]
|
||||
[ text item.option.text
|
||||
, i [ class "delete icon" ] []
|
||||
]
|
||||
in
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui search dropdown multiple selection", True )
|
||||
, ( "open", model.menuOpen )
|
||||
]
|
||||
]
|
||||
(List.concat
|
||||
[ [ i [ class "dropdown icon", onClick ToggleMenu ] []
|
||||
]
|
||||
, List.map renderSelectMultiple model.selected
|
||||
, if isSearchable model then
|
||||
[ input
|
||||
[ class "search"
|
||||
, placeholder "Search…"
|
||||
, onInput Filter
|
||||
, onKeyUp KeyPress
|
||||
, value model.filterString
|
||||
][]
|
||||
, renderMenu model
|
||||
]
|
||||
in
|
||||
div [classList [ ("ui search dropdown selection", True)
|
||||
, ("open", model.menuOpen)
|
||||
]
|
||||
]
|
||||
(List.append [ i [class "dropdown icon", onClick ToggleMenu][]
|
||||
] <|
|
||||
if model.menuOpen && isSearchable model
|
||||
then openSearch
|
||||
else renderDefault
|
||||
)
|
||||
|
||||
|
||||
viewMultiple: Model a -> Html (Msg a)
|
||||
viewMultiple model =
|
||||
let
|
||||
renderSelectMultiple: Item a -> Html (Msg a)
|
||||
renderSelectMultiple item =
|
||||
div [classList [ ("ui label", True)
|
||||
, (model.labelColor item.value, True)
|
||||
]
|
||||
,style "display" "inline-block !important"
|
||||
,onClick (RemoveItem item)
|
||||
]
|
||||
[]
|
||||
]
|
||||
[text item.option.text
|
||||
,i [class "delete icon"][]
|
||||
]
|
||||
in
|
||||
div [classList [ ("ui search dropdown multiple selection", True)
|
||||
, ("open", model.menuOpen)
|
||||
]
|
||||
]
|
||||
(List.concat
|
||||
[ [i [class "dropdown icon", onClick ToggleMenu][]
|
||||
]
|
||||
, List.map renderSelectMultiple model.selected
|
||||
, if isSearchable model then
|
||||
[ input [ class "search"
|
||||
, placeholder "Search…"
|
||||
, onInput Filter
|
||||
, onKeyUp KeyPress
|
||||
, value model.filterString
|
||||
][]
|
||||
]
|
||||
else []
|
||||
, [ renderMenu model
|
||||
]
|
||||
])
|
||||
|
||||
renderMenu: Model a -> Html (Msg a)
|
||||
else
|
||||
[]
|
||||
, [ renderMenu model
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
renderMenu : Model a -> Html (Msg a)
|
||||
renderMenu model =
|
||||
div [classList [( "menu", True )
|
||||
,( "transition visible", model.menuOpen )
|
||||
]
|
||||
] (getOptions model |> List.map renderOption)
|
||||
div
|
||||
[ classList
|
||||
[ ( "menu", True )
|
||||
, ( "transition visible", model.menuOpen )
|
||||
]
|
||||
]
|
||||
(getOptions model |> List.map renderOption)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
renderPlaceholder: Model a -> Html (Msg a)
|
||||
renderPlaceholder : Model a -> Html (Msg a)
|
||||
renderPlaceholder model =
|
||||
div [classList [ ("placeholder-message", True)
|
||||
, ("text", model.multiple)
|
||||
]
|
||||
,style "display" "inline-block !important"
|
||||
,onClick ToggleMenu
|
||||
div
|
||||
[ classList
|
||||
[ ( "placeholder-message", True )
|
||||
, ( "text", model.multiple )
|
||||
]
|
||||
, style "display" "inline-block !important"
|
||||
, onClick ToggleMenu
|
||||
]
|
||||
[ text model.placeholder
|
||||
]
|
||||
[text model.placeholder
|
||||
]
|
||||
|
||||
renderOption: Item a -> Html (Msg a)
|
||||
|
||||
renderOption : Item a -> Html (Msg a)
|
||||
renderOption item =
|
||||
div [classList [ ("item", True)
|
||||
, ("active", item.active || item.selected)
|
||||
]
|
||||
,onClick (AddItem item)
|
||||
div
|
||||
[ classList
|
||||
[ ( "item", True )
|
||||
, ( "active", item.active || item.selected )
|
||||
]
|
||||
, onClick (AddItem item)
|
||||
]
|
||||
[text item.option.text
|
||||
[ text item.option.text
|
||||
]
|
||||
|
@ -1,48 +1,57 @@
|
||||
-- inspired from here: https://ellie-app.com/3T5mNms7SwKa1
|
||||
module Comp.Dropzone exposing ( view
|
||||
, Settings
|
||||
, defaultSettings
|
||||
, update
|
||||
, setActive
|
||||
, Model
|
||||
, init
|
||||
, Msg(..)
|
||||
)
|
||||
|
||||
|
||||
module Comp.Dropzone exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, Settings
|
||||
, defaultSettings
|
||||
, init
|
||||
, setActive
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import File exposing (File)
|
||||
import File.Select
|
||||
import Json.Decode as D
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (..)
|
||||
import Json.Decode as D
|
||||
|
||||
|
||||
type alias State =
|
||||
{ hover: Bool
|
||||
, active: Bool
|
||||
{ hover : Bool
|
||||
, active : Bool
|
||||
}
|
||||
|
||||
|
||||
type alias Settings =
|
||||
{ classList: State -> List (String, Bool)
|
||||
, contentTypes: List String
|
||||
{ classList : State -> List ( String, Bool )
|
||||
, contentTypes : List String
|
||||
}
|
||||
|
||||
defaultSettings: Settings
|
||||
|
||||
defaultSettings : Settings
|
||||
defaultSettings =
|
||||
{ classList = \m -> [("ui placeholder segment", True)]
|
||||
{ classList = \_ -> [ ( "ui placeholder segment", True ) ]
|
||||
, contentTypes = [ "application/pdf" ]
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ state: State
|
||||
, settings: Settings
|
||||
{ state : State
|
||||
, settings : Settings
|
||||
}
|
||||
|
||||
init: Settings -> Model
|
||||
|
||||
init : Settings -> Model
|
||||
init settings =
|
||||
{ state = State False True
|
||||
, settings = settings
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= DragEnter
|
||||
| DragLeave
|
||||
@ -50,45 +59,55 @@ type Msg
|
||||
| PickFiles
|
||||
| SetActive Bool
|
||||
|
||||
setActive: Bool -> Msg
|
||||
|
||||
setActive : Bool -> Msg
|
||||
setActive flag =
|
||||
SetActive flag
|
||||
|
||||
update: Msg -> Model -> (Model, Cmd Msg, List File)
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg, List File )
|
||||
update msg model =
|
||||
case msg of
|
||||
SetActive flag ->
|
||||
let
|
||||
ns = { hover = model.state.hover, active = flag }
|
||||
ns =
|
||||
{ hover = model.state.hover, active = flag }
|
||||
in
|
||||
({ model | state = ns }, Cmd.none, [])
|
||||
( { model | state = ns }, Cmd.none, [] )
|
||||
|
||||
PickFiles ->
|
||||
(model, File.Select.files model.settings.contentTypes GotFiles, [])
|
||||
( model, File.Select.files model.settings.contentTypes GotFiles, [] )
|
||||
|
||||
DragEnter ->
|
||||
let
|
||||
ns = {hover = True, active = model.state.active}
|
||||
ns =
|
||||
{ hover = True, active = model.state.active }
|
||||
in
|
||||
({model| state = ns}, Cmd.none, [])
|
||||
( { model | state = ns }, Cmd.none, [] )
|
||||
|
||||
DragLeave ->
|
||||
let
|
||||
ns = {hover = False, active = model.state.active}
|
||||
ns =
|
||||
{ hover = False, active = model.state.active }
|
||||
in
|
||||
({model | state = ns}, Cmd.none, [])
|
||||
( { model | state = ns }, Cmd.none, [] )
|
||||
|
||||
GotFiles file files ->
|
||||
let
|
||||
ns = {hover = False, active = model.state.active}
|
||||
newFiles = if model.state.active then filterMime model.settings (file :: files)
|
||||
else []
|
||||
ns =
|
||||
{ hover = False, active = model.state.active }
|
||||
|
||||
newFiles =
|
||||
if model.state.active then
|
||||
filterMime model.settings (file :: files)
|
||||
|
||||
else
|
||||
[]
|
||||
in
|
||||
({model | state = ns}, Cmd.none, newFiles)
|
||||
( { model | state = ns }, Cmd.none, newFiles )
|
||||
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div
|
||||
[ classList (model.settings.classList model.state)
|
||||
@ -97,46 +116,51 @@ view model =
|
||||
, hijackOn "dragleave" (D.succeed DragLeave)
|
||||
, hijackOn "drop" dropDecoder
|
||||
]
|
||||
[div [class "ui icon header"]
|
||||
[i [class "mouse pointer icon"][]
|
||||
,div [class "content"]
|
||||
[text "Drop files here"
|
||||
,div [class "sub header"]
|
||||
[text "PDF files only"
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [class "ui horizontal divider"]
|
||||
[text "Or"
|
||||
[ div [ class "ui icon header" ]
|
||||
[ i [ class "mouse pointer icon" ] []
|
||||
, div [ class "content" ]
|
||||
[ text "Drop files here"
|
||||
, div [ class "sub header" ]
|
||||
[ text "PDF files only"
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "ui horizontal divider" ]
|
||||
[ text "Or"
|
||||
]
|
||||
, a
|
||||
[ classList
|
||||
[ ( "ui basic primary button", True )
|
||||
, ( "disabled", not model.state.active )
|
||||
]
|
||||
, onClick PickFiles
|
||||
, href ""
|
||||
]
|
||||
[ i [ class "folder open icon" ] []
|
||||
, text "Select ..."
|
||||
]
|
||||
,a [classList [("ui basic primary button", True)
|
||||
,("disabled", not model.state.active)
|
||||
]
|
||||
, onClick PickFiles
|
||||
, href ""]
|
||||
[i [class "folder open icon"][]
|
||||
,text "Select ..."
|
||||
]
|
||||
]
|
||||
|
||||
filterMime: Settings -> List File -> List File
|
||||
|
||||
filterMime : Settings -> List File -> List File
|
||||
filterMime settings files =
|
||||
let
|
||||
pred f =
|
||||
List.member (File.mime f) settings.contentTypes
|
||||
in
|
||||
List.filter pred files
|
||||
List.filter pred files
|
||||
|
||||
|
||||
dropDecoder : D.Decoder Msg
|
||||
dropDecoder =
|
||||
D.at ["dataTransfer","files"] (D.oneOrMore GotFiles File.decoder)
|
||||
D.at [ "dataTransfer", "files" ] (D.oneOrMore GotFiles File.decoder)
|
||||
|
||||
|
||||
hijackOn : String -> D.Decoder msg -> Attribute msg
|
||||
hijackOn event decoder =
|
||||
preventDefaultOn event (D.map hijack decoder)
|
||||
preventDefaultOn event (D.map hijack decoder)
|
||||
|
||||
|
||||
hijack : msg -> (msg, Bool)
|
||||
hijack : msg -> ( msg, Bool )
|
||||
hijack msg =
|
||||
(msg, True)
|
||||
( msg, True )
|
||||
|
@ -1,62 +1,74 @@
|
||||
module Comp.EquipmentForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, getEquipment)
|
||||
module Comp.EquipmentForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getEquipment
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ equipment: Equipment
|
||||
, name: String
|
||||
{ equipment : Equipment
|
||||
, name : String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ equipment = Api.Model.Equipment.empty
|
||||
, name = ""
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.name /= ""
|
||||
|
||||
getEquipment: Model -> Equipment
|
||||
|
||||
getEquipment : Model -> Equipment
|
||||
getEquipment model =
|
||||
Equipment model.equipment.id model.name model.equipment.created
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
| SetEquipment Equipment
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetEquipment t ->
|
||||
({model | equipment = t, name = t.name }, Cmd.none)
|
||||
( { model | equipment = t, name = t.name }, Cmd.none )
|
||||
|
||||
SetName n ->
|
||||
({model | name = n}, Cmd.none)
|
||||
( { model | name = n }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", not (isValid model))
|
||||
]
|
||||
]
|
||||
[label [][text "Name*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetName
|
||||
,placeholder "Name"
|
||||
,value model.name
|
||||
][]
|
||||
]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", not (isValid model) )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "Name*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, placeholder "Name"
|
||||
, value model.name
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.EquipmentManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.EquipmentManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Equipment
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
import Comp.EquipmentForm
|
||||
import Comp.EquipmentTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.EquipmentTable
|
||||
import Comp.EquipmentForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.Equipment
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tableModel: Comp.EquipmentTable.Model
|
||||
, formModel: Comp.EquipmentForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tableModel : Comp.EquipmentTable.Model
|
||||
, formModel : Comp.EquipmentForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tableModel = Comp.EquipmentTable.emptyModel
|
||||
, formModel = Comp.EquipmentForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.EquipmentTable.Msg
|
||||
| FormMsg Comp.EquipmentForm.Msg
|
||||
@ -52,155 +60,210 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.EquipmentTable.update flags m model.tableModel
|
||||
(m2, c2) = ({model | tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.EquipmentTable.update flags m model.tableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just equipment ->
|
||||
update flags (FormMsg (Comp.EquipmentForm.SetEquipment equipment)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.EquipmentForm.update flags m model.formModel
|
||||
( m2, c2 ) =
|
||||
Comp.EquipmentForm.update flags m model.formModel
|
||||
in
|
||||
({model | formModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadEquipments ->
|
||||
({model| loading = True}, Api.getEquipments flags EquipmentResp)
|
||||
( { model | loading = True }, Api.getEquipments flags EquipmentResp )
|
||||
|
||||
EquipmentResp (Ok equipments) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.EquipmentTable.SetEquipments equipments.items)) m2
|
||||
update flags (TableMsg (Comp.EquipmentTable.SetEquipments equipments.items)) m2
|
||||
|
||||
EquipmentResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
EquipmentResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.EquipmentTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.EquipmentTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewEquipment ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
equipment = Api.Model.Equipment.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
equipment =
|
||||
Api.Model.Equipment.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.EquipmentForm.SetEquipment equipment)) nm
|
||||
update flags (FormMsg (Comp.EquipmentForm.SetEquipment equipment)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
equipment = Comp.EquipmentForm.getEquipment model.formModel
|
||||
valid = Comp.EquipmentForm.isValid model.formModel
|
||||
in if valid then
|
||||
({model|loading = True}, Api.postEquipment flags equipment SubmitResp)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
equipment =
|
||||
Comp.EquipmentForm.getEquipment model.formModel
|
||||
|
||||
valid =
|
||||
Comp.EquipmentForm.isValid model.formModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postEquipment flags equipment SubmitResp )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadEquipments m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadEquipments m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
equip = Comp.EquipmentForm.getEquipment model.formModel
|
||||
cmd = if confirmed then Api.deleteEquip flags equip.id SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
equip =
|
||||
Comp.EquipmentForm.getEquipment model.formModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deleteEquip flags equip.id SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else viewForm model
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
viewForm model
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewEquipment]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.EquipmentTable.view model.tableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewEquipment ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.EquipmentTable.view model.tableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Model -> Html Msg
|
||||
|
||||
viewForm : Model -> Html Msg
|
||||
viewForm model =
|
||||
let
|
||||
newEquipment = model.formModel.equipment.id == ""
|
||||
newEquipment =
|
||||
model.formModel.equipment.id == ""
|
||||
in
|
||||
Html.form [class "ui segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,if newEquipment then
|
||||
h3 [class "ui dividing header"]
|
||||
[text "Create new equipment"
|
||||
]
|
||||
else
|
||||
h3 [class "ui dividing header"]
|
||||
[text ("Edit equipment: " ++ model.formModel.equipment.name)
|
||||
,div [class "sub header"]
|
||||
[text "Id: "
|
||||
,text model.formModel.equipment.id
|
||||
]
|
||||
]
|
||||
,Html.map FormMsg (Comp.EquipmentForm.view model.formModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newEquipment then
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text "Create new equipment"
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit equipment: " ++ model.formModel.equipment.name)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.equipment.id
|
||||
]
|
||||
]
|
||||
, Html.map FormMsg (Comp.EquipmentForm.view model.formModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newEquipment then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newEquipment then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,62 +1,70 @@
|
||||
module Comp.EquipmentTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.EquipmentTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ equips: List Equipment
|
||||
, selected: Maybe Equipment
|
||||
{ equips : List Equipment
|
||||
, selected : Maybe Equipment
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ equips = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetEquipments (List Equipment)
|
||||
| Select Equipment
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetEquipments list ->
|
||||
({model | equips = list, selected = Nothing }, Cmd.none)
|
||||
( { model | equips = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select equip ->
|
||||
({model | selected = Just equip}, Cmd.none)
|
||||
( { model | selected = Just equip }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [][text "Name"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [] [ text "Name" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderEquipmentLine model) model.equips)
|
||||
]
|
||||
|
||||
renderEquipmentLine: Model -> Equipment -> Html Msg
|
||||
|
||||
renderEquipmentLine : Model -> Equipment -> Html Msg
|
||||
renderEquipmentLine model equip =
|
||||
tr [classList [("active", model.selected == Just equip)]
|
||||
,onClick (Select equip)
|
||||
]
|
||||
[td []
|
||||
[text equip.name
|
||||
]
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just equip ) ]
|
||||
, onClick (Select equip)
|
||||
]
|
||||
[ td []
|
||||
[ text equip.name
|
||||
]
|
||||
]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,36 +1,41 @@
|
||||
module Comp.ItemList exposing (Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, prevItem
|
||||
, nextItem
|
||||
, update
|
||||
, view)
|
||||
module Comp.ItemList exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, nextItem
|
||||
, prevItem
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Set exposing (Set)
|
||||
import Api.Model.ItemLight exposing (ItemLight)
|
||||
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
|
||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||
import Data.Direction
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
|
||||
import Api.Model.ItemLight exposing (ItemLight)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Direction
|
||||
import Set exposing (Set)
|
||||
import Util.List
|
||||
import Util.Maybe
|
||||
import Util.String
|
||||
import Util.Time
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ results: ItemLightList
|
||||
, openGroups: Set String
|
||||
{ results : ItemLightList
|
||||
, openGroups : Set String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ results = Api.Model.ItemLightList.empty
|
||||
, openGroups = Set.empty
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetResults ItemLightList
|
||||
| ToggleGroupState ItemLightGroup
|
||||
@ -38,198 +43,243 @@ type Msg
|
||||
| ExpandAll
|
||||
| SelectItem ItemLight
|
||||
|
||||
nextItem: Model -> String -> Maybe ItemLight
|
||||
|
||||
nextItem : Model -> String -> Maybe ItemLight
|
||||
nextItem model id =
|
||||
List.concatMap .items model.results.groups
|
||||
|> Util.List.findNext (\i -> i.id == id)
|
||||
|
||||
prevItem: Model -> String -> Maybe ItemLight
|
||||
|
||||
prevItem : Model -> String -> Maybe ItemLight
|
||||
prevItem model id =
|
||||
List.concatMap .items model.results.groups
|
||||
|> Util.List.findPrev (\i -> i.id == id)
|
||||
|
||||
openAllGroups: Model -> Set String
|
||||
|
||||
openAllGroups : Model -> Set String
|
||||
openAllGroups model =
|
||||
List.foldl
|
||||
(\g -> \set -> Set.insert g.name set)
|
||||
model.openGroups
|
||||
model.results.groups
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg, Maybe ItemLight)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe ItemLight )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetResults list ->
|
||||
let
|
||||
newModel = { model | results = list, openGroups = Set.empty }
|
||||
newModel =
|
||||
{ model | results = list, openGroups = Set.empty }
|
||||
in
|
||||
({newModel|openGroups = openAllGroups newModel}, Cmd.none, Nothing)
|
||||
( { newModel | openGroups = openAllGroups newModel }, Cmd.none, Nothing )
|
||||
|
||||
ToggleGroupState group ->
|
||||
let
|
||||
m2 = if isGroupOpen model group then closeGroup model group
|
||||
else openGroup model group
|
||||
m2 =
|
||||
if isGroupOpen model group then
|
||||
closeGroup model group
|
||||
|
||||
else
|
||||
openGroup model group
|
||||
in
|
||||
(m2, Cmd.none, Nothing)
|
||||
( m2, Cmd.none, Nothing )
|
||||
|
||||
CollapseAll ->
|
||||
({model | openGroups = Set.empty }, Cmd.none, Nothing)
|
||||
( { model | openGroups = Set.empty }, Cmd.none, Nothing )
|
||||
|
||||
ExpandAll ->
|
||||
let
|
||||
open = openAllGroups model
|
||||
open =
|
||||
openAllGroups model
|
||||
in
|
||||
({model | openGroups = open }, Cmd.none, Nothing)
|
||||
( { model | openGroups = open }, Cmd.none, Nothing )
|
||||
|
||||
SelectItem item ->
|
||||
(model, Cmd.none, Just item)
|
||||
( model, Cmd.none, Just item )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[div [class "ui ablue-comp menu"]
|
||||
[div [class "right floated menu"]
|
||||
[a [class "item"
|
||||
,title "Expand all"
|
||||
,onClick ExpandAll
|
||||
,href ""
|
||||
]
|
||||
[i [class "double angle down icon"][]
|
||||
]
|
||||
,a [class "item"
|
||||
,title "Collapse all"
|
||||
,onClick CollapseAll
|
||||
,href ""
|
||||
]
|
||||
[i [class "double angle up icon"][]
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [class "ui middle aligned very relaxed divided basic list segment"]
|
||||
[ div [ class "ui ablue-comp menu" ]
|
||||
[ div [ class "right floated menu" ]
|
||||
[ a
|
||||
[ class "item"
|
||||
, title "Expand all"
|
||||
, onClick ExpandAll
|
||||
, href ""
|
||||
]
|
||||
[ i [ class "double angle down icon" ] []
|
||||
]
|
||||
, a
|
||||
[ class "item"
|
||||
, title "Collapse all"
|
||||
, onClick CollapseAll
|
||||
, href ""
|
||||
]
|
||||
[ i [ class "double angle up icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "ui middle aligned very relaxed divided basic list segment" ]
|
||||
(List.map (viewGroup model) model.results.groups)
|
||||
]
|
||||
|
||||
|
||||
isGroupOpen: Model -> ItemLightGroup -> Bool
|
||||
isGroupOpen : Model -> ItemLightGroup -> Bool
|
||||
isGroupOpen model group =
|
||||
Set.member group.name model.openGroups
|
||||
|
||||
openGroup: Model -> ItemLightGroup -> Model
|
||||
|
||||
openGroup : Model -> ItemLightGroup -> Model
|
||||
openGroup model group =
|
||||
{ model | openGroups = Set.insert group.name model.openGroups }
|
||||
|
||||
closeGroup: Model -> ItemLightGroup -> Model
|
||||
|
||||
closeGroup : Model -> ItemLightGroup -> Model
|
||||
closeGroup model group =
|
||||
{ model | openGroups = Set.remove group.name model.openGroups }
|
||||
|
||||
viewGroup: Model -> ItemLightGroup -> Html Msg
|
||||
|
||||
viewGroup : Model -> ItemLightGroup -> Html Msg
|
||||
viewGroup model group =
|
||||
let
|
||||
groupOpen = isGroupOpen model group
|
||||
groupOpen =
|
||||
isGroupOpen model group
|
||||
|
||||
children =
|
||||
[i [classList [("large middle aligned icon", True)
|
||||
,("caret right", not groupOpen)
|
||||
,("caret down", groupOpen)
|
||||
]][]
|
||||
,div [class "content"]
|
||||
[div [class "right floated content"]
|
||||
[div [class "ui blue label"]
|
||||
[List.length group.items |> String.fromInt |> text
|
||||
]
|
||||
]
|
||||
,a [class "header"
|
||||
,onClick (ToggleGroupState group)
|
||||
,href ""
|
||||
]
|
||||
[text group.name
|
||||
]
|
||||
,div [class "description"]
|
||||
[makeSummary group |> text
|
||||
[ i
|
||||
[ classList
|
||||
[ ( "large middle aligned icon", True )
|
||||
, ( "caret right", not groupOpen )
|
||||
, ( "caret down", groupOpen )
|
||||
]
|
||||
]
|
||||
[]
|
||||
, div [ class "content" ]
|
||||
[ div [ class "right floated content" ]
|
||||
[ div [ class "ui blue label" ]
|
||||
[ List.length group.items |> String.fromInt |> text
|
||||
]
|
||||
]
|
||||
, a
|
||||
[ class "header"
|
||||
, onClick (ToggleGroupState group)
|
||||
, href ""
|
||||
]
|
||||
[ text group.name
|
||||
]
|
||||
, div [ class "description" ]
|
||||
[ makeSummary group |> text
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
itemTable =
|
||||
div [class "ui basic content segment no-margin"]
|
||||
[(renderItemTable model group.items)
|
||||
div [ class "ui basic content segment no-margin" ]
|
||||
[ renderItemTable model group.items
|
||||
]
|
||||
in
|
||||
if isGroupOpen model group then
|
||||
div [class "item"]
|
||||
(List.append children [itemTable])
|
||||
else
|
||||
div [class "item"]
|
||||
children
|
||||
if isGroupOpen model group then
|
||||
div [ class "item" ]
|
||||
(List.append children [ itemTable ])
|
||||
|
||||
else
|
||||
div [ class "item" ]
|
||||
children
|
||||
|
||||
|
||||
renderItemTable: Model -> List ItemLight -> Html Msg
|
||||
renderItemTable : Model -> List ItemLight -> Html Msg
|
||||
renderItemTable model items =
|
||||
table [class "ui selectable padded table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [class "collapsing"][]
|
||||
,th [class "collapsing"][text "Name"]
|
||||
,th [class "collapsing"][text "Date"]
|
||||
,th [class "collapsing"][text "Source"]
|
||||
,th [][text "Correspondent"]
|
||||
,th [][text "Concerning"]
|
||||
]
|
||||
]
|
||||
,tbody[]
|
||||
table [ class "ui selectable padded table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [ class "collapsing" ] [ text "Name" ]
|
||||
, th [ class "collapsing" ] [ text "Date" ]
|
||||
, th [ class "collapsing" ] [ text "Source" ]
|
||||
, th [] [ text "Correspondent" ]
|
||||
, th [] [ text "Concerning" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderItemLine model) items)
|
||||
]
|
||||
|
||||
renderItemLine: Model -> ItemLight -> Html Msg
|
||||
|
||||
renderItemLine : Model -> ItemLight -> Html Msg
|
||||
renderItemLine model item =
|
||||
let
|
||||
dirIcon = i [class (Data.Direction.iconFromMaybe item.direction)][]
|
||||
corr = List.filterMap identity [item.corrOrg, item.corrPerson]
|
||||
|> List.map .name
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
conc = List.filterMap identity [item.concPerson, item.concEquip]
|
||||
|> List.map .name
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
dirIcon =
|
||||
i [ class (Data.Direction.iconFromMaybe item.direction) ] []
|
||||
|
||||
corr =
|
||||
List.filterMap identity [ item.corrOrg, item.corrPerson ]
|
||||
|> List.map .name
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
|
||||
conc =
|
||||
List.filterMap identity [ item.concPerson, item.concEquip ]
|
||||
|> List.map .name
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
in
|
||||
tr [onClick (SelectItem item)]
|
||||
[td [class "collapsing"]
|
||||
[div [classList [("ui teal ribbon label", True)
|
||||
,("invisible", item.state /= "created")
|
||||
]
|
||||
][text "New"
|
||||
]
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[ dirIcon
|
||||
, Util.String.ellipsis 45 item.name |> text
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[Util.Time.formatDateShort item.date |> text
|
||||
,span [classList [("invisible", Util.Maybe.isEmpty item.dueDate)
|
||||
]
|
||||
]
|
||||
[text " "
|
||||
,div [class "ui basic label"]
|
||||
[i [class "bell icon"][]
|
||||
,Maybe.map Util.Time.formatDateShort item.dueDate |> Maybe.withDefault "" |> text
|
||||
]
|
||||
tr [ onClick (SelectItem item) ]
|
||||
[ td [ class "collapsing" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "ui teal ribbon label", True )
|
||||
, ( "invisible", item.state /= "created" )
|
||||
]
|
||||
]
|
||||
,td [class "collapsing"][text item.source]
|
||||
,td [][text corr]
|
||||
,td [][text conc]
|
||||
[ text "New"
|
||||
]
|
||||
]
|
||||
, td [ class "collapsing" ]
|
||||
[ dirIcon
|
||||
, Util.String.ellipsis 45 item.name |> text
|
||||
]
|
||||
, td [ class "collapsing" ]
|
||||
[ Util.Time.formatDateShort item.date |> text
|
||||
, span
|
||||
[ classList
|
||||
[ ( "invisible", Util.Maybe.isEmpty item.dueDate )
|
||||
]
|
||||
]
|
||||
[ text " "
|
||||
, div [ class "ui basic label" ]
|
||||
[ i [ class "bell icon" ] []
|
||||
, Maybe.map Util.Time.formatDateShort item.dueDate |> Maybe.withDefault "" |> text
|
||||
]
|
||||
]
|
||||
]
|
||||
, td [ class "collapsing" ] [ text item.source ]
|
||||
, td [] [ text corr ]
|
||||
, td [] [ text conc ]
|
||||
]
|
||||
|
||||
makeSummary: ItemLightGroup -> String
|
||||
|
||||
makeSummary : ItemLightGroup -> String
|
||||
makeSummary group =
|
||||
let
|
||||
corrOrgs = List.filterMap .corrOrg group.items
|
||||
corrPers = List.filterMap .corrPerson group.items
|
||||
concPers = List.filterMap .concPerson group.items
|
||||
concEqui = List.filterMap .concEquip group.items
|
||||
all = List.concat [corrOrgs, corrPers, concPers, concEqui]
|
||||
corrOrgs =
|
||||
List.filterMap .corrOrg group.items
|
||||
|
||||
corrPers =
|
||||
List.filterMap .corrPerson group.items
|
||||
|
||||
concPers =
|
||||
List.filterMap .concPerson group.items
|
||||
|
||||
concEqui =
|
||||
List.filterMap .concEquip group.items
|
||||
|
||||
all =
|
||||
List.concat [ corrOrgs, corrPers, concPers, concEqui ]
|
||||
in
|
||||
List.map .name all
|
||||
|> Util.List.distinct
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
List.map .name all
|
||||
|> Util.List.distinct
|
||||
|> List.intersperse ", "
|
||||
|> String.concat
|
||||
|
@ -1,28 +1,32 @@
|
||||
module Comp.OrgForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, getOrg)
|
||||
module Comp.OrgForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getOrg
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Organization exposing (Organization)
|
||||
import Comp.AddressForm
|
||||
import Comp.ContactField
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ org: Organization
|
||||
, name: String
|
||||
, addressModel: Comp.AddressForm.Model
|
||||
, contactModel: Comp.ContactField.Model
|
||||
, notes: Maybe String
|
||||
{ org : Organization
|
||||
, name : String
|
||||
, addressModel : Comp.AddressForm.Model
|
||||
, contactModel : Comp.ContactField.Model
|
||||
, notes : Maybe String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ org = Api.Model.Organization.empty
|
||||
, name = ""
|
||||
@ -31,20 +35,25 @@ emptyModel =
|
||||
, notes = Nothing
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.name /= ""
|
||||
|
||||
getOrg: Model -> Organization
|
||||
|
||||
getOrg : Model -> Organization
|
||||
getOrg model =
|
||||
let
|
||||
o = model.org
|
||||
o =
|
||||
model.org
|
||||
in
|
||||
{ o | name = model.name
|
||||
, address = Comp.AddressForm.getAddress model.addressModel
|
||||
, contacts = Comp.ContactField.getContacts model.contactModel
|
||||
, notes = model.notes
|
||||
}
|
||||
{ o
|
||||
| name = model.name
|
||||
, address = Comp.AddressForm.getAddress model.addressModel
|
||||
, contacts = Comp.ContactField.getContacts model.contactModel
|
||||
, notes = model.notes
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
@ -53,61 +62,80 @@ type Msg
|
||||
| ContactMsg Comp.ContactField.Msg
|
||||
| SetNotes String
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetOrg t ->
|
||||
let
|
||||
(m1, c1) = update flags (AddressMsg (Comp.AddressForm.SetAddress t.address)) model
|
||||
(m2, c2) = update flags (ContactMsg (Comp.ContactField.SetItems t.contacts)) m1
|
||||
( m1, c1 ) =
|
||||
update flags (AddressMsg (Comp.AddressForm.SetAddress t.address)) model
|
||||
|
||||
( m2, c2 ) =
|
||||
update flags (ContactMsg (Comp.ContactField.SetItems t.contacts)) m1
|
||||
in
|
||||
({m2 | org = t, name = t.name, notes = t.notes }, Cmd.none)
|
||||
( { m2 | org = t, name = t.name, notes = t.notes }, Cmd.batch [ c1, c2 ] )
|
||||
|
||||
AddressMsg am ->
|
||||
let
|
||||
(m1, c1) = Comp.AddressForm.update am model.addressModel
|
||||
( m1, c1 ) =
|
||||
Comp.AddressForm.update am model.addressModel
|
||||
in
|
||||
({model | addressModel = m1}, Cmd.map AddressMsg c1)
|
||||
( { model | addressModel = m1 }, Cmd.map AddressMsg c1 )
|
||||
|
||||
ContactMsg m ->
|
||||
let
|
||||
(m1, c1) = Comp.ContactField.update m model.contactModel
|
||||
( m1, c1 ) =
|
||||
Comp.ContactField.update m model.contactModel
|
||||
in
|
||||
({model | contactModel = m1}, Cmd.map ContactMsg c1)
|
||||
( { model | contactModel = m1 }, Cmd.map ContactMsg c1 )
|
||||
|
||||
SetName n ->
|
||||
({model | name = n}, Cmd.none)
|
||||
( { model | name = n }, Cmd.none )
|
||||
|
||||
SetNotes str ->
|
||||
({model | notes = if str == "" then Nothing else Just str}, Cmd.none)
|
||||
( { model
|
||||
| notes =
|
||||
if str == "" then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just str
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", not (isValid model))
|
||||
]
|
||||
]
|
||||
[label [][text "Name*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetName
|
||||
,placeholder "Name"
|
||||
,value model.name
|
||||
][]
|
||||
]
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Address"
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", not (isValid model) )
|
||||
]
|
||||
]
|
||||
,Html.map AddressMsg (Comp.AddressForm.view model.addressModel)
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Contacts"
|
||||
[ label [] [ text "Name*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, placeholder "Name"
|
||||
, value model.name
|
||||
]
|
||||
[]
|
||||
]
|
||||
,Html.map ContactMsg (Comp.ContactField.view model.contactModel)
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Notes"
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Address"
|
||||
]
|
||||
,div [class "field"]
|
||||
[textarea [onInput SetNotes][Maybe.withDefault "" model.notes |> text ]
|
||||
, Html.map AddressMsg (Comp.AddressForm.view model.addressModel)
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Contacts"
|
||||
]
|
||||
, Html.map ContactMsg (Comp.ContactField.view model.contactModel)
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Notes"
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ textarea [ onInput SetNotes ] [ Maybe.withDefault "" model.notes |> text ]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.OrgManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.OrgManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Organization
|
||||
import Api.Model.OrganizationList exposing (OrganizationList)
|
||||
import Comp.OrgForm
|
||||
import Comp.OrgTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.OrgTable
|
||||
import Comp.OrgForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.Organization
|
||||
import Api.Model.OrganizationList exposing (OrganizationList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tableModel: Comp.OrgTable.Model
|
||||
, formModel: Comp.OrgForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tableModel : Comp.OrgTable.Model
|
||||
, formModel : Comp.OrgForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tableModel = Comp.OrgTable.emptyModel
|
||||
, formModel = Comp.OrgForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.OrgTable.Msg
|
||||
| FormMsg Comp.OrgForm.Msg
|
||||
@ -52,155 +60,210 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.OrgTable.update flags m model.tableModel
|
||||
(m2, c2) = ({model | tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.OrgTable.update flags m model.tableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just org ->
|
||||
update flags (FormMsg (Comp.OrgForm.SetOrg org)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.OrgForm.update flags m model.formModel
|
||||
( m2, c2 ) =
|
||||
Comp.OrgForm.update flags m model.formModel
|
||||
in
|
||||
({model | formModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadOrgs ->
|
||||
({model| loading = True}, Api.getOrganizations flags OrgResp)
|
||||
( { model | loading = True }, Api.getOrganizations flags OrgResp )
|
||||
|
||||
OrgResp (Ok orgs) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.OrgTable.SetOrgs orgs.items)) m2
|
||||
update flags (TableMsg (Comp.OrgTable.SetOrgs orgs.items)) m2
|
||||
|
||||
OrgResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
OrgResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.OrgTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.OrgTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewOrg ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
org = Api.Model.Organization.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
org =
|
||||
Api.Model.Organization.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.OrgForm.SetOrg org)) nm
|
||||
update flags (FormMsg (Comp.OrgForm.SetOrg org)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
org = Comp.OrgForm.getOrg model.formModel
|
||||
valid = Comp.OrgForm.isValid model.formModel
|
||||
in if valid then
|
||||
({model|loading = True}, Api.postOrg flags org SubmitResp)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
org =
|
||||
Comp.OrgForm.getOrg model.formModel
|
||||
|
||||
valid =
|
||||
Comp.OrgForm.isValid model.formModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postOrg flags org SubmitResp )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadOrgs m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadOrgs m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
org = Comp.OrgForm.getOrg model.formModel
|
||||
cmd = if confirmed then Api.deleteOrg flags org.id SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
org =
|
||||
Comp.OrgForm.getOrg model.formModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deleteOrg flags org.id SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else viewForm model
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
viewForm model
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewOrg]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.OrgTable.view model.tableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewOrg ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.OrgTable.view model.tableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Model -> Html Msg
|
||||
|
||||
viewForm : Model -> Html Msg
|
||||
viewForm model =
|
||||
let
|
||||
newOrg = model.formModel.org.id == ""
|
||||
newOrg =
|
||||
model.formModel.org.id == ""
|
||||
in
|
||||
Html.form [class "ui segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,if newOrg then
|
||||
h3 [class "ui dividing header"]
|
||||
[text "Create new organization"
|
||||
]
|
||||
else
|
||||
h3 [class "ui dividing header"]
|
||||
[text ("Edit org: " ++ model.formModel.org.name)
|
||||
,div [class "sub header"]
|
||||
[text "Id: "
|
||||
,text model.formModel.org.id
|
||||
]
|
||||
]
|
||||
,Html.map FormMsg (Comp.OrgForm.view model.formModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newOrg then
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text "Create new organization"
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit org: " ++ model.formModel.org.name)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.org.id
|
||||
]
|
||||
]
|
||||
, Html.map FormMsg (Comp.OrgForm.view model.formModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newOrg then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newOrg then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,74 +1,80 @@
|
||||
module Comp.OrgTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.OrgTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Organization exposing (Organization)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Organization exposing (Organization)
|
||||
import Api.Model.Address exposing (Address)
|
||||
import Api.Model.Contact exposing (Contact)
|
||||
import Util.Address
|
||||
import Util.Contact
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ equips: List Organization
|
||||
, selected: Maybe Organization
|
||||
{ equips : List Organization
|
||||
, selected : Maybe Organization
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ equips = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetOrgs (List Organization)
|
||||
| Select Organization
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetOrgs list ->
|
||||
({model | equips = list, selected = Nothing }, Cmd.none)
|
||||
( { model | equips = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select equip ->
|
||||
({model | selected = Just equip}, Cmd.none)
|
||||
( { model | selected = Just equip }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [class "collapsing"][text "Name"]
|
||||
,th [][text "Address"]
|
||||
,th [][text "Contact"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Name" ]
|
||||
, th [] [ text "Address" ]
|
||||
, th [] [ text "Contact" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderOrgLine model) model.equips)
|
||||
]
|
||||
|
||||
renderOrgLine: Model -> Organization -> Html Msg
|
||||
|
||||
renderOrgLine : Model -> Organization -> Html Msg
|
||||
renderOrgLine model org =
|
||||
tr [classList [("active", model.selected == Just org)]
|
||||
,onClick (Select org)
|
||||
]
|
||||
[td [class "collapsing"]
|
||||
[text org.name
|
||||
]
|
||||
,td []
|
||||
[Util.Address.toString org.address |> text
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just org ) ]
|
||||
, onClick (Select org)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ text org.name
|
||||
]
|
||||
,td []
|
||||
[Util.Contact.toString org.contacts |> text
|
||||
, td []
|
||||
[ Util.Address.toString org.address |> text
|
||||
]
|
||||
, td []
|
||||
[ Util.Contact.toString org.contacts |> text
|
||||
]
|
||||
]
|
||||
|
@ -1,30 +1,33 @@
|
||||
module Comp.PersonForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, getPerson)
|
||||
module Comp.PersonForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getPerson
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onCheck)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Comp.AddressForm
|
||||
import Comp.ContactField
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onCheck, onInput)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ org: Person
|
||||
, name: String
|
||||
, addressModel: Comp.AddressForm.Model
|
||||
, contactModel: Comp.ContactField.Model
|
||||
, notes: Maybe String
|
||||
, concerning: Bool
|
||||
{ org : Person
|
||||
, name : String
|
||||
, addressModel : Comp.AddressForm.Model
|
||||
, contactModel : Comp.ContactField.Model
|
||||
, notes : Maybe String
|
||||
, concerning : Bool
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ org = Api.Model.Person.empty
|
||||
, name = ""
|
||||
@ -34,21 +37,26 @@ emptyModel =
|
||||
, concerning = False
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.name /= ""
|
||||
|
||||
getPerson: Model -> Person
|
||||
|
||||
getPerson : Model -> Person
|
||||
getPerson model =
|
||||
let
|
||||
o = model.org
|
||||
o =
|
||||
model.org
|
||||
in
|
||||
{ o | name = model.name
|
||||
, address = Comp.AddressForm.getAddress model.addressModel
|
||||
, contacts = Comp.ContactField.getContacts model.contactModel
|
||||
, notes = model.notes
|
||||
, concerning = model.concerning
|
||||
}
|
||||
{ o
|
||||
| name = model.name
|
||||
, address = Comp.AddressForm.getAddress model.addressModel
|
||||
, contacts = Comp.ContactField.getContacts model.contactModel
|
||||
, notes = model.notes
|
||||
, concerning = model.concerning
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
@ -58,72 +66,101 @@ type Msg
|
||||
| SetNotes String
|
||||
| SetConcerning Bool
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetPerson t ->
|
||||
let
|
||||
(m1, c1) = update flags (AddressMsg (Comp.AddressForm.SetAddress t.address)) model
|
||||
(m2, c2) = update flags (ContactMsg (Comp.ContactField.SetItems t.contacts)) m1
|
||||
( m1, c1 ) =
|
||||
update flags (AddressMsg (Comp.AddressForm.SetAddress t.address)) model
|
||||
|
||||
( m2, c2 ) =
|
||||
update flags (ContactMsg (Comp.ContactField.SetItems t.contacts)) m1
|
||||
in
|
||||
({m2 | org = t, name = t.name, notes = t.notes, concerning = t.concerning }, Cmd.none)
|
||||
( { m2
|
||||
| org = t
|
||||
, name = t.name
|
||||
, notes = t.notes
|
||||
, concerning = t.concerning
|
||||
}
|
||||
, Cmd.batch [ c1, c2 ]
|
||||
)
|
||||
|
||||
AddressMsg am ->
|
||||
let
|
||||
(m1, c1) = Comp.AddressForm.update am model.addressModel
|
||||
( m1, c1 ) =
|
||||
Comp.AddressForm.update am model.addressModel
|
||||
in
|
||||
({model | addressModel = m1}, Cmd.map AddressMsg c1)
|
||||
( { model | addressModel = m1 }, Cmd.map AddressMsg c1 )
|
||||
|
||||
ContactMsg m ->
|
||||
let
|
||||
(m1, c1) = Comp.ContactField.update m model.contactModel
|
||||
( m1, c1 ) =
|
||||
Comp.ContactField.update m model.contactModel
|
||||
in
|
||||
({model | contactModel = m1}, Cmd.map ContactMsg c1)
|
||||
( { model | contactModel = m1 }, Cmd.map ContactMsg c1 )
|
||||
|
||||
SetName n ->
|
||||
({model | name = n}, Cmd.none)
|
||||
( { model | name = n }, Cmd.none )
|
||||
|
||||
SetNotes str ->
|
||||
({model | notes = if str == "" then Nothing else Just str}, Cmd.none)
|
||||
( { model
|
||||
| notes =
|
||||
if str == "" then
|
||||
Nothing
|
||||
|
||||
SetConcerning flag ->
|
||||
({model | concerning = not model.concerning}, Cmd.none)
|
||||
else
|
||||
Just str
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SetConcerning _ ->
|
||||
( { model | concerning = not model.concerning }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", not (isValid model))
|
||||
]
|
||||
]
|
||||
[label [][text "Name*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetName
|
||||
,placeholder "Name"
|
||||
,value model.name
|
||||
][]
|
||||
]
|
||||
,div [class "inline field"]
|
||||
[div [class "ui checkbox"]
|
||||
[input [type_ "checkbox"
|
||||
, checked model.concerning
|
||||
, onCheck SetConcerning][]
|
||||
,label [][text "Use for concerning person suggestion only"]
|
||||
]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", not (isValid model) )
|
||||
]
|
||||
]
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Address"
|
||||
[ label [] [ text "Name*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, placeholder "Name"
|
||||
, value model.name
|
||||
]
|
||||
[]
|
||||
]
|
||||
,Html.map AddressMsg (Comp.AddressForm.view model.addressModel)
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Contacts"
|
||||
, div [ class "inline field" ]
|
||||
[ div [ class "ui checkbox" ]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, checked model.concerning
|
||||
, onCheck SetConcerning
|
||||
]
|
||||
[]
|
||||
, label [] [ text "Use for concerning person suggestion only" ]
|
||||
]
|
||||
]
|
||||
,Html.map ContactMsg (Comp.ContactField.view model.contactModel)
|
||||
,h3 [class "ui dividing header"]
|
||||
[text "Notes"
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Address"
|
||||
]
|
||||
,div [class "field"]
|
||||
[textarea [onInput SetNotes][Maybe.withDefault "" model.notes |> text ]
|
||||
, Html.map AddressMsg (Comp.AddressForm.view model.addressModel)
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Contacts"
|
||||
]
|
||||
, Html.map ContactMsg (Comp.ContactField.view model.contactModel)
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Notes"
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ textarea [ onInput SetNotes ] [ Maybe.withDefault "" model.notes |> text ]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.PersonManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.PersonManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Person
|
||||
import Api.Model.PersonList exposing (PersonList)
|
||||
import Comp.PersonForm
|
||||
import Comp.PersonTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.PersonTable
|
||||
import Comp.PersonForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.Person
|
||||
import Api.Model.PersonList exposing (PersonList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tableModel: Comp.PersonTable.Model
|
||||
, formModel: Comp.PersonForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tableModel : Comp.PersonTable.Model
|
||||
, formModel : Comp.PersonForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tableModel = Comp.PersonTable.emptyModel
|
||||
, formModel = Comp.PersonForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.PersonTable.Msg
|
||||
| FormMsg Comp.PersonForm.Msg
|
||||
@ -52,156 +60,210 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.PersonTable.update flags m model.tableModel
|
||||
(m2, c2) = ({model | tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.PersonTable.update flags m model.tableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just org ->
|
||||
update flags (FormMsg (Comp.PersonForm.SetPerson org)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.PersonForm.update flags m model.formModel
|
||||
( m2, c2 ) =
|
||||
Comp.PersonForm.update flags m model.formModel
|
||||
in
|
||||
({model | formModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadPersons ->
|
||||
({model| loading = True}, Api.getPersons flags PersonResp)
|
||||
( { model | loading = True }, Api.getPersons flags PersonResp )
|
||||
|
||||
PersonResp (Ok orgs) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.PersonTable.SetPersons orgs.items)) m2
|
||||
update flags (TableMsg (Comp.PersonTable.SetPersons orgs.items)) m2
|
||||
|
||||
PersonResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
PersonResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.PersonTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.PersonTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewPerson ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
org = Api.Model.Person.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
org =
|
||||
Api.Model.Person.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.PersonForm.SetPerson org)) nm
|
||||
update flags (FormMsg (Comp.PersonForm.SetPerson org)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
person = Comp.PersonForm.getPerson model.formModel
|
||||
valid = Comp.PersonForm.isValid model.formModel
|
||||
in if valid then
|
||||
({model|loading = True}, Api.postPerson flags person SubmitResp)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
person =
|
||||
Comp.PersonForm.getPerson model.formModel
|
||||
|
||||
valid =
|
||||
Comp.PersonForm.isValid model.formModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postPerson flags person SubmitResp )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadPersons m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadPersons m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
person = Comp.PersonForm.getPerson model.formModel
|
||||
cmd = if confirmed then Api.deletePerson flags person.id SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
person =
|
||||
Comp.PersonForm.getPerson model.formModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deletePerson flags person.id SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else viewForm model
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
viewForm model
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewPerson]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.PersonTable.view model.tableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewPerson ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.PersonTable.view model.tableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Model -> Html Msg
|
||||
|
||||
viewForm : Model -> Html Msg
|
||||
viewForm model =
|
||||
let
|
||||
newPerson = model.formModel.org.id == ""
|
||||
newPerson =
|
||||
model.formModel.org.id == ""
|
||||
in
|
||||
Html.form [class "ui segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,if newPerson then
|
||||
h3 [class "ui dividing header"]
|
||||
[text "Create new person"
|
||||
]
|
||||
else
|
||||
h3 [class "ui dividing header"]
|
||||
[text ("Edit org: " ++ model.formModel.org.name)
|
||||
,div [class "sub header"]
|
||||
[text "Id: "
|
||||
,text model.formModel.org.id
|
||||
]
|
||||
]
|
||||
,Html.map FormMsg (Comp.PersonForm.view model.formModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newPerson then
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text "Create new person"
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit org: " ++ model.formModel.org.name)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.org.id
|
||||
]
|
||||
]
|
||||
, Html.map FormMsg (Comp.PersonForm.view model.formModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newPerson then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newPerson then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,81 +1,88 @@
|
||||
module Comp.PersonTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.PersonTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Api.Model.Address exposing (Address)
|
||||
import Api.Model.Contact exposing (Contact)
|
||||
import Util.Address
|
||||
import Util.Contact
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ equips: List Person
|
||||
, selected: Maybe Person
|
||||
{ equips : List Person
|
||||
, selected : Maybe Person
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ equips = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetPersons (List Person)
|
||||
| Select Person
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetPersons list ->
|
||||
({model | equips = list, selected = Nothing }, Cmd.none)
|
||||
( { model | equips = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select equip ->
|
||||
({model | selected = Just equip}, Cmd.none)
|
||||
( { model | selected = Just equip }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [class "collapsing"][text "Name"]
|
||||
,th [class "collapsing"][text "Concerning"]
|
||||
,th [][text "Address"]
|
||||
,th [][text "Contact"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Name" ]
|
||||
, th [ class "collapsing" ] [ text "Concerning" ]
|
||||
, th [] [ text "Address" ]
|
||||
, th [] [ text "Contact" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderPersonLine model) model.equips)
|
||||
]
|
||||
|
||||
renderPersonLine: Model -> Person -> Html Msg
|
||||
|
||||
renderPersonLine : Model -> Person -> Html Msg
|
||||
renderPersonLine model person =
|
||||
tr [classList [("active", model.selected == Just person)]
|
||||
,onClick (Select person)
|
||||
]
|
||||
[td [class "collapsing"]
|
||||
[text person.name
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[if person.concerning then
|
||||
i [class "check square outline icon"][]
|
||||
else
|
||||
i [class "minus square outline icon"][]
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just person ) ]
|
||||
, onClick (Select person)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ text person.name
|
||||
]
|
||||
,td []
|
||||
[Util.Address.toString person.address |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ if person.concerning then
|
||||
i [ class "check square outline icon" ] []
|
||||
|
||||
else
|
||||
i [ class "minus square outline icon" ] []
|
||||
]
|
||||
,td []
|
||||
[Util.Contact.toString person.contacts |> text
|
||||
, td []
|
||||
[ Util.Address.toString person.address |> text
|
||||
]
|
||||
, td []
|
||||
[ Util.Contact.toString person.contacts |> text
|
||||
]
|
||||
]
|
||||
|
@ -1,87 +1,96 @@
|
||||
module Comp.SearchMenu exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, update
|
||||
, NextState
|
||||
, view
|
||||
, getItemSearch
|
||||
)
|
||||
module Comp.SearchMenu exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, NextState
|
||||
, emptyModel
|
||||
, getItemSearch
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Api.Model.ItemSearch exposing (ItemSearch)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Comp.DatePicker
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.Flags exposing (Flags)
|
||||
import DatePicker exposing (DatePicker)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onCheck, onInput)
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
import Comp.DatePicker
|
||||
import DatePicker exposing (DatePicker)
|
||||
import Api
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Api.Model.ItemSearch exposing (ItemSearch)
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Api.Model.Equipment exposing (Equipment)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
import Http
|
||||
import Util.Maybe
|
||||
import Util.Update
|
||||
|
||||
|
||||
|
||||
-- Data Model
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tagInclModel: Comp.Dropdown.Model Tag
|
||||
, tagExclModel: Comp.Dropdown.Model Tag
|
||||
, directionModel: Comp.Dropdown.Model Direction
|
||||
, orgModel: Comp.Dropdown.Model IdName
|
||||
, corrPersonModel: Comp.Dropdown.Model IdName
|
||||
, concPersonModel: Comp.Dropdown.Model IdName
|
||||
, concEquipmentModel: Comp.Dropdown.Model Equipment
|
||||
, inboxCheckbox: Bool
|
||||
, fromDateModel: DatePicker
|
||||
, fromDate: Maybe Int
|
||||
, untilDateModel: DatePicker
|
||||
, untilDate: Maybe Int
|
||||
, fromDueDateModel: DatePicker
|
||||
, fromDueDate: Maybe Int
|
||||
, untilDueDateModel: DatePicker
|
||||
, untilDueDate: Maybe Int
|
||||
, nameModel: Maybe String
|
||||
{ tagInclModel : Comp.Dropdown.Model Tag
|
||||
, tagExclModel : Comp.Dropdown.Model Tag
|
||||
, directionModel : Comp.Dropdown.Model Direction
|
||||
, orgModel : Comp.Dropdown.Model IdName
|
||||
, corrPersonModel : Comp.Dropdown.Model IdName
|
||||
, concPersonModel : Comp.Dropdown.Model IdName
|
||||
, concEquipmentModel : Comp.Dropdown.Model Equipment
|
||||
, inboxCheckbox : Bool
|
||||
, fromDateModel : DatePicker
|
||||
, fromDate : Maybe Int
|
||||
, untilDateModel : DatePicker
|
||||
, untilDate : Maybe Int
|
||||
, fromDueDateModel : DatePicker
|
||||
, fromDueDate : Maybe Int
|
||||
, untilDueDateModel : DatePicker
|
||||
, untilDueDate : Maybe Int
|
||||
, nameModel : Maybe String
|
||||
}
|
||||
|
||||
|
||||
emptyModel: Model
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tagInclModel = makeTagModel
|
||||
, tagExclModel = makeTagModel
|
||||
, directionModel = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \entry -> {value = Data.Direction.toString entry, text = Data.Direction.toString entry}
|
||||
, options = Data.Direction.all
|
||||
, placeholder = "Choose a direction…"
|
||||
, selected = Nothing
|
||||
}
|
||||
, orgModel = Comp.Dropdown.makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 5
|
||||
, makeOption = \e -> {value = e.id, text = e.name}
|
||||
, labelColor = \_ -> ""
|
||||
, placeholder = "Choose an organization"
|
||||
}
|
||||
, corrPersonModel = Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> {value = e.id, text = e.name}
|
||||
, placeholder = "Choose a person"
|
||||
}
|
||||
, concPersonModel = Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> {value = e.id, text = e.name}
|
||||
, placeholder = "Choose a person"
|
||||
}
|
||||
, concEquipmentModel = Comp.Dropdown.makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 5
|
||||
, makeOption = \e -> {value = e.id, text = e.name}
|
||||
, labelColor = \_ -> ""
|
||||
, placeholder = "Choosa an equipment"
|
||||
}
|
||||
, directionModel =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \entry -> { value = Data.Direction.toString entry, text = Data.Direction.toString entry }
|
||||
, options = Data.Direction.all
|
||||
, placeholder = "Choose a direction…"
|
||||
, selected = Nothing
|
||||
}
|
||||
, orgModel =
|
||||
Comp.Dropdown.makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 5
|
||||
, makeOption = \e -> { value = e.id, text = e.name }
|
||||
, labelColor = \_ -> ""
|
||||
, placeholder = "Choose an organization"
|
||||
}
|
||||
, corrPersonModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name }
|
||||
, placeholder = "Choose a person"
|
||||
}
|
||||
, concPersonModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name }
|
||||
, placeholder = "Choose a person"
|
||||
}
|
||||
, concEquipmentModel =
|
||||
Comp.Dropdown.makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 5
|
||||
, makeOption = \e -> { value = e.id, text = e.name }
|
||||
, labelColor = \_ -> ""
|
||||
, placeholder = "Choosa an equipment"
|
||||
}
|
||||
, inboxCheckbox = False
|
||||
, fromDateModel = Comp.DatePicker.emptyModel
|
||||
, fromDate = Nothing
|
||||
@ -94,6 +103,7 @@ emptyModel =
|
||||
, nameModel = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Init
|
||||
| TagIncMsg (Comp.Dropdown.Msg Tag)
|
||||
@ -115,315 +125,386 @@ type Msg
|
||||
| SetName String
|
||||
|
||||
|
||||
makeTagModel: Comp.Dropdown.Model Tag
|
||||
makeTagModel : Comp.Dropdown.Model Tag
|
||||
makeTagModel =
|
||||
Comp.Dropdown.makeModel
|
||||
{ multiple = True
|
||||
, searchable = \n -> n > 4
|
||||
, makeOption = \tag -> { value = tag.id, text = tag.name }
|
||||
, labelColor = \tag -> if Util.Maybe.nonEmpty tag.category then "basic blue" else ""
|
||||
, labelColor =
|
||||
\tag ->
|
||||
if Util.Maybe.nonEmpty tag.category then
|
||||
"basic blue"
|
||||
|
||||
else
|
||||
""
|
||||
, placeholder = "Choose a tag…"
|
||||
}
|
||||
|
||||
getDirection: Model -> Maybe Direction
|
||||
|
||||
getDirection : Model -> Maybe Direction
|
||||
getDirection model =
|
||||
let
|
||||
selection = Comp.Dropdown.getSelected model.directionModel
|
||||
selection =
|
||||
Comp.Dropdown.getSelected model.directionModel
|
||||
in
|
||||
case selection of
|
||||
[d] -> Just d
|
||||
_ -> Nothing
|
||||
case selection of
|
||||
[ d ] ->
|
||||
Just d
|
||||
|
||||
getItemSearch: Model -> ItemSearch
|
||||
_ ->
|
||||
Nothing
|
||||
|
||||
|
||||
getItemSearch : Model -> ItemSearch
|
||||
getItemSearch model =
|
||||
let e = Api.Model.ItemSearch.empty in
|
||||
{ e | tagsInclude = Comp.Dropdown.getSelected model.tagInclModel |> List.map .id
|
||||
, tagsExclude = Comp.Dropdown.getSelected model.tagExclModel |> List.map .id
|
||||
, corrPerson = Comp.Dropdown.getSelected model.corrPersonModel |> List.map .id |> List.head
|
||||
, corrOrg = Comp.Dropdown.getSelected model.orgModel |> List.map .id |> List.head
|
||||
, concPerson = Comp.Dropdown.getSelected model.concPersonModel |> List.map .id |> List.head
|
||||
, concEquip = Comp.Dropdown.getSelected model.concEquipmentModel |> List.map .id |> List.head
|
||||
, direction = Comp.Dropdown.getSelected model.directionModel |> List.head |> Maybe.map Data.Direction.toString
|
||||
, inbox = model.inboxCheckbox
|
||||
, dateFrom = model.fromDate
|
||||
, dateUntil = model.untilDate
|
||||
, dueDateFrom = model.fromDueDate
|
||||
, dueDateUntil = model.untilDueDate
|
||||
, name = model.nameModel
|
||||
let
|
||||
e =
|
||||
Api.Model.ItemSearch.empty
|
||||
in
|
||||
{ e
|
||||
| tagsInclude = Comp.Dropdown.getSelected model.tagInclModel |> List.map .id
|
||||
, tagsExclude = Comp.Dropdown.getSelected model.tagExclModel |> List.map .id
|
||||
, corrPerson = Comp.Dropdown.getSelected model.corrPersonModel |> List.map .id |> List.head
|
||||
, corrOrg = Comp.Dropdown.getSelected model.orgModel |> List.map .id |> List.head
|
||||
, concPerson = Comp.Dropdown.getSelected model.concPersonModel |> List.map .id |> List.head
|
||||
, concEquip = Comp.Dropdown.getSelected model.concEquipmentModel |> List.map .id |> List.head
|
||||
, direction = Comp.Dropdown.getSelected model.directionModel |> List.head |> Maybe.map Data.Direction.toString
|
||||
, inbox = model.inboxCheckbox
|
||||
, dateFrom = model.fromDate
|
||||
, dateUntil = model.untilDate
|
||||
, dueDateFrom = model.fromDueDate
|
||||
, dueDateUntil = model.untilDueDate
|
||||
, name = model.nameModel
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- Update
|
||||
|
||||
type alias NextState
|
||||
= { modelCmd: (Model, Cmd Msg)
|
||||
, stateChange: Bool
|
||||
}
|
||||
|
||||
noChange: (Model, Cmd Msg) -> NextState
|
||||
type alias NextState =
|
||||
{ modelCmd : ( Model, Cmd Msg )
|
||||
, stateChange : Bool
|
||||
}
|
||||
|
||||
|
||||
noChange : ( Model, Cmd Msg ) -> NextState
|
||||
noChange p =
|
||||
NextState p False
|
||||
|
||||
update: Flags -> Msg -> Model -> NextState
|
||||
|
||||
update : Flags -> Msg -> Model -> NextState
|
||||
update flags msg model =
|
||||
case msg of
|
||||
Init ->
|
||||
let
|
||||
(dp, dpc) = Comp.DatePicker.init
|
||||
( dp, dpc ) =
|
||||
Comp.DatePicker.init
|
||||
in
|
||||
noChange ({model|untilDateModel = dp, fromDateModel = dp, untilDueDateModel = dp, fromDueDateModel = dp}
|
||||
, Cmd.batch
|
||||
[Api.getTags flags GetTagsResp
|
||||
,Api.getOrgLight flags GetOrgResp
|
||||
,Api.getEquipments flags GetEquipResp
|
||||
,Api.getPersonsLight flags GetPersonResp
|
||||
,Cmd.map UntilDateMsg dpc
|
||||
,Cmd.map FromDateMsg dpc
|
||||
,Cmd.map UntilDueDateMsg dpc
|
||||
,Cmd.map FromDueDateMsg dpc
|
||||
]
|
||||
)
|
||||
noChange
|
||||
( { model | untilDateModel = dp, fromDateModel = dp, untilDueDateModel = dp, fromDueDateModel = dp }
|
||||
, Cmd.batch
|
||||
[ Api.getTags flags GetTagsResp
|
||||
, Api.getOrgLight flags GetOrgResp
|
||||
, Api.getEquipments flags GetEquipResp
|
||||
, Api.getPersonsLight flags GetPersonResp
|
||||
, Cmd.map UntilDateMsg dpc
|
||||
, Cmd.map FromDateMsg dpc
|
||||
, Cmd.map UntilDueDateMsg dpc
|
||||
, Cmd.map FromDueDateMsg dpc
|
||||
]
|
||||
)
|
||||
|
||||
GetTagsResp (Ok tags) ->
|
||||
let
|
||||
tagList = Comp.Dropdown.SetOptions tags.items
|
||||
tagList =
|
||||
Comp.Dropdown.SetOptions tags.items
|
||||
in
|
||||
noChange <|
|
||||
Util.Update.andThen1
|
||||
[ update flags (TagIncMsg tagList) >> .modelCmd
|
||||
, update flags (TagExcMsg tagList) >> .modelCmd
|
||||
]
|
||||
model
|
||||
noChange <|
|
||||
Util.Update.andThen1
|
||||
[ update flags (TagIncMsg tagList) >> .modelCmd
|
||||
, update flags (TagExcMsg tagList) >> .modelCmd
|
||||
]
|
||||
model
|
||||
|
||||
GetTagsResp (Err err) ->
|
||||
noChange (model, Cmd.none)
|
||||
GetTagsResp (Err _) ->
|
||||
noChange ( model, Cmd.none )
|
||||
|
||||
GetEquipResp (Ok equips) ->
|
||||
let
|
||||
opts = Comp.Dropdown.SetOptions equips.items
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions equips.items
|
||||
in
|
||||
update flags (ConcEquipmentMsg opts) model
|
||||
update flags (ConcEquipmentMsg opts) model
|
||||
|
||||
GetEquipResp (Err err) ->
|
||||
noChange (model, Cmd.none)
|
||||
GetEquipResp (Err _) ->
|
||||
noChange ( model, Cmd.none )
|
||||
|
||||
GetOrgResp (Ok orgs) ->
|
||||
let
|
||||
opts = Comp.Dropdown.SetOptions orgs.items
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions orgs.items
|
||||
in
|
||||
update flags (OrgMsg opts) model
|
||||
update flags (OrgMsg opts) model
|
||||
|
||||
GetOrgResp (Err err) ->
|
||||
noChange (model, Cmd.none)
|
||||
GetOrgResp (Err _) ->
|
||||
noChange ( model, Cmd.none )
|
||||
|
||||
GetPersonResp (Ok ps) ->
|
||||
let
|
||||
opts = Comp.Dropdown.SetOptions ps.items
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions ps.items
|
||||
in
|
||||
noChange <|
|
||||
Util.Update.andThen1
|
||||
[ update flags (CorrPersonMsg opts) >> .modelCmd
|
||||
, update flags (ConcPersonMsg opts) >> .modelCmd
|
||||
]
|
||||
model
|
||||
noChange <|
|
||||
Util.Update.andThen1
|
||||
[ update flags (CorrPersonMsg opts) >> .modelCmd
|
||||
, update flags (ConcPersonMsg opts) >> .modelCmd
|
||||
]
|
||||
model
|
||||
|
||||
GetPersonResp (Err err) ->
|
||||
noChange (model, Cmd.none)
|
||||
GetPersonResp (Err _) ->
|
||||
noChange ( model, Cmd.none )
|
||||
|
||||
TagIncMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.tagInclModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.tagInclModel
|
||||
in
|
||||
NextState ({model|tagInclModel = m2}, Cmd.map TagIncMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | tagInclModel = m2 }, Cmd.map TagIncMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
TagExcMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.tagExclModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.tagExclModel
|
||||
in
|
||||
NextState ({model|tagExclModel = m2}, Cmd.map TagExcMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | tagExclModel = m2 }, Cmd.map TagExcMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
DirectionMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.directionModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.directionModel
|
||||
in
|
||||
NextState ({model|directionModel = m2}, Cmd.map DirectionMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | directionModel = m2 }, Cmd.map DirectionMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
OrgMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.orgModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.orgModel
|
||||
in
|
||||
NextState ({model|orgModel = m2}, Cmd.map OrgMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | orgModel = m2 }, Cmd.map OrgMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
CorrPersonMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.corrPersonModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.corrPersonModel
|
||||
in
|
||||
NextState ({model|corrPersonModel = m2}, Cmd.map CorrPersonMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | corrPersonModel = m2 }, Cmd.map CorrPersonMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
ConcPersonMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.concPersonModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.concPersonModel
|
||||
in
|
||||
NextState ({model|concPersonModel = m2}, Cmd.map ConcPersonMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | concPersonModel = m2 }, Cmd.map ConcPersonMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
ConcEquipmentMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.concEquipmentModel
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.concEquipmentModel
|
||||
in
|
||||
NextState ({model|concEquipmentModel = m2}, Cmd.map ConcEquipmentMsg c2) (isDropdownChangeMsg m)
|
||||
NextState ( { model | concEquipmentModel = m2 }, Cmd.map ConcEquipmentMsg c2 ) (isDropdownChangeMsg m)
|
||||
|
||||
ToggleInbox ->
|
||||
let
|
||||
current = model.inboxCheckbox
|
||||
current =
|
||||
model.inboxCheckbox
|
||||
in
|
||||
NextState ({model | inboxCheckbox = not current }, Cmd.none) True
|
||||
NextState ( { model | inboxCheckbox = not current }, Cmd.none ) True
|
||||
|
||||
FromDateMsg m ->
|
||||
let
|
||||
(dp, event) = Comp.DatePicker.updateDefault m model.fromDateModel
|
||||
nextDate = case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.startOfDay date)
|
||||
_ ->
|
||||
Nothing
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.fromDateModel
|
||||
|
||||
nextDate =
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.startOfDay date)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
in
|
||||
NextState ({model|fromDateModel = dp, fromDate = nextDate}, Cmd.none) (model.fromDate /= nextDate)
|
||||
NextState ( { model | fromDateModel = dp, fromDate = nextDate }, Cmd.none ) (model.fromDate /= nextDate)
|
||||
|
||||
UntilDateMsg m ->
|
||||
let
|
||||
(dp, event) = Comp.DatePicker.updateDefault m model.untilDateModel
|
||||
nextDate = case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.endOfDay date)
|
||||
_ ->
|
||||
Nothing
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.untilDateModel
|
||||
|
||||
nextDate =
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.endOfDay date)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
in
|
||||
NextState ({model|untilDateModel = dp, untilDate = nextDate}, Cmd.none) (model.untilDate /= nextDate)
|
||||
NextState ( { model | untilDateModel = dp, untilDate = nextDate }, Cmd.none ) (model.untilDate /= nextDate)
|
||||
|
||||
FromDueDateMsg m ->
|
||||
let
|
||||
(dp, event) = Comp.DatePicker.updateDefault m model.fromDueDateModel
|
||||
nextDate = case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.startOfDay date)
|
||||
_ ->
|
||||
Nothing
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.fromDueDateModel
|
||||
|
||||
nextDate =
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.startOfDay date)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
in
|
||||
NextState ({model|fromDueDateModel = dp, fromDueDate = nextDate}, Cmd.none) (model.fromDueDate /= nextDate)
|
||||
NextState ( { model | fromDueDateModel = dp, fromDueDate = nextDate }, Cmd.none ) (model.fromDueDate /= nextDate)
|
||||
|
||||
UntilDueDateMsg m ->
|
||||
let
|
||||
(dp, event) = Comp.DatePicker.updateDefault m model.untilDueDateModel
|
||||
nextDate = case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.endOfDay date)
|
||||
_ ->
|
||||
Nothing
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.untilDueDateModel
|
||||
|
||||
nextDate =
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
Just (Comp.DatePicker.endOfDay date)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
in
|
||||
NextState ({model|untilDueDateModel = dp, untilDueDate = nextDate}, Cmd.none) (model.untilDueDate /= nextDate)
|
||||
NextState ( { model | untilDueDateModel = dp, untilDueDate = nextDate }, Cmd.none ) (model.untilDueDate /= nextDate)
|
||||
|
||||
SetName str ->
|
||||
let
|
||||
next = if str == "" then Nothing else Just str
|
||||
next =
|
||||
if str == "" then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just str
|
||||
in
|
||||
NextState ({model|nameModel = next}, Cmd.none) (model.nameModel /= next)
|
||||
NextState ( { model | nameModel = next }, Cmd.none ) (model.nameModel /= next)
|
||||
|
||||
|
||||
|
||||
-- View
|
||||
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [class "inline field"]
|
||||
[div [class "ui checkbox"]
|
||||
[input [type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleInbox)
|
||||
, checked model.inboxCheckbox][]
|
||||
,label [][text "Only New"
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Name"]
|
||||
,input [type_ "text"
|
||||
,onInput SetName
|
||||
,model.nameModel |> Maybe.withDefault "" |> value
|
||||
][]
|
||||
,span [class "small-info"]
|
||||
[text "May contain wildcard "
|
||||
,code [][text "*"]
|
||||
,text " at beginning or end"
|
||||
]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Direction"]
|
||||
,Html.map DirectionMsg (Comp.Dropdown.view model.directionModel)
|
||||
]
|
||||
,h3 [class "ui header"]
|
||||
[text "Tags"
|
||||
div [ class "ui form" ]
|
||||
[ div [ class "inline field" ]
|
||||
[ div [ class "ui checkbox" ]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleInbox)
|
||||
, checked model.inboxCheckbox
|
||||
]
|
||||
[]
|
||||
, label []
|
||||
[ text "Only New"
|
||||
]
|
||||
]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Include (and)"]
|
||||
,Html.map TagIncMsg (Comp.Dropdown.view model.tagInclModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Exclude (or)"]
|
||||
,Html.map TagExcMsg (Comp.Dropdown.view model.tagExclModel)
|
||||
]
|
||||
,h3 [class "ui header"]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Name" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, model.nameModel |> Maybe.withDefault "" |> value
|
||||
]
|
||||
[]
|
||||
, span [ class "small-info" ]
|
||||
[ text "May contain wildcard "
|
||||
, code [] [ text "*" ]
|
||||
, text " at beginning or end"
|
||||
]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Direction" ]
|
||||
, Html.map DirectionMsg (Comp.Dropdown.view model.directionModel)
|
||||
]
|
||||
, h3 [ class "ui header" ]
|
||||
[ text "Tags"
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Include (and)" ]
|
||||
, Html.map TagIncMsg (Comp.Dropdown.view model.tagInclModel)
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Exclude (or)" ]
|
||||
, Html.map TagExcMsg (Comp.Dropdown.view model.tagExclModel)
|
||||
]
|
||||
, h3 [ class "ui header" ]
|
||||
[ case getDirection model of
|
||||
Just Data.Direction.Incoming -> text "Sender"
|
||||
Just Data.Direction.Outgoing -> text "Recipient"
|
||||
Nothing -> text "Correspondent"
|
||||
Just Data.Direction.Incoming ->
|
||||
text "Sender"
|
||||
|
||||
Just Data.Direction.Outgoing ->
|
||||
text "Recipient"
|
||||
|
||||
Nothing ->
|
||||
text "Correspondent"
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Organization"]
|
||||
,Html.map OrgMsg (Comp.Dropdown.view model.orgModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Person"]
|
||||
,Html.map CorrPersonMsg (Comp.Dropdown.view model.corrPersonModel)
|
||||
]
|
||||
,h3 [class "ui header"]
|
||||
[text "Concerned"
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Organization" ]
|
||||
, Html.map OrgMsg (Comp.Dropdown.view model.orgModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Person"]
|
||||
,Html.map ConcPersonMsg (Comp.Dropdown.view model.concPersonModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Equipment"]
|
||||
,Html.map ConcEquipmentMsg (Comp.Dropdown.view model.concEquipmentModel)
|
||||
]
|
||||
,h3 [class "ui header"]
|
||||
[text "Date"
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Person" ]
|
||||
, Html.map CorrPersonMsg (Comp.Dropdown.view model.corrPersonModel)
|
||||
]
|
||||
,div [class "fields"]
|
||||
[div [class "field"]
|
||||
[label [][text "From"
|
||||
]
|
||||
,Html.map FromDateMsg (Comp.DatePicker.viewTimeDefault model.fromDate model.fromDateModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "To"
|
||||
]
|
||||
,Html.map UntilDateMsg (Comp.DatePicker.viewTimeDefault model.untilDate model.untilDateModel)
|
||||
]
|
||||
]
|
||||
,h3 [class "ui header"]
|
||||
[text "Due Date"
|
||||
, h3 [ class "ui header" ]
|
||||
[ text "Concerned"
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Person" ]
|
||||
, Html.map ConcPersonMsg (Comp.Dropdown.view model.concPersonModel)
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Equipment" ]
|
||||
, Html.map ConcEquipmentMsg (Comp.Dropdown.view model.concEquipmentModel)
|
||||
]
|
||||
, h3 [ class "ui header" ]
|
||||
[ text "Date"
|
||||
]
|
||||
, div [ class "fields" ]
|
||||
[ div [ class "field" ]
|
||||
[ label []
|
||||
[ text "From"
|
||||
]
|
||||
, Html.map FromDateMsg (Comp.DatePicker.viewTimeDefault model.fromDate model.fromDateModel)
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label []
|
||||
[ text "To"
|
||||
]
|
||||
, Html.map UntilDateMsg (Comp.DatePicker.viewTimeDefault model.untilDate model.untilDateModel)
|
||||
]
|
||||
]
|
||||
, h3 [ class "ui header" ]
|
||||
[ text "Due Date"
|
||||
]
|
||||
, div [ class "fields" ]
|
||||
[ div [ class "field" ]
|
||||
[ label []
|
||||
[ text "Due From"
|
||||
]
|
||||
, Html.map FromDueDateMsg (Comp.DatePicker.viewTimeDefault model.fromDueDate model.fromDueDateModel)
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label []
|
||||
[ text "Due To"
|
||||
]
|
||||
, Html.map UntilDueDateMsg (Comp.DatePicker.viewTimeDefault model.untilDueDate model.untilDueDateModel)
|
||||
]
|
||||
]
|
||||
,div [class "fields"]
|
||||
[div [class "field"]
|
||||
[label [][text "Due From"
|
||||
]
|
||||
,Html.map FromDueDateMsg (Comp.DatePicker.viewTimeDefault model.fromDueDate model.fromDueDateModel)
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Due To"
|
||||
]
|
||||
,Html.map UntilDueDateMsg (Comp.DatePicker.viewTimeDefault model.untilDueDate model.untilDueDateModel)
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -1,62 +1,88 @@
|
||||
module Comp.Settings exposing (..)
|
||||
module Comp.Settings exposing
|
||||
( Model
|
||||
, Msg
|
||||
, getSettings
|
||||
, init
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.CollectiveSettings exposing (CollectiveSettings)
|
||||
import Comp.Dropdown
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Language exposing (Language)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Data.Language exposing (Language)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.Dropdown
|
||||
import Api.Model.CollectiveSettings exposing (CollectiveSettings)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ langModel: Comp.Dropdown.Model Language
|
||||
, initSettings: CollectiveSettings
|
||||
{ langModel : Comp.Dropdown.Model Language
|
||||
, initSettings : CollectiveSettings
|
||||
}
|
||||
|
||||
init: CollectiveSettings -> Model
|
||||
|
||||
init : CollectiveSettings -> Model
|
||||
init settings =
|
||||
let
|
||||
lang = Data.Language.fromString settings.language |> Maybe.withDefault Data.Language.German
|
||||
lang =
|
||||
Data.Language.fromString settings.language
|
||||
|> Maybe.withDefault Data.Language.German
|
||||
in
|
||||
{ langModel = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \l -> { value = Data.Language.toIso3 l, text = Data.Language.toName l }
|
||||
, placeholder = ""
|
||||
, options = Data.Language.all
|
||||
, selected = Just lang
|
||||
}
|
||||
, initSettings = settings
|
||||
}
|
||||
{ langModel =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption =
|
||||
\l ->
|
||||
{ value = Data.Language.toIso3 l
|
||||
, text = Data.Language.toName l
|
||||
}
|
||||
, placeholder = ""
|
||||
, options = Data.Language.all
|
||||
, selected = Just lang
|
||||
}
|
||||
, initSettings = settings
|
||||
}
|
||||
|
||||
getSettings: Model -> CollectiveSettings
|
||||
|
||||
getSettings : Model -> CollectiveSettings
|
||||
getSettings model =
|
||||
CollectiveSettings
|
||||
(Comp.Dropdown.getSelected model.langModel
|
||||
|> List.head
|
||||
|> Maybe.map Data.Language.toIso3
|
||||
|> Maybe.withDefault model.initSettings.language
|
||||
|> List.head
|
||||
|> Maybe.map Data.Language.toIso3
|
||||
|> Maybe.withDefault model.initSettings.language
|
||||
)
|
||||
|
||||
|
||||
type Msg
|
||||
= LangDropdownMsg (Comp.Dropdown.Msg Language)
|
||||
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg, Maybe CollectiveSettings)
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe CollectiveSettings )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
LangDropdownMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.langModel
|
||||
nextModel = {model|langModel = m2}
|
||||
nextSettings = if Comp.Dropdown.isDropdownChangeMsg m then Just (getSettings nextModel)
|
||||
else Nothing
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.langModel
|
||||
|
||||
nextModel =
|
||||
{ model | langModel = m2 }
|
||||
|
||||
nextSettings =
|
||||
if Comp.Dropdown.isDropdownChangeMsg m then
|
||||
Just (getSettings nextModel)
|
||||
|
||||
else
|
||||
Nothing
|
||||
in
|
||||
(nextModel, Cmd.map LangDropdownMsg c2, nextSettings)
|
||||
( nextModel, Cmd.map LangDropdownMsg c2, nextSettings )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [class "field"]
|
||||
[label [][text "Document Language"]
|
||||
,Html.map LangDropdownMsg (Comp.Dropdown.view model.langModel)
|
||||
]
|
||||
div [ class "ui form" ]
|
||||
[ div [ class "field" ]
|
||||
[ label [] [ text "Document Language" ]
|
||||
, Html.map LangDropdownMsg (Comp.Dropdown.view model.langModel)
|
||||
]
|
||||
]
|
||||
|
@ -1,60 +1,68 @@
|
||||
module Comp.SourceForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, getSource)
|
||||
module Comp.SourceForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getSource
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Source exposing (Source)
|
||||
import Comp.Dropdown
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Priority exposing (Priority)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onCheck)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.SourceState exposing (SourceState)
|
||||
import Data.Priority exposing (Priority)
|
||||
import Comp.Dropdown
|
||||
import Api.Model.Source exposing (Source)
|
||||
import Util.Maybe
|
||||
import Html.Events exposing (onCheck, onInput)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ source: Source
|
||||
, abbrev: String
|
||||
, description: Maybe String
|
||||
, priority: Comp.Dropdown.Model Priority
|
||||
, enabled: Bool
|
||||
{ source : Source
|
||||
, abbrev : String
|
||||
, description : Maybe String
|
||||
, priority : Comp.Dropdown.Model Priority
|
||||
, enabled : Bool
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ source = Api.Model.Source.empty
|
||||
, abbrev = ""
|
||||
, description = Nothing
|
||||
, priority = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \p -> { text = Data.Priority.toName p, value = Data.Priority.toName p }
|
||||
, placeholder = ""
|
||||
, options = Data.Priority.all
|
||||
, selected = Nothing
|
||||
}
|
||||
, priority =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \p -> { text = Data.Priority.toName p, value = Data.Priority.toName p }
|
||||
, placeholder = ""
|
||||
, options = Data.Priority.all
|
||||
, selected = Nothing
|
||||
}
|
||||
, enabled = False
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.abbrev /= ""
|
||||
|
||||
getSource: Model -> Source
|
||||
|
||||
getSource : Model -> Source
|
||||
getSource model =
|
||||
let
|
||||
s = model.source
|
||||
s =
|
||||
model.source
|
||||
in
|
||||
{s | abbrev = model.abbrev
|
||||
, description = model.description
|
||||
, enabled = model.enabled
|
||||
, priority = Comp.Dropdown.getSelected model.priority
|
||||
|> List.head
|
||||
|> Maybe.map Data.Priority.toName
|
||||
|> Maybe.withDefault s.priority
|
||||
}
|
||||
{ s
|
||||
| abbrev = model.abbrev
|
||||
, description = model.description
|
||||
, enabled = model.enabled
|
||||
, priority =
|
||||
Comp.Dropdown.getSelected model.priority
|
||||
|> List.head
|
||||
|> Maybe.map Data.Priority.toName
|
||||
|> Maybe.withDefault s.priority
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
@ -64,105 +72,138 @@ type Msg
|
||||
| ToggleEnabled
|
||||
| PrioDropdownMsg (Comp.Dropdown.Msg Priority)
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetSource t ->
|
||||
let
|
||||
post = model.source
|
||||
np = {post | id = t.id
|
||||
, abbrev = t.abbrev
|
||||
, description = t.description
|
||||
, priority = t.priority
|
||||
, enabled = t.enabled
|
||||
}
|
||||
post =
|
||||
model.source
|
||||
|
||||
np =
|
||||
{ post
|
||||
| id = t.id
|
||||
, abbrev = t.abbrev
|
||||
, description = t.description
|
||||
, priority = t.priority
|
||||
, enabled = t.enabled
|
||||
}
|
||||
in
|
||||
({model | source = np
|
||||
, abbrev = t.abbrev
|
||||
, description = t.description
|
||||
, priority = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \p -> { text = Data.Priority.toName p, value = Data.Priority.toName p }
|
||||
, placeholder = ""
|
||||
, options = Data.Priority.all
|
||||
, selected = Data.Priority.fromString t.priority
|
||||
}
|
||||
, enabled = t.enabled }, Cmd.none)
|
||||
( { model
|
||||
| source = np
|
||||
, abbrev = t.abbrev
|
||||
, description = t.description
|
||||
, priority =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \p -> { text = Data.Priority.toName p, value = Data.Priority.toName p }
|
||||
, placeholder = ""
|
||||
, options = Data.Priority.all
|
||||
, selected = Data.Priority.fromString t.priority
|
||||
}
|
||||
, enabled = t.enabled
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ToggleEnabled ->
|
||||
let
|
||||
_ = Debug.log "got" model.enabled
|
||||
in
|
||||
({model | enabled = not model.enabled}, Cmd.none)
|
||||
( { model | enabled = not model.enabled }, Cmd.none )
|
||||
|
||||
SetAbbrev n ->
|
||||
({model | abbrev = n}, Cmd.none)
|
||||
( { model | abbrev = n }, Cmd.none )
|
||||
|
||||
SetDescr d ->
|
||||
({model | description = if d /= "" then Just d else Nothing }, Cmd.none)
|
||||
( { model
|
||||
| description =
|
||||
if d /= "" then
|
||||
Just d
|
||||
|
||||
else
|
||||
Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
PrioDropdownMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.Dropdown.update m model.priority
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.priority
|
||||
in
|
||||
({model | priority = m2 }, Cmd.map PrioDropdownMsg c2)
|
||||
( { model | priority = m2 }, Cmd.map PrioDropdownMsg c2 )
|
||||
|
||||
view: Flags -> Model -> Html Msg
|
||||
|
||||
view : Flags -> Model -> Html Msg
|
||||
view flags model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", not (isValid model))
|
||||
]
|
||||
]
|
||||
[label [][text "Abbrev*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetAbbrev
|
||||
,placeholder "Abbrev"
|
||||
,value model.abbrev
|
||||
][]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Description"]
|
||||
,textarea [onInput SetDescr][model.description |> Maybe.withDefault "" |> text]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", not (isValid model) )
|
||||
]
|
||||
]
|
||||
,div [class "inline field"]
|
||||
[div [class "ui checkbox"]
|
||||
[input [type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleEnabled)
|
||||
, checked model.enabled][]
|
||||
,label [][text "Enabled"]
|
||||
]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Priority"]
|
||||
,Html.map PrioDropdownMsg (Comp.Dropdown.view model.priority)
|
||||
[ label [] [ text "Abbrev*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetAbbrev
|
||||
, placeholder "Abbrev"
|
||||
, value model.abbrev
|
||||
]
|
||||
[]
|
||||
]
|
||||
,urlInfoMessage flags model
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Description" ]
|
||||
, textarea [ onInput SetDescr ] [ model.description |> Maybe.withDefault "" |> text ]
|
||||
]
|
||||
, div [ class "inline field" ]
|
||||
[ div [ class "ui checkbox" ]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, onCheck (\_ -> ToggleEnabled)
|
||||
, checked model.enabled
|
||||
]
|
||||
[]
|
||||
, label [] [ text "Enabled" ]
|
||||
]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Priority" ]
|
||||
, Html.map PrioDropdownMsg (Comp.Dropdown.view model.priority)
|
||||
]
|
||||
, urlInfoMessage flags model
|
||||
]
|
||||
|
||||
urlInfoMessage: Flags -> Model -> Html Msg
|
||||
|
||||
urlInfoMessage : Flags -> Model -> Html Msg
|
||||
urlInfoMessage flags model =
|
||||
div [classList [("ui info icon message", True)
|
||||
,("hidden", not model.enabled || model.source.id == "")
|
||||
]]
|
||||
[i [class "info icon"][]
|
||||
,div [class "content"]
|
||||
[div [class "header"]
|
||||
[text "Public Uploads"
|
||||
]
|
||||
,p [][text "This source defines URLs that can be used by anyone to send files to "
|
||||
,text "you. There is a web page that you can share or tha API url can be used "
|
||||
,text "with other clients."
|
||||
]
|
||||
,dl [class "ui list"]
|
||||
[dt [][text "Public Upload Page"]
|
||||
,dd [][let
|
||||
url = flags.config.baseUrl ++ "/app/index.html#/upload/" ++ model.source.id
|
||||
in
|
||||
a [href url, target "_blank"][code [][text url]]
|
||||
]
|
||||
,dt [][text "Public API Upload URL"]
|
||||
,dd [][code [][text (flags.config.baseUrl ++ "/api/v1/open/upload/item/" ++ model.source.id)]
|
||||
]
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui info icon message", True )
|
||||
, ( "hidden", not model.enabled || model.source.id == "" )
|
||||
]
|
||||
]
|
||||
[ i [ class "info icon" ] []
|
||||
, div [ class "content" ]
|
||||
[ div [ class "header" ]
|
||||
[ text "Public Uploads"
|
||||
]
|
||||
, p []
|
||||
[ text "This source defines URLs that can be used by anyone to send files to "
|
||||
, text "you. There is a web page that you can share or tha API url can be used "
|
||||
, text "with other clients."
|
||||
]
|
||||
, dl [ class "ui list" ]
|
||||
[ dt [] [ text "Public Upload Page" ]
|
||||
, dd []
|
||||
[ let
|
||||
url =
|
||||
flags.config.baseUrl ++ "/app/index.html#/upload/" ++ model.source.id
|
||||
in
|
||||
a [ href url, target "_blank" ] [ code [] [ text url ] ]
|
||||
]
|
||||
, dt [] [ text "Public API Upload URL" ]
|
||||
, dd []
|
||||
[ code [] [ text (flags.config.baseUrl ++ "/api/v1/open/upload/item/" ++ model.source.id) ]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.SourceManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.SourceManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Source
|
||||
import Api.Model.SourceList exposing (SourceList)
|
||||
import Comp.SourceForm
|
||||
import Comp.SourceTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.SourceTable
|
||||
import Comp.SourceForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.Source
|
||||
import Api.Model.SourceList exposing (SourceList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tableModel: Comp.SourceTable.Model
|
||||
, formModel: Comp.SourceForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tableModel : Comp.SourceTable.Model
|
||||
, formModel : Comp.SourceForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tableModel = Comp.SourceTable.emptyModel
|
||||
, formModel = Comp.SourceForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.SourceTable.Msg
|
||||
| FormMsg Comp.SourceForm.Msg
|
||||
@ -52,156 +60,211 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.SourceTable.update flags m model.tableModel
|
||||
(m2, c2) = ({model | tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.SourceTable.update flags m model.tableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just source ->
|
||||
update flags (FormMsg (Comp.SourceForm.SetSource source)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.SourceForm.update flags m model.formModel
|
||||
( m2, c2 ) =
|
||||
Comp.SourceForm.update flags m model.formModel
|
||||
in
|
||||
({model | formModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadSources ->
|
||||
({model| loading = True}, Api.getSources flags SourceResp)
|
||||
( { model | loading = True }, Api.getSources flags SourceResp )
|
||||
|
||||
SourceResp (Ok sources) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.SourceTable.SetSources sources.items)) m2
|
||||
update flags (TableMsg (Comp.SourceTable.SetSources sources.items)) m2
|
||||
|
||||
SourceResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
SourceResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.SourceTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.SourceTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewSource ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
source = Api.Model.Source.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
source =
|
||||
Api.Model.Source.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.SourceForm.SetSource source)) nm
|
||||
update flags (FormMsg (Comp.SourceForm.SetSource source)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
source = Comp.SourceForm.getSource model.formModel
|
||||
valid = Comp.SourceForm.isValid model.formModel
|
||||
in if valid then
|
||||
({model|loading = True}, Api.postSource flags source SubmitResp)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
source =
|
||||
Comp.SourceForm.getSource model.formModel
|
||||
|
||||
valid =
|
||||
Comp.SourceForm.isValid model.formModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postSource flags source SubmitResp )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadSources m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadSources m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
src = Comp.SourceForm.getSource model.formModel
|
||||
cmd = if confirmed then Api.deleteSource flags src.id SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
src =
|
||||
Comp.SourceForm.getSource model.formModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deleteSource flags src.id SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
view: Flags -> Model -> Html Msg
|
||||
|
||||
view : Flags -> Model -> Html Msg
|
||||
view flags model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else div [](viewForm flags model)
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
div [] (viewForm flags model)
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewSource]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.SourceTable.view model.tableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewSource ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.SourceTable.view model.tableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Flags -> Model -> List (Html Msg)
|
||||
|
||||
viewForm : Flags -> Model -> List (Html Msg)
|
||||
viewForm flags model =
|
||||
let
|
||||
newSource = model.formModel.source.id == ""
|
||||
newSource =
|
||||
model.formModel.source.id == ""
|
||||
in
|
||||
[if newSource then
|
||||
h3 [class "ui top attached header"]
|
||||
[text "Create new source"
|
||||
]
|
||||
else
|
||||
h3 [class "ui top attached header"]
|
||||
[text ("Edit: " ++ model.formModel.source.abbrev)
|
||||
,div [class "sub header"]
|
||||
[text "Id: "
|
||||
,text model.formModel.source.id
|
||||
]
|
||||
]
|
||||
,Html.form [class "ui attached segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,Html.map FormMsg (Comp.SourceForm.view flags model.formModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
[ if newSource then
|
||||
h3 [ class "ui top attached header" ]
|
||||
[ text "Create new source"
|
||||
]
|
||||
|
||||
else
|
||||
h3 [ class "ui top attached header" ]
|
||||
[ text ("Edit: " ++ model.formModel.source.abbrev)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.source.id
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
]
|
||||
, Html.form [ class "ui attached segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, Html.map FormMsg (Comp.SourceForm.view flags model.formModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newSource then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newSource then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -1,85 +1,94 @@
|
||||
module Comp.SourceTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.SourceTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Source exposing (Source)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Priority
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Priority exposing (Priority)
|
||||
import Api.Model.Source exposing (Source)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ sources: List Source
|
||||
, selected: Maybe Source
|
||||
{ sources : List Source
|
||||
, selected : Maybe Source
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ sources = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetSources (List Source)
|
||||
| Select Source
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetSources list ->
|
||||
({model | sources = list, selected = Nothing }, Cmd.none)
|
||||
( { model | sources = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select source ->
|
||||
({model | selected = Just source}, Cmd.none)
|
||||
( { model | selected = Just source }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [class "collapsing"][text "Abbrev"]
|
||||
,th [class "collapsing"][text "Enabled"]
|
||||
,th [class "collapsing"][text "Counter"]
|
||||
,th [class "collapsing"][text "Priority"]
|
||||
,th [][text "Id"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Abbrev" ]
|
||||
, th [ class "collapsing" ] [ text "Enabled" ]
|
||||
, th [ class "collapsing" ] [ text "Counter" ]
|
||||
, th [ class "collapsing" ] [ text "Priority" ]
|
||||
, th [] [ text "Id" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderSourceLine model) model.sources)
|
||||
]
|
||||
|
||||
renderSourceLine: Model -> Source -> Html Msg
|
||||
|
||||
renderSourceLine : Model -> Source -> Html Msg
|
||||
renderSourceLine model source =
|
||||
tr [classList [("active", model.selected == Just source)]
|
||||
,onClick (Select source)
|
||||
]
|
||||
[td [class "collapsing"]
|
||||
[text source.abbrev
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[if source.enabled then
|
||||
i [class "check square outline icon"][]
|
||||
else
|
||||
i [class "minus square outline icon"][]
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just source ) ]
|
||||
, onClick (Select source)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ text source.abbrev
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[source.counter |> String.fromInt |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ if source.enabled then
|
||||
i [ class "check square outline icon" ] []
|
||||
|
||||
else
|
||||
i [ class "minus square outline icon" ] []
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[Data.Priority.fromString source.priority
|
||||
|> Maybe.map Data.Priority.toName
|
||||
|> Maybe.withDefault source.priority
|
||||
|> text
|
||||
, td [ class "collapsing" ]
|
||||
[ source.counter |> String.fromInt |> text
|
||||
]
|
||||
,td []
|
||||
[text source.id
|
||||
, td [ class "collapsing" ]
|
||||
[ Data.Priority.fromString source.priority
|
||||
|> Maybe.map Data.Priority.toName
|
||||
|> Maybe.withDefault source.priority
|
||||
|> text
|
||||
]
|
||||
, td []
|
||||
[ text source.id
|
||||
]
|
||||
]
|
||||
|
@ -1,76 +1,90 @@
|
||||
module Comp.TagForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, getTag)
|
||||
module Comp.TagForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getTag
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tag: Tag
|
||||
, name: String
|
||||
, category: Maybe String
|
||||
{ tag : Tag
|
||||
, name : String
|
||||
, category : Maybe String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tag = Api.Model.Tag.empty
|
||||
, name = ""
|
||||
, category = Nothing
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
model.name /= ""
|
||||
|
||||
getTag: Model -> Tag
|
||||
|
||||
getTag : Model -> Tag
|
||||
getTag model =
|
||||
Tag model.tag.id model.name model.category 0
|
||||
|
||||
|
||||
type Msg
|
||||
= SetName String
|
||||
| SetCategory String
|
||||
| SetTag Tag
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetTag t ->
|
||||
({model | tag = t, name = t.name, category = t.category }, Cmd.none)
|
||||
( { model | tag = t, name = t.name, category = t.category }, Cmd.none )
|
||||
|
||||
SetName n ->
|
||||
({model | name = n}, Cmd.none)
|
||||
( { model | name = n }, Cmd.none )
|
||||
|
||||
SetCategory n ->
|
||||
({model | category = Just n}, Cmd.none)
|
||||
( { model | category = Just n }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", not (isValid model))
|
||||
]
|
||||
]
|
||||
[label [][text "Name*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetName
|
||||
,placeholder "Name"
|
||||
,value model.name
|
||||
][]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "Category"]
|
||||
,input [type_ "text"
|
||||
,onInput SetCategory
|
||||
,placeholder "Category (optional)"
|
||||
,value (Maybe.withDefault "" model.category)
|
||||
][]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", not (isValid model) )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "Name*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetName
|
||||
, placeholder "Name"
|
||||
, value model.name
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Category" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetCategory
|
||||
, placeholder "Category (optional)"
|
||||
, value (Maybe.withDefault "" model.category)
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.TagManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.TagManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Tag
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Comp.TagForm
|
||||
import Comp.TagTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.TagTable
|
||||
import Comp.TagForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.Tag
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tagTableModel: Comp.TagTable.Model
|
||||
, tagFormModel: Comp.TagForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tagTableModel : Comp.TagTable.Model
|
||||
, tagFormModel : Comp.TagForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tagTableModel = Comp.TagTable.emptyModel
|
||||
, tagFormModel = Comp.TagForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.TagTable.Msg
|
||||
| FormMsg Comp.TagForm.Msg
|
||||
@ -52,155 +60,210 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.TagTable.update flags m model.tagTableModel
|
||||
(m2, c2) = ({model | tagTableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.TagTable.update flags m model.tagTableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tagTableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just tag ->
|
||||
update flags (FormMsg (Comp.TagForm.SetTag tag)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.TagForm.update flags m model.tagFormModel
|
||||
( m2, c2 ) =
|
||||
Comp.TagForm.update flags m model.tagFormModel
|
||||
in
|
||||
({model | tagFormModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | tagFormModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadTags ->
|
||||
({model| loading = True}, Api.getTags flags TagResp)
|
||||
( { model | loading = True }, Api.getTags flags TagResp )
|
||||
|
||||
TagResp (Ok tags) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.TagTable.SetTags tags.items)) m2
|
||||
update flags (TableMsg (Comp.TagTable.SetTags tags.items)) m2
|
||||
|
||||
TagResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
TagResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.TagTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.TagTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewTag ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
tag = Api.Model.Tag.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
tag =
|
||||
Api.Model.Tag.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.TagForm.SetTag tag)) nm
|
||||
update flags (FormMsg (Comp.TagForm.SetTag tag)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
tag = Comp.TagForm.getTag model.tagFormModel
|
||||
valid = Comp.TagForm.isValid model.tagFormModel
|
||||
in if valid then
|
||||
({model|loading = True}, Api.postTag flags tag SubmitResp)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
tag =
|
||||
Comp.TagForm.getTag model.tagFormModel
|
||||
|
||||
valid =
|
||||
Comp.TagForm.isValid model.tagFormModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postTag flags tag SubmitResp )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadTags m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadTags m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
tag = Comp.TagForm.getTag model.tagFormModel
|
||||
cmd = if confirmed then Api.deleteTag flags tag.id SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
tag =
|
||||
Comp.TagForm.getTag model.tagFormModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deleteTag flags tag.id SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else viewForm model
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
viewForm model
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewTag]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.TagTable.view model.tagTableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewTag ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.TagTable.view model.tagTableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Model -> Html Msg
|
||||
|
||||
viewForm : Model -> Html Msg
|
||||
viewForm model =
|
||||
let
|
||||
newTag = model.tagFormModel.tag.id == ""
|
||||
newTag =
|
||||
model.tagFormModel.tag.id == ""
|
||||
in
|
||||
Html.form [class "ui segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,if newTag then
|
||||
h3 [class "ui dividing header"]
|
||||
[text "Create new tag"
|
||||
]
|
||||
else
|
||||
h3 [class "ui dividing header"]
|
||||
[text ("Edit tag: " ++ model.tagFormModel.tag.name)
|
||||
,div [class "sub header"]
|
||||
[text "Id: "
|
||||
,text model.tagFormModel.tag.id
|
||||
]
|
||||
]
|
||||
,Html.map FormMsg (Comp.TagForm.view model.tagFormModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newTag then
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text "Create new tag"
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit tag: " ++ model.tagFormModel.tag.name)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.tagFormModel.tag.id
|
||||
]
|
||||
]
|
||||
, Html.map FormMsg (Comp.TagForm.view model.tagFormModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newTag then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newTag then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,66 +1,74 @@
|
||||
module Comp.TagTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.TagTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tags: List Tag
|
||||
, selected: Maybe Tag
|
||||
{ tags : List Tag
|
||||
, selected : Maybe Tag
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tags = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetTags (List Tag)
|
||||
| Select Tag
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetTags list ->
|
||||
({model | tags = list, selected = Nothing }, Cmd.none)
|
||||
( { model | tags = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select tag ->
|
||||
({model | selected = Just tag}, Cmd.none)
|
||||
( { model | selected = Just tag }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [][text "Name"]
|
||||
,th [][text "Category"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [] [ text "Name" ]
|
||||
, th [] [ text "Category" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderTagLine model) model.tags)
|
||||
]
|
||||
|
||||
renderTagLine: Model -> Tag -> Html Msg
|
||||
|
||||
renderTagLine : Model -> Tag -> Html Msg
|
||||
renderTagLine model tag =
|
||||
tr [classList [("active", model.selected == Just tag)]
|
||||
,onClick (Select tag)
|
||||
]
|
||||
[td []
|
||||
[text tag.name
|
||||
]
|
||||
,td []
|
||||
[Maybe.withDefault "-" tag.category |> text
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just tag ) ]
|
||||
, onClick (Select tag)
|
||||
]
|
||||
[ td []
|
||||
[ text tag.name
|
||||
]
|
||||
, td []
|
||||
[ Maybe.withDefault "-" tag.category |> text
|
||||
]
|
||||
]
|
||||
|
@ -1,68 +1,85 @@
|
||||
module Comp.UserForm exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update
|
||||
, isValid
|
||||
, isNewUser
|
||||
, getUser)
|
||||
module Comp.UserForm exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, getUser
|
||||
, isNewUser
|
||||
, isValid
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput, onCheck)
|
||||
import Api.Model.User exposing (User)
|
||||
import Comp.Dropdown
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UserState exposing (UserState)
|
||||
import Api.Model.User exposing (User)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onInput)
|
||||
import Util.Maybe
|
||||
import Comp.Dropdown
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ user: User
|
||||
, login: String
|
||||
, email: Maybe String
|
||||
, state: Comp.Dropdown.Model UserState
|
||||
, password: Maybe String
|
||||
{ user : User
|
||||
, login : String
|
||||
, email : Maybe String
|
||||
, state : Comp.Dropdown.Model UserState
|
||||
, password : Maybe String
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ user = Api.Model.User.empty
|
||||
, login = ""
|
||||
, email = Nothing
|
||||
, password = Nothing
|
||||
, state = Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \s -> { value = Data.UserState.toString s, text = Data.UserState.toString s }
|
||||
, placeholder = ""
|
||||
, options = Data.UserState.all
|
||||
, selected = List.head Data.UserState.all
|
||||
}
|
||||
, state =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption =
|
||||
\s ->
|
||||
{ value = Data.UserState.toString s
|
||||
, text = Data.UserState.toString s
|
||||
}
|
||||
, placeholder = ""
|
||||
, options = Data.UserState.all
|
||||
, selected = List.head Data.UserState.all
|
||||
}
|
||||
}
|
||||
|
||||
isValid: Model -> Bool
|
||||
|
||||
isValid : Model -> Bool
|
||||
isValid model =
|
||||
if model.user.login == "" then
|
||||
model.login /= "" && Util.Maybe.nonEmpty model.password
|
||||
|
||||
else
|
||||
True
|
||||
|
||||
isNewUser: Model -> Bool
|
||||
|
||||
isNewUser : Model -> Bool
|
||||
isNewUser model =
|
||||
model.user.login == ""
|
||||
|
||||
getUser: Model -> User
|
||||
|
||||
getUser : Model -> User
|
||||
getUser model =
|
||||
let
|
||||
s = model.user
|
||||
state = Comp.Dropdown.getSelected model.state
|
||||
s =
|
||||
model.user
|
||||
|
||||
state =
|
||||
Comp.Dropdown.getSelected model.state
|
||||
|> List.head
|
||||
|> Maybe.withDefault Data.UserState.Active
|
||||
|> Data.UserState.toString
|
||||
in
|
||||
{s | login = model.login
|
||||
, email = model.email
|
||||
, state = state
|
||||
, password = model.password
|
||||
}
|
||||
{ s
|
||||
| login = model.login
|
||||
, email = model.email
|
||||
, state = state
|
||||
, password = model.password
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
@ -72,79 +89,115 @@ type Msg
|
||||
| StateMsg (Comp.Dropdown.Msg UserState)
|
||||
| SetPassword String
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetUser t ->
|
||||
let
|
||||
state = Comp.Dropdown.makeSingleList
|
||||
state =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption = \s -> { value = Data.UserState.toString s, text = Data.UserState.toString s }
|
||||
, placeholder = ""
|
||||
, options = Data.UserState.all
|
||||
, selected = Data.UserState.fromString t.state
|
||||
|> Maybe.map (\u -> List.filter ((==) u) Data.UserState.all)
|
||||
|> Maybe.andThen List.head
|
||||
|> Util.Maybe.withDefault (List.head Data.UserState.all)
|
||||
, selected =
|
||||
Data.UserState.fromString t.state
|
||||
|> Maybe.map (\u -> List.filter ((==) u) Data.UserState.all)
|
||||
|> Maybe.andThen List.head
|
||||
|> Util.Maybe.withDefault (List.head Data.UserState.all)
|
||||
}
|
||||
in
|
||||
({model | user = t
|
||||
, login = t.login
|
||||
, email = t.email
|
||||
, password = t.password
|
||||
, state = state }, Cmd.none)
|
||||
( { model
|
||||
| user = t
|
||||
, login = t.login
|
||||
, email = t.email
|
||||
, password = t.password
|
||||
, state = state
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
StateMsg m ->
|
||||
let
|
||||
(m1, c1) = Comp.Dropdown.update m model.state
|
||||
( m1, c1 ) =
|
||||
Comp.Dropdown.update m model.state
|
||||
in
|
||||
({model | state = m1}, Cmd.map StateMsg c1)
|
||||
( { model | state = m1 }, Cmd.map StateMsg c1 )
|
||||
|
||||
SetLogin n ->
|
||||
({model | login = n}, Cmd.none)
|
||||
( { model | login = n }, Cmd.none )
|
||||
|
||||
SetEmail e ->
|
||||
({model | email = if e == "" then Nothing else Just e }, Cmd.none)
|
||||
( { model
|
||||
| email =
|
||||
if e == "" then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just e
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SetPassword p ->
|
||||
({model | password = if p == "" then Nothing else Just p}, Cmd.none)
|
||||
( { model
|
||||
| password =
|
||||
if p == "" then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just p
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [class "ui form"]
|
||||
[div [classList [("field", True)
|
||||
,("error", model.login == "")
|
||||
,("invisible", model.user.login /= "")
|
||||
]
|
||||
]
|
||||
[label [][text "Login*"]
|
||||
,input [type_ "text"
|
||||
,onInput SetLogin
|
||||
,placeholder "Login"
|
||||
,value model.login
|
||||
][]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "E-Mail"]
|
||||
,input [ onInput SetEmail
|
||||
, model.email |> Maybe.withDefault "" |> value
|
||||
, placeholder "E-Mail"
|
||||
][]
|
||||
div [ class "ui form" ]
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "error", model.login == "" )
|
||||
, ( "invisible", model.user.login /= "" )
|
||||
]
|
||||
]
|
||||
,div [class "field"]
|
||||
[label [][text "State"]
|
||||
,Html.map StateMsg (Comp.Dropdown.view model.state)
|
||||
[ label [] [ text "Login*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetLogin
|
||||
, placeholder "Login"
|
||||
, value model.login
|
||||
]
|
||||
[]
|
||||
]
|
||||
,div [classList [("field", True)
|
||||
,("invisible", model.user.login /= "")
|
||||
,("error", Util.Maybe.isEmpty model.password)
|
||||
]
|
||||
]
|
||||
[label [][text "Password*"]
|
||||
,input [type_ "text"
|
||||
, onInput SetPassword
|
||||
, placeholder "Password"
|
||||
, Maybe.withDefault "" model.password |> value
|
||||
][]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "E-Mail" ]
|
||||
, input
|
||||
[ onInput SetEmail
|
||||
, model.email |> Maybe.withDefault "" |> value
|
||||
, placeholder "E-Mail"
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "State" ]
|
||||
, Html.map StateMsg (Comp.Dropdown.view model.state)
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "field", True )
|
||||
, ( "invisible", model.user.login /= "" )
|
||||
, ( "error", Util.Maybe.isEmpty model.password )
|
||||
]
|
||||
]
|
||||
[ label [] [ text "Password*" ]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, onInput SetPassword
|
||||
, placeholder "Password"
|
||||
, Maybe.withDefault "" model.password |> value
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
@ -1,36 +1,43 @@
|
||||
module Comp.UserManage exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.UserManage exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Http
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.User
|
||||
import Api.Model.UserList exposing (UserList)
|
||||
import Comp.UserForm
|
||||
import Comp.UserTable
|
||||
import Comp.YesNoDimmer
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onSubmit)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Comp.UserTable
|
||||
import Comp.UserForm
|
||||
import Comp.YesNoDimmer
|
||||
import Api.Model.User
|
||||
import Api.Model.UserList exposing (UserList)
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Util.Maybe
|
||||
import Http
|
||||
import Util.Http
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tableModel: Comp.UserTable.Model
|
||||
, formModel: Comp.UserForm.Model
|
||||
, viewMode: ViewMode
|
||||
, formError: Maybe String
|
||||
, loading: Bool
|
||||
, deleteConfirm: Comp.YesNoDimmer.Model
|
||||
{ tableModel : Comp.UserTable.Model
|
||||
, formModel : Comp.UserForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
}
|
||||
|
||||
type ViewMode = Table | Form
|
||||
|
||||
emptyModel: Model
|
||||
type ViewMode
|
||||
= Table
|
||||
| Form
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ tableModel = Comp.UserTable.emptyModel
|
||||
, formModel = Comp.UserForm.emptyModel
|
||||
@ -40,6 +47,7 @@ emptyModel =
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= TableMsg Comp.UserTable.Msg
|
||||
| FormMsg Comp.UserForm.Msg
|
||||
@ -52,154 +60,213 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TableMsg m ->
|
||||
let
|
||||
(tm, tc) = Comp.UserTable.update flags m model.tableModel
|
||||
(m2, c2) = ({model | tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError = if Util.Maybe.nonEmpty tm.selected then Nothing else model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
(m3, c3) = case tm.selected of
|
||||
( tm, tc ) =
|
||||
Comp.UserTable.update flags m model.tableModel
|
||||
|
||||
( m2, c2 ) =
|
||||
( { model
|
||||
| tableModel = tm
|
||||
, viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
|
||||
, formError =
|
||||
if Util.Maybe.nonEmpty tm.selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
model.formError
|
||||
}
|
||||
, Cmd.map TableMsg tc
|
||||
)
|
||||
|
||||
( m3, c3 ) =
|
||||
case tm.selected of
|
||||
Just user ->
|
||||
update flags (FormMsg (Comp.UserForm.SetUser user)) m2
|
||||
|
||||
Nothing ->
|
||||
(m2, Cmd.none)
|
||||
( m2, Cmd.none )
|
||||
in
|
||||
(m3, Cmd.batch [c2, c3])
|
||||
( m3, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
FormMsg m ->
|
||||
let
|
||||
(m2, c2) = Comp.UserForm.update flags m model.formModel
|
||||
( m2, c2 ) =
|
||||
Comp.UserForm.update flags m model.formModel
|
||||
in
|
||||
({model | formModel = m2}, Cmd.map FormMsg c2)
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadUsers ->
|
||||
({model| loading = True}, Api.getUsers flags UserResp)
|
||||
( { model | loading = True }, Api.getUsers flags UserResp )
|
||||
|
||||
UserResp (Ok users) ->
|
||||
let
|
||||
m2 = {model|viewMode = Table, loading = False}
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
in
|
||||
update flags (TableMsg (Comp.UserTable.SetUsers users.items)) m2
|
||||
update flags (TableMsg (Comp.UserTable.SetUsers users.items)) m2
|
||||
|
||||
UserResp (Err err) ->
|
||||
({model|loading = False}, Cmd.none)
|
||||
UserResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
m2 = {model | viewMode = m }
|
||||
m2 =
|
||||
{ model | viewMode = m }
|
||||
in
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.UserTable.Deselect) m2
|
||||
Form ->
|
||||
(m2, Cmd.none)
|
||||
case m of
|
||||
Table ->
|
||||
update flags (TableMsg Comp.UserTable.Deselect) m2
|
||||
|
||||
Form ->
|
||||
( m2, Cmd.none )
|
||||
|
||||
InitNewUser ->
|
||||
let
|
||||
nm = {model | viewMode = Form, formError = Nothing }
|
||||
user = Api.Model.User.empty
|
||||
nm =
|
||||
{ model | viewMode = Form, formError = Nothing }
|
||||
|
||||
user =
|
||||
Api.Model.User.empty
|
||||
in
|
||||
update flags (FormMsg (Comp.UserForm.SetUser user)) nm
|
||||
update flags (FormMsg (Comp.UserForm.SetUser user)) nm
|
||||
|
||||
Submit ->
|
||||
let
|
||||
user = Comp.UserForm.getUser model.formModel
|
||||
valid = Comp.UserForm.isValid model.formModel
|
||||
cmd = if Comp.UserForm.isNewUser model.formModel
|
||||
then Api.postNewUser flags user SubmitResp
|
||||
else Api.putUser flags user SubmitResp
|
||||
in if valid then
|
||||
({model|loading = True}, cmd)
|
||||
else
|
||||
({model|formError = Just "Please correct the errors in the form."}, Cmd.none)
|
||||
user =
|
||||
Comp.UserForm.getUser model.formModel
|
||||
|
||||
valid =
|
||||
Comp.UserForm.isValid model.formModel
|
||||
|
||||
cmd =
|
||||
if Comp.UserForm.isNewUser model.formModel then
|
||||
Api.postNewUser flags user SubmitResp
|
||||
|
||||
else
|
||||
Api.putUser flags user SubmitResp
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, cmd )
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
if res.success then
|
||||
let
|
||||
(m2, c2) = update flags (SetViewMode Table) model
|
||||
(m3, c3) = update flags LoadUsers m2
|
||||
( m2, c2 ) =
|
||||
update flags (SetViewMode Table) model
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags LoadUsers m2
|
||||
in
|
||||
({m3|loading = False}, Cmd.batch [c2,c3])
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
({model | formError = Just res.message, loading = False }, Cmd.none)
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
({model | formError = Just (Util.Http.errorToString err), loading = False}, Cmd.none)
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
|
||||
YesNoMsg m ->
|
||||
let
|
||||
(cm, confirmed) = Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
user = Comp.UserForm.getUser model.formModel
|
||||
cmd = if confirmed then Api.deleteUser flags user.login SubmitResp else Cmd.none
|
||||
( cm, confirmed ) =
|
||||
Comp.YesNoDimmer.update m model.deleteConfirm
|
||||
|
||||
user =
|
||||
Comp.UserForm.getUser model.formModel
|
||||
|
||||
cmd =
|
||||
if confirmed then
|
||||
Api.deleteUser flags user.login SubmitResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
({model | deleteConfirm = cm}, cmd)
|
||||
( { model | deleteConfirm = cm }, cmd )
|
||||
|
||||
view: Model -> Html Msg
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
if model.viewMode == Table then viewTable model
|
||||
else viewForm model
|
||||
if model.viewMode == Table then
|
||||
viewTable model
|
||||
|
||||
viewTable: Model -> Html Msg
|
||||
else
|
||||
viewForm model
|
||||
|
||||
|
||||
viewTable : Model -> Html Msg
|
||||
viewTable model =
|
||||
div []
|
||||
[button [class "ui basic button", onClick InitNewUser]
|
||||
[i [class "plus icon"][]
|
||||
,text "Create new"
|
||||
]
|
||||
,Html.map TableMsg (Comp.UserTable.view model.tableModel)
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
[ button [ class "ui basic button", onClick InitNewUser ]
|
||||
[ i [ class "plus icon" ] []
|
||||
, text "Create new"
|
||||
]
|
||||
, Html.map TableMsg (Comp.UserTable.view model.tableModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
||||
viewForm: Model -> Html Msg
|
||||
|
||||
viewForm : Model -> Html Msg
|
||||
viewForm model =
|
||||
let
|
||||
newUser = Comp.UserForm.isNewUser model.formModel
|
||||
newUser =
|
||||
Comp.UserForm.isNewUser model.formModel
|
||||
in
|
||||
Html.form [class "ui segment", onSubmit Submit]
|
||||
[Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
,if newUser then
|
||||
h3 [class "ui dividing header"]
|
||||
[text "Create new user"
|
||||
]
|
||||
else
|
||||
h3 [class "ui dividing header"]
|
||||
[text ("Edit user: " ++ model.formModel.user.login)
|
||||
]
|
||||
,Html.map FormMsg (Comp.UserForm.view model.formModel)
|
||||
,div [classList [("ui error message", True)
|
||||
,("invisible", Util.Maybe.isEmpty model.formError)
|
||||
]
|
||||
]
|
||||
[Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
,div [class "ui horizontal divider"][]
|
||||
,button [class "ui primary button", type_ "submit"]
|
||||
[text "Submit"
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newUser then
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text "Create new user"
|
||||
]
|
||||
,a [class "ui secondary button", onClick (SetViewMode Table), href ""]
|
||||
[text "Cancel"
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit user: " ++ model.formModel.user.login)
|
||||
]
|
||||
, Html.map FormMsg (Comp.UserForm.view model.formModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui error message", True )
|
||||
, ( "invisible", Util.Maybe.isEmpty model.formError )
|
||||
]
|
||||
,if not newUser then
|
||||
a [class "ui right floated red button", href "", onClick RequestDelete]
|
||||
[text "Delete"]
|
||||
else
|
||||
span[][]
|
||||
,div [classList [("ui dimmer", True)
|
||||
,("active", model.loading)
|
||||
]]
|
||||
[div [class "ui loader"][]
|
||||
]
|
||||
]
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newUser then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
span [] []
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
]
|
||||
]
|
||||
|
@ -1,83 +1,91 @@
|
||||
module Comp.UserTable exposing ( Model
|
||||
, emptyModel
|
||||
, Msg(..)
|
||||
, view
|
||||
, update)
|
||||
module Comp.UserTable exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api.Model.User exposing (User)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Api.Model.User exposing (User)
|
||||
import Util.Time exposing (formatDateTime)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ users: List User
|
||||
, selected: Maybe User
|
||||
{ users : List User
|
||||
, selected : Maybe User
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ users = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SetUsers (List User)
|
||||
| Select User
|
||||
| Deselect
|
||||
|
||||
update: Flags -> Msg -> Model -> (Model, Cmd Msg)
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
SetUsers list ->
|
||||
({model | users = list, selected = Nothing }, Cmd.none)
|
||||
( { model | users = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select user ->
|
||||
({model | selected = Just user}, Cmd.none)
|
||||
( { model | selected = Just user }, Cmd.none )
|
||||
|
||||
Deselect ->
|
||||
({model | selected = Nothing}, Cmd.none)
|
||||
( { model | selected = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view: Model -> Html Msg
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [class "ui selectable table"]
|
||||
[thead []
|
||||
[tr []
|
||||
[th [class "collapsing"][text "Login"]
|
||||
,th [class "collapsing"][text "State"]
|
||||
,th [class "collapsing"][text "Email"]
|
||||
,th [class "collapsing"][text "Logins"]
|
||||
,th [class "collapsing"][text "Last Login"]
|
||||
,th [class "collapsing"][text "Created"]
|
||||
]
|
||||
]
|
||||
,tbody []
|
||||
table [ class "ui selectable table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Login" ]
|
||||
, th [ class "collapsing" ] [ text "State" ]
|
||||
, th [ class "collapsing" ] [ text "Email" ]
|
||||
, th [ class "collapsing" ] [ text "Logins" ]
|
||||
, th [ class "collapsing" ] [ text "Last Login" ]
|
||||
, th [ class "collapsing" ] [ text "Created" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderUserLine model) model.users)
|
||||
]
|
||||
|
||||
renderUserLine: Model -> User -> Html Msg
|
||||
|
||||
renderUserLine : Model -> User -> Html Msg
|
||||
renderUserLine model user =
|
||||
tr [classList [("active", model.selected == Just user)]
|
||||
,onClick (Select user)
|
||||
]
|
||||
[td [class "collapsing"]
|
||||
[text user.login
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[text user.state
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just user ) ]
|
||||
, onClick (Select user)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ text user.login
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[Maybe.withDefault "" user.email |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ text user.state
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[String.fromInt user.loginCount |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ Maybe.withDefault "" user.email |> text
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[Maybe.map formatDateTime user.lastLogin |> Maybe.withDefault "" |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ String.fromInt user.loginCount |> text
|
||||
]
|
||||
,td [class "collapsing"]
|
||||
[formatDateTime user.created |> text
|
||||
, td [ class "collapsing" ]
|
||||
[ Maybe.map formatDateTime user.lastLogin |> Maybe.withDefault "" |> text
|
||||
]
|
||||
, td [ class "collapsing" ]
|
||||
[ formatDateTime user.created |> text
|
||||
]
|
||||
]
|
||||
|
@ -1,43 +1,49 @@
|
||||
module Comp.YesNoDimmer exposing ( Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
, view2
|
||||
, activate
|
||||
, disable
|
||||
, Settings
|
||||
, defaultSettings
|
||||
)
|
||||
module Comp.YesNoDimmer exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, Settings
|
||||
, activate
|
||||
, defaultSettings
|
||||
, disable
|
||||
, emptyModel
|
||||
, update
|
||||
, view
|
||||
, view2
|
||||
)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ active: Bool
|
||||
{ active : Bool
|
||||
}
|
||||
|
||||
emptyModel: Model
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ active = False
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Activate
|
||||
| Disable
|
||||
| ConfirmDelete
|
||||
|
||||
|
||||
type alias Settings =
|
||||
{ message: String
|
||||
, headerIcon: String
|
||||
, headerClass: String
|
||||
, confirmButton: String
|
||||
, cancelButton: String
|
||||
, invertedDimmer: Bool
|
||||
{ message : String
|
||||
, headerIcon : String
|
||||
, headerClass : String
|
||||
, confirmButton : String
|
||||
, cancelButton : String
|
||||
, invertedDimmer : Bool
|
||||
}
|
||||
|
||||
defaultSettings: Settings
|
||||
|
||||
defaultSettings : Settings
|
||||
defaultSettings =
|
||||
{ message = "Delete this item permanently?"
|
||||
, headerIcon = "exclamation icon"
|
||||
@ -48,48 +54,62 @@ defaultSettings =
|
||||
}
|
||||
|
||||
|
||||
activate: Msg
|
||||
activate = Activate
|
||||
activate : Msg
|
||||
activate =
|
||||
Activate
|
||||
|
||||
disable: Msg
|
||||
disable = Disable
|
||||
|
||||
update: Msg -> Model -> (Model, Bool)
|
||||
disable : Msg
|
||||
disable =
|
||||
Disable
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Bool )
|
||||
update msg model =
|
||||
case msg of
|
||||
Activate ->
|
||||
({model | active = True}, False)
|
||||
Disable ->
|
||||
({model | active = False}, False)
|
||||
ConfirmDelete ->
|
||||
({model | active = False}, True)
|
||||
( { model | active = True }, False )
|
||||
|
||||
view: Model -> Html Msg
|
||||
Disable ->
|
||||
( { model | active = False }, False )
|
||||
|
||||
ConfirmDelete ->
|
||||
( { model | active = False }, True )
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
view2 True defaultSettings model
|
||||
|
||||
view2: Bool -> Settings -> Model -> Html Msg
|
||||
|
||||
|
||||
view2 : Bool -> Settings -> Model -> Html Msg
|
||||
view2 active settings model =
|
||||
div [classList [("ui dimmer", True)
|
||||
,("inverted", settings.invertedDimmer)
|
||||
,("active", (active && model.active))
|
||||
]
|
||||
]
|
||||
[div [class "content"]
|
||||
[h3 [class settings.headerClass]
|
||||
[if settings.headerIcon == "" then span[][] else i [class settings.headerIcon][]
|
||||
,text settings.message
|
||||
]
|
||||
]
|
||||
,div [class "content"]
|
||||
[div [class "ui buttons"]
|
||||
[a [class "ui primary button", onClick ConfirmDelete, href ""]
|
||||
[text settings.confirmButton
|
||||
]
|
||||
,div [class "or"][]
|
||||
,a [class "ui secondary button", onClick Disable, href ""]
|
||||
[text settings.cancelButton
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "inverted", settings.invertedDimmer )
|
||||
, ( "active", active && model.active )
|
||||
]
|
||||
]
|
||||
[ div [ class "content" ]
|
||||
[ h3 [ class settings.headerClass ]
|
||||
[ if settings.headerIcon == "" then
|
||||
span [] []
|
||||
|
||||
else
|
||||
i [ class settings.headerIcon ] []
|
||||
, text settings.message
|
||||
]
|
||||
]
|
||||
, div [ class "content" ]
|
||||
[ div [ class "ui buttons" ]
|
||||
[ a [ class "ui primary button", onClick ConfirmDelete, href "" ]
|
||||
[ text settings.confirmButton
|
||||
]
|
||||
, div [ class "or" ] []
|
||||
, a [ class "ui secondary button", onClick Disable, href "" ]
|
||||
[ text settings.cancelButton
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
Reference in New Issue
Block a user