mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-04 10:29:34 +00:00
Fix and enhance custom-multi-input field
This commit is contained in:
parent
066c856981
commit
23b343649c
@ -1,13 +1,14 @@
|
||||
module Comp.CustomFieldMultiInput exposing
|
||||
( FieldResult(..)
|
||||
, Model
|
||||
( Model
|
||||
, Msg
|
||||
, UpdateResult
|
||||
, ViewSettings
|
||||
, init
|
||||
, initCmd
|
||||
, initWith
|
||||
, isEmpty
|
||||
, nonEmpty
|
||||
, reset
|
||||
, setValues
|
||||
, update
|
||||
, view
|
||||
@ -19,24 +20,49 @@ import Api.Model.CustomFieldList exposing (CustomFieldList)
|
||||
import Api.Model.ItemFieldValue exposing (ItemFieldValue)
|
||||
import Comp.CustomFieldInput
|
||||
import Comp.FixedDropdown
|
||||
import Data.CustomFieldChange exposing (CustomFieldChange(..))
|
||||
import Data.Flags exposing (Flags)
|
||||
import Dict exposing (Dict)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Util.List
|
||||
import Util.Maybe
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ fieldModels : Dict String Comp.CustomFieldInput.Model
|
||||
, fieldSelect : FieldSelect
|
||||
, visibleFields : List CustomField
|
||||
, availableFields : List CustomField
|
||||
{ fieldSelect : FieldSelect
|
||||
, visibleFields : Dict String VisibleField
|
||||
, allFields : List CustomField
|
||||
}
|
||||
|
||||
|
||||
type alias FieldSelect =
|
||||
{ selected : Maybe CustomField
|
||||
, dropdown : Comp.FixedDropdown.Model CustomField
|
||||
}
|
||||
|
||||
|
||||
type alias VisibleField =
|
||||
{ field : CustomField
|
||||
, inputModel : Comp.CustomFieldInput.Model
|
||||
}
|
||||
|
||||
|
||||
visibleFields : Model -> List CustomField
|
||||
visibleFields model =
|
||||
Dict.toList model.visibleFields
|
||||
|> List.map (Tuple.second >> .field)
|
||||
|> List.sortBy .name
|
||||
|
||||
|
||||
currentOptions : List CustomField -> Dict String VisibleField -> List CustomField
|
||||
currentOptions all visible =
|
||||
List.filter
|
||||
(\e -> not <| Dict.member e.name visible)
|
||||
all
|
||||
|
||||
|
||||
type Msg
|
||||
= CustomFieldInputMsg CustomField Comp.CustomFieldInput.Msg
|
||||
| ApplyField CustomField
|
||||
@ -47,30 +73,21 @@ type Msg
|
||||
| SetValues (List ItemFieldValue)
|
||||
|
||||
|
||||
type FieldResult
|
||||
= NoResult
|
||||
| FieldValueRemove CustomField
|
||||
| FieldValueChange CustomField String
|
||||
| FieldCreateNew
|
||||
|
||||
|
||||
type alias FieldSelect =
|
||||
{ selected : Maybe CustomField
|
||||
, dropdown : Comp.FixedDropdown.Model CustomField
|
||||
}
|
||||
|
||||
|
||||
nonEmpty : Model -> Bool
|
||||
nonEmpty model =
|
||||
not (List.isEmpty model.availableFields && List.isEmpty model.visibleFields)
|
||||
not (isEmpty model)
|
||||
|
||||
|
||||
isEmpty : Model -> Bool
|
||||
isEmpty model =
|
||||
List.isEmpty model.allFields
|
||||
|
||||
|
||||
initWith : List CustomField -> Model
|
||||
initWith fields =
|
||||
{ fieldModels = Dict.empty
|
||||
, fieldSelect = mkFieldSelect fields
|
||||
, visibleFields = []
|
||||
, availableFields = fields
|
||||
{ fieldSelect = mkFieldSelect (currentOptions fields Dict.empty)
|
||||
, visibleFields = Dict.empty
|
||||
, allFields = fields
|
||||
}
|
||||
|
||||
|
||||
@ -91,6 +108,18 @@ setValues values =
|
||||
SetValues values
|
||||
|
||||
|
||||
reset : Model -> Model
|
||||
reset model =
|
||||
let
|
||||
opts =
|
||||
currentOptions model.allFields Dict.empty
|
||||
in
|
||||
{ model
|
||||
| fieldSelect = mkFieldSelect opts
|
||||
, visibleFields = Dict.empty
|
||||
}
|
||||
|
||||
|
||||
mkFieldSelect : List CustomField -> FieldSelect
|
||||
mkFieldSelect fields =
|
||||
{ selected = Nothing
|
||||
@ -106,7 +135,7 @@ type alias UpdateResult =
|
||||
{ model : Model
|
||||
, cmd : Cmd Msg
|
||||
, subs : Sub Msg
|
||||
, result : FieldResult
|
||||
, result : CustomFieldChange
|
||||
}
|
||||
|
||||
|
||||
@ -123,21 +152,16 @@ update msg model =
|
||||
|
||||
CustomFieldResp (Ok list) ->
|
||||
let
|
||||
avail =
|
||||
List.filter
|
||||
(\e -> not <| Dict.member e.name model.fieldModels)
|
||||
list.items
|
||||
|
||||
model_ =
|
||||
{ model
|
||||
| availableFields = avail
|
||||
, fieldSelect = mkFieldSelect avail
|
||||
| allFields = list.items
|
||||
, fieldSelect = mkFieldSelect (currentOptions list.items model.visibleFields)
|
||||
}
|
||||
in
|
||||
UpdateResult model_ Cmd.none Sub.none NoResult
|
||||
UpdateResult model_ Cmd.none Sub.none NoFieldChange
|
||||
|
||||
CustomFieldResp (Err _) ->
|
||||
UpdateResult model Cmd.none Sub.none NoResult
|
||||
UpdateResult model Cmd.none Sub.none NoFieldChange
|
||||
|
||||
FieldSelectMsg lm ->
|
||||
let
|
||||
@ -160,26 +184,18 @@ update msg model =
|
||||
update (ApplyField field) model
|
||||
|
||||
Nothing ->
|
||||
UpdateResult model_ Cmd.none Sub.none NoResult
|
||||
UpdateResult model_ Cmd.none Sub.none NoFieldChange
|
||||
|
||||
ApplyField f ->
|
||||
let
|
||||
notSelected e =
|
||||
e /= f && (not <| Dict.member e.name model.fieldModels)
|
||||
|
||||
( fm, fc ) =
|
||||
Comp.CustomFieldInput.init f
|
||||
|
||||
avail =
|
||||
List.filter notSelected model.availableFields
|
||||
|
||||
visible =
|
||||
f
|
||||
:: model.visibleFields
|
||||
|> List.sortBy .name
|
||||
Dict.insert f.name (VisibleField f fm) model.visibleFields
|
||||
|
||||
fSelect =
|
||||
mkFieldSelect avail
|
||||
mkFieldSelect (currentOptions model.allFields visible)
|
||||
|
||||
-- have to re-state the open menu when this is invoked
|
||||
-- from a click in the dropdown
|
||||
@ -192,46 +208,43 @@ update msg model =
|
||||
model_ =
|
||||
{ model
|
||||
| fieldSelect = { fSelect | dropdown = dropdownOpen }
|
||||
, availableFields = avail
|
||||
, visibleFields = visible
|
||||
, fieldModels = Dict.insert f.name fm model.fieldModels
|
||||
}
|
||||
|
||||
cmd_ =
|
||||
Cmd.map (CustomFieldInputMsg f) fc
|
||||
in
|
||||
UpdateResult model_ cmd_ Sub.none NoResult
|
||||
UpdateResult model_ cmd_ Sub.none NoFieldChange
|
||||
|
||||
RemoveField f ->
|
||||
let
|
||||
avail =
|
||||
f :: model.availableFields
|
||||
|
||||
visible =
|
||||
List.filter (\e -> e /= f) model.visibleFields
|
||||
Dict.remove f.name model.visibleFields
|
||||
|
||||
model_ =
|
||||
{ model
|
||||
| availableFields = avail
|
||||
, visibleFields = visible
|
||||
, fieldSelect = mkFieldSelect avail
|
||||
| visibleFields = visible
|
||||
, fieldSelect = mkFieldSelect (currentOptions model.allFields visible)
|
||||
}
|
||||
in
|
||||
UpdateResult model_ Cmd.none Sub.none (FieldValueRemove f)
|
||||
|
||||
CustomFieldInputMsg field lm ->
|
||||
CustomFieldInputMsg f lm ->
|
||||
let
|
||||
fieldModel =
|
||||
Dict.get field.name model.fieldModels
|
||||
visibleField =
|
||||
Dict.get f.name model.visibleFields
|
||||
in
|
||||
case fieldModel of
|
||||
Just fm ->
|
||||
case visibleField of
|
||||
Just { field, inputModel } ->
|
||||
let
|
||||
res =
|
||||
Comp.CustomFieldInput.update lm fm
|
||||
Comp.CustomFieldInput.update lm inputModel
|
||||
|
||||
model_ =
|
||||
{ model | fieldModels = Dict.insert field.name res.model model.fieldModels }
|
||||
{ model
|
||||
| visibleFields =
|
||||
Dict.insert field.name (VisibleField field res.model) model.visibleFields
|
||||
}
|
||||
|
||||
cmd_ =
|
||||
Cmd.map (CustomFieldInputMsg field) res.cmd
|
||||
@ -245,7 +258,7 @@ update msg model =
|
||||
FieldValueRemove field
|
||||
|
||||
Comp.CustomFieldInput.NoResult ->
|
||||
NoResult
|
||||
NoFieldChange
|
||||
in
|
||||
if res.result == Comp.CustomFieldInput.RemoveField then
|
||||
update (RemoveField field) model_
|
||||
@ -254,7 +267,7 @@ update msg model =
|
||||
UpdateResult model_ cmd_ Sub.none result
|
||||
|
||||
Nothing ->
|
||||
UpdateResult model Cmd.none Sub.none NoResult
|
||||
UpdateResult model Cmd.none Sub.none NoFieldChange
|
||||
|
||||
SetValues values ->
|
||||
let
|
||||
@ -265,33 +278,24 @@ update msg model =
|
||||
let
|
||||
( fim, fic ) =
|
||||
Comp.CustomFieldInput.initWith fv
|
||||
|
||||
f =
|
||||
field fv
|
||||
in
|
||||
( Dict.insert fv.name fim dict
|
||||
, Cmd.map (CustomFieldInputMsg (field fv)) fic :: cmds
|
||||
( Dict.insert fv.name (VisibleField f fim) dict
|
||||
, Cmd.map (CustomFieldInputMsg f) fic :: cmds
|
||||
)
|
||||
|
||||
( modelDict, cmdList ) =
|
||||
List.foldl merge ( Dict.empty, [] ) values
|
||||
|
||||
avail =
|
||||
List.filter
|
||||
(\e -> not <| Dict.member e.name modelDict)
|
||||
(model.availableFields ++ model.visibleFields)
|
||||
|
||||
model_ =
|
||||
{ model
|
||||
| fieldModels = modelDict
|
||||
, availableFields = avail
|
||||
, fieldSelect = mkFieldSelect avail
|
||||
, visibleFields =
|
||||
model.visibleFields
|
||||
++ model.availableFields
|
||||
|> List.filter (\e -> Dict.member e.name modelDict)
|
||||
|> Util.List.distinct
|
||||
|> List.sortBy .name
|
||||
| fieldSelect = mkFieldSelect (currentOptions model.allFields modelDict)
|
||||
, visibleFields = modelDict
|
||||
}
|
||||
in
|
||||
UpdateResult model_ (Cmd.batch cmdList) Sub.none NoResult
|
||||
UpdateResult model_ (Cmd.batch cmdList) Sub.none NoFieldChange
|
||||
|
||||
|
||||
|
||||
@ -308,7 +312,7 @@ view : ViewSettings -> Model -> Html Msg
|
||||
view viewSettings model =
|
||||
div [ class viewSettings.classes ]
|
||||
(viewMenuBar viewSettings model
|
||||
:: List.map (viewCustomField model) model.visibleFields
|
||||
:: List.map (viewCustomField model) (visibleFields model)
|
||||
)
|
||||
|
||||
|
||||
@ -339,13 +343,13 @@ viewMenuBar viewSettings model =
|
||||
viewCustomField : Model -> CustomField -> Html Msg
|
||||
viewCustomField model field =
|
||||
let
|
||||
fieldModel =
|
||||
Dict.get field.name model.fieldModels
|
||||
visibleField =
|
||||
Dict.get field.name model.visibleFields
|
||||
in
|
||||
case fieldModel of
|
||||
Just fm ->
|
||||
case visibleField of
|
||||
Just vf ->
|
||||
Html.map (CustomFieldInputMsg field)
|
||||
(Comp.CustomFieldInput.view "field" Nothing fm)
|
||||
(Comp.CustomFieldInput.view "field" Nothing vf.inputModel)
|
||||
|
||||
Nothing ->
|
||||
span [] []
|
||||
|
@ -18,11 +18,12 @@ import Api.Model.ItemProposals exposing (ItemProposals)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Api.Model.TagList exposing (TagList)
|
||||
import Comp.CustomFieldMultiInput exposing (FieldResult(..))
|
||||
import Comp.CustomFieldMultiInput
|
||||
import Comp.DatePicker
|
||||
import Comp.DetailEdit
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
import Comp.ItemDetail.FormChange exposing (FormChange(..))
|
||||
import Data.CustomFieldChange exposing (CustomFieldChange(..))
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.Fields
|
||||
import Data.Flags exposing (Flags)
|
||||
@ -568,7 +569,7 @@ update flags msg model =
|
||||
|
||||
change =
|
||||
case res.result of
|
||||
NoResult ->
|
||||
NoFieldChange ->
|
||||
NoFormChange
|
||||
|
||||
FieldValueRemove cf ->
|
||||
|
@ -14,7 +14,7 @@ import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Browser.Navigation as Nav
|
||||
import Comp.AttachmentMeta
|
||||
import Comp.CustomFieldMultiInput exposing (FieldResult(..))
|
||||
import Comp.CustomFieldMultiInput
|
||||
import Comp.DatePicker
|
||||
import Comp.DetailEdit
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
@ -41,6 +41,7 @@ import Comp.OrgForm
|
||||
import Comp.PersonForm
|
||||
import Comp.SentMails
|
||||
import Comp.YesNoDimmer
|
||||
import Data.CustomFieldChange exposing (CustomFieldChange(..))
|
||||
import Data.Direction
|
||||
import Data.Fields exposing (Field)
|
||||
import Data.Flags exposing (Flags)
|
||||
@ -1301,7 +1302,7 @@ update key flags inav settings msg model =
|
||||
|
||||
action =
|
||||
case result.result of
|
||||
NoResult ->
|
||||
NoFieldChange ->
|
||||
Cmd.none
|
||||
|
||||
FieldValueRemove field ->
|
||||
|
77
modules/webapp/src/main/elm/Data/CustomFieldChange.elm
Normal file
77
modules/webapp/src/main/elm/Data/CustomFieldChange.elm
Normal file
@ -0,0 +1,77 @@
|
||||
module Data.CustomFieldChange exposing
|
||||
( CustomFieldChange(..)
|
||||
, CustomFieldValueCollect
|
||||
, collectValues
|
||||
, emptyCollect
|
||||
, isValueChange
|
||||
, toFieldValues
|
||||
)
|
||||
|
||||
import Api.Model.CustomField exposing (CustomField)
|
||||
import Api.Model.CustomFieldValue exposing (CustomFieldValue)
|
||||
import Dict exposing (Dict)
|
||||
|
||||
|
||||
type CustomFieldChange
|
||||
= NoFieldChange
|
||||
| FieldValueRemove CustomField
|
||||
| FieldValueChange CustomField String
|
||||
| FieldCreateNew
|
||||
|
||||
|
||||
type CustomFieldValueCollect
|
||||
= CustomFieldValueCollect (Dict String String)
|
||||
|
||||
|
||||
emptyCollect : CustomFieldValueCollect
|
||||
emptyCollect =
|
||||
CustomFieldValueCollect Dict.empty
|
||||
|
||||
|
||||
collectValues :
|
||||
CustomFieldChange
|
||||
-> CustomFieldValueCollect
|
||||
-> CustomFieldValueCollect
|
||||
collectValues change collector =
|
||||
let
|
||||
dict =
|
||||
case collector of
|
||||
CustomFieldValueCollect d ->
|
||||
d
|
||||
in
|
||||
case change of
|
||||
NoFieldChange ->
|
||||
collector
|
||||
|
||||
FieldValueRemove f ->
|
||||
CustomFieldValueCollect (Dict.remove f.id dict)
|
||||
|
||||
FieldValueChange f v ->
|
||||
CustomFieldValueCollect (Dict.insert f.id v dict)
|
||||
|
||||
FieldCreateNew ->
|
||||
collector
|
||||
|
||||
|
||||
toFieldValues : CustomFieldValueCollect -> List CustomFieldValue
|
||||
toFieldValues dict =
|
||||
case dict of
|
||||
CustomFieldValueCollect d ->
|
||||
Dict.toList d
|
||||
|> List.map (\( k, v ) -> CustomFieldValue k v)
|
||||
|
||||
|
||||
isValueChange : CustomFieldChange -> Bool
|
||||
isValueChange change =
|
||||
case change of
|
||||
NoFieldChange ->
|
||||
False
|
||||
|
||||
FieldValueRemove _ ->
|
||||
True
|
||||
|
||||
FieldValueChange _ _ ->
|
||||
True
|
||||
|
||||
FieldCreateNew ->
|
||||
False
|
Loading…
x
Reference in New Issue
Block a user