mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-23 02:48:26 +00:00
Allow to select multiple items for deletion and edit
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
module Comp.ItemCardList exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, ViewConfig
|
||||
, init
|
||||
, nextItem
|
||||
, prevItem
|
||||
@ -17,12 +18,16 @@ import Data.Direction
|
||||
import Data.Fields
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Icons as Icons
|
||||
import Data.ItemSelection exposing (ItemSelection)
|
||||
import Data.Items
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Markdown
|
||||
import Page exposing (Page(..))
|
||||
import Set exposing (Set)
|
||||
import Util.Html
|
||||
import Util.ItemDragDrop as DD
|
||||
import Util.List
|
||||
import Util.String
|
||||
@ -38,6 +43,7 @@ type Msg
|
||||
= SetResults ItemLightList
|
||||
| AddResults ItemLightList
|
||||
| ItemDDMsg DD.Msg
|
||||
| ToggleSelectItem (Set String) String
|
||||
|
||||
|
||||
init : Model
|
||||
@ -75,6 +81,7 @@ type alias UpdateResult =
|
||||
{ model : Model
|
||||
, cmd : Cmd Msg
|
||||
, dragModel : DD.Model
|
||||
, selection : ItemSelection
|
||||
}
|
||||
|
||||
|
||||
@ -91,51 +98,78 @@ updateDrag dm _ msg model =
|
||||
newModel =
|
||||
{ model | results = list }
|
||||
in
|
||||
UpdateResult newModel Cmd.none dm
|
||||
UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive
|
||||
|
||||
AddResults list ->
|
||||
if list.groups == [] then
|
||||
UpdateResult model Cmd.none dm
|
||||
UpdateResult model Cmd.none dm Data.ItemSelection.Inactive
|
||||
|
||||
else
|
||||
let
|
||||
newModel =
|
||||
{ model | results = Data.Items.concat model.results list }
|
||||
in
|
||||
UpdateResult newModel Cmd.none dm
|
||||
UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive
|
||||
|
||||
ItemDDMsg lm ->
|
||||
let
|
||||
ddd =
|
||||
DD.update lm dm
|
||||
in
|
||||
UpdateResult model Cmd.none ddd.model
|
||||
UpdateResult model Cmd.none ddd.model Data.ItemSelection.Inactive
|
||||
|
||||
ToggleSelectItem ids id ->
|
||||
let
|
||||
newSet =
|
||||
if Set.member id ids then
|
||||
Set.remove id ids
|
||||
|
||||
else
|
||||
Set.insert id ids
|
||||
in
|
||||
UpdateResult model Cmd.none dm (Data.ItemSelection.Active newSet)
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Maybe String -> UiSettings -> Model -> Html Msg
|
||||
view current settings model =
|
||||
type alias ViewConfig =
|
||||
{ current : Maybe String
|
||||
, selection : ItemSelection
|
||||
}
|
||||
|
||||
|
||||
isSelected : ViewConfig -> String -> Bool
|
||||
isSelected cfg id =
|
||||
case cfg.selection of
|
||||
Data.ItemSelection.Active ids ->
|
||||
Set.member id ids
|
||||
|
||||
Data.ItemSelection.Inactive ->
|
||||
False
|
||||
|
||||
|
||||
view : ViewConfig -> UiSettings -> Model -> Html Msg
|
||||
view cfg settings model =
|
||||
div [ class "ui container" ]
|
||||
(List.map (viewGroup current settings) model.results.groups)
|
||||
(List.map (viewGroup cfg settings) model.results.groups)
|
||||
|
||||
|
||||
viewGroup : Maybe String -> UiSettings -> ItemLightGroup -> Html Msg
|
||||
viewGroup current settings group =
|
||||
viewGroup : ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
|
||||
viewGroup cfg settings group =
|
||||
div [ class "item-group" ]
|
||||
[ div [ class "ui horizontal divider header item-list" ]
|
||||
[ i [ class "calendar alternate outline icon" ] []
|
||||
, text group.name
|
||||
]
|
||||
, div [ class "ui stackable three cards" ]
|
||||
(List.map (viewItem current settings) group.items)
|
||||
(List.map (viewItem cfg settings) group.items)
|
||||
]
|
||||
|
||||
|
||||
viewItem : Maybe String -> UiSettings -> ItemLight -> Html Msg
|
||||
viewItem current settings item =
|
||||
viewItem : ViewConfig -> UiSettings -> ItemLight -> Html Msg
|
||||
viewItem cfg settings item =
|
||||
let
|
||||
dirIcon =
|
||||
i [ class (Data.Direction.iconFromMaybe item.direction) ] []
|
||||
@ -163,43 +197,68 @@ viewItem current settings item =
|
||||
isConfirmed =
|
||||
item.state /= "created"
|
||||
|
||||
newColor =
|
||||
"blue"
|
||||
cardColor =
|
||||
if isSelected cfg item.id then
|
||||
"purple"
|
||||
|
||||
else if not isConfirmed then
|
||||
"blue"
|
||||
|
||||
else
|
||||
""
|
||||
|
||||
fieldHidden f =
|
||||
Data.UiSettings.fieldHidden settings f
|
||||
|
||||
cardAction =
|
||||
case cfg.selection of
|
||||
Data.ItemSelection.Inactive ->
|
||||
Page.href (ItemDetailPage item.id)
|
||||
|
||||
Data.ItemSelection.Active ids ->
|
||||
onClick (ToggleSelectItem ids item.id)
|
||||
in
|
||||
a
|
||||
([ classList
|
||||
[ ( "ui fluid card", True )
|
||||
, ( newColor, not isConfirmed )
|
||||
, ( "current", current == Just item.id )
|
||||
, ( cardColor, True )
|
||||
, ( "current", cfg.current == Just item.id )
|
||||
]
|
||||
, id item.id
|
||||
, Page.href (ItemDetailPage item.id)
|
||||
, href "#"
|
||||
, cardAction
|
||||
]
|
||||
++ DD.draggable ItemDDMsg item.id
|
||||
)
|
||||
[ div [ class "content" ]
|
||||
[ if fieldHidden Data.Fields.Direction then
|
||||
div [ class "header" ]
|
||||
[ Util.String.underscoreToSpace item.name |> text
|
||||
]
|
||||
[ case cfg.selection of
|
||||
Data.ItemSelection.Active ids ->
|
||||
div [ class "header" ]
|
||||
[ Util.Html.checkbox (Set.member item.id ids)
|
||||
, Util.String.underscoreToSpace item.name
|
||||
|> text
|
||||
]
|
||||
|
||||
else
|
||||
div
|
||||
[ class "header"
|
||||
, Data.Direction.labelFromMaybe item.direction
|
||||
|> title
|
||||
]
|
||||
[ dirIcon
|
||||
, Util.String.underscoreToSpace item.name
|
||||
|> text
|
||||
]
|
||||
Data.ItemSelection.Inactive ->
|
||||
if fieldHidden Data.Fields.Direction then
|
||||
div [ class "header" ]
|
||||
[ Util.String.underscoreToSpace item.name |> text
|
||||
]
|
||||
|
||||
else
|
||||
div
|
||||
[ class "header"
|
||||
, Data.Direction.labelFromMaybe item.direction
|
||||
|> title
|
||||
]
|
||||
[ dirIcon
|
||||
, Util.String.underscoreToSpace item.name
|
||||
|> text
|
||||
]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui right corner label", True )
|
||||
, ( newColor, True )
|
||||
, ( cardColor, True )
|
||||
, ( "invisible", isConfirmed )
|
||||
]
|
||||
, title "New"
|
||||
|
693
modules/webapp/src/main/elm/Comp/ItemDetail/EditMenu.elm
Normal file
693
modules/webapp/src/main/elm/Comp/ItemDetail/EditMenu.elm
Normal file
@ -0,0 +1,693 @@
|
||||
module Comp.ItemDetail.EditMenu exposing
|
||||
( Model
|
||||
, Msg
|
||||
, SaveNameState(..)
|
||||
, defaultViewConfig
|
||||
, init
|
||||
, loadModel
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Api
|
||||
import Api.Model.EquipmentList exposing (EquipmentList)
|
||||
import Api.Model.FolderItem exposing (FolderItem)
|
||||
import Api.Model.FolderList exposing (FolderList)
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
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.DatePicker
|
||||
import Comp.DetailEdit
|
||||
import Comp.Dropdown exposing (isDropdownChangeMsg)
|
||||
import Comp.ItemDetail.FormChange exposing (FormChange(..))
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.Fields
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.Icons as Icons
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import DatePicker exposing (DatePicker)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Http
|
||||
import Markdown
|
||||
import Page exposing (Page(..))
|
||||
import Task
|
||||
import Throttle exposing (Throttle)
|
||||
import Time
|
||||
import Util.Folder exposing (mkFolderOption)
|
||||
import Util.List
|
||||
import Util.Maybe
|
||||
import Util.Tag
|
||||
|
||||
|
||||
|
||||
--- Model
|
||||
|
||||
|
||||
type SaveNameState
|
||||
= Saving
|
||||
| SaveSuccess
|
||||
| SaveFailed
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ tagModel : Comp.Dropdown.Model Tag
|
||||
, nameModel : String
|
||||
, nameSaveThrottle : Throttle Msg
|
||||
, folderModel : Comp.Dropdown.Model IdName
|
||||
, allFolders : List FolderItem
|
||||
, directionModel : Comp.Dropdown.Model Direction
|
||||
, itemDatePicker : DatePicker
|
||||
, itemDate : Maybe Int
|
||||
, itemProposals : ItemProposals
|
||||
, dueDate : Maybe Int
|
||||
, dueDatePicker : DatePicker
|
||||
, corrOrgModel : Comp.Dropdown.Model IdName
|
||||
, corrPersonModel : Comp.Dropdown.Model IdName
|
||||
, concPersonModel : Comp.Dropdown.Model IdName
|
||||
, concEquipModel : Comp.Dropdown.Model IdName
|
||||
, modalEdit : Maybe Comp.DetailEdit.Model
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= ItemDatePickerMsg Comp.DatePicker.Msg
|
||||
| DueDatePickerMsg Comp.DatePicker.Msg
|
||||
| SetName String
|
||||
| SaveName
|
||||
| UpdateThrottle
|
||||
| RemoveDueDate
|
||||
| RemoveDate
|
||||
| FolderDropdownMsg (Comp.Dropdown.Msg IdName)
|
||||
| TagDropdownMsg (Comp.Dropdown.Msg Tag)
|
||||
| DirDropdownMsg (Comp.Dropdown.Msg Direction)
|
||||
| OrgDropdownMsg (Comp.Dropdown.Msg IdName)
|
||||
| CorrPersonMsg (Comp.Dropdown.Msg IdName)
|
||||
| ConcPersonMsg (Comp.Dropdown.Msg IdName)
|
||||
| ConcEquipMsg (Comp.Dropdown.Msg IdName)
|
||||
| GetTagsResp (Result Http.Error TagList)
|
||||
| GetOrgResp (Result Http.Error ReferenceList)
|
||||
| GetPersonResp (Result Http.Error ReferenceList)
|
||||
| GetEquipResp (Result Http.Error EquipmentList)
|
||||
| GetFolderResp (Result Http.Error FolderList)
|
||||
|
||||
|
||||
init : Model
|
||||
init =
|
||||
{ tagModel =
|
||||
Util.Tag.makeDropdownModel
|
||||
, directionModel =
|
||||
Comp.Dropdown.makeSingleList
|
||||
{ makeOption =
|
||||
\entry ->
|
||||
{ value = Data.Direction.toString entry
|
||||
, text = Data.Direction.toString entry
|
||||
, additional = ""
|
||||
}
|
||||
, options = Data.Direction.all
|
||||
, placeholder = "Choose a direction…"
|
||||
, selected = Nothing
|
||||
}
|
||||
, corrOrgModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, placeholder = ""
|
||||
}
|
||||
, corrPersonModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, placeholder = ""
|
||||
}
|
||||
, concPersonModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, placeholder = ""
|
||||
}
|
||||
, concEquipModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, placeholder = ""
|
||||
}
|
||||
, folderModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, placeholder = ""
|
||||
}
|
||||
, allFolders = []
|
||||
, nameModel = ""
|
||||
, nameSaveThrottle = Throttle.create 1
|
||||
, itemDatePicker = Comp.DatePicker.emptyModel
|
||||
, itemDate = Nothing
|
||||
, itemProposals = Api.Model.ItemProposals.empty
|
||||
, dueDate = Nothing
|
||||
, dueDatePicker = Comp.DatePicker.emptyModel
|
||||
, modalEdit = Nothing
|
||||
}
|
||||
|
||||
|
||||
loadModel : Flags -> Cmd Msg
|
||||
loadModel flags =
|
||||
let
|
||||
( _, dpc ) =
|
||||
Comp.DatePicker.init
|
||||
in
|
||||
Cmd.batch
|
||||
[ Api.getTags flags "" GetTagsResp
|
||||
, Api.getOrgLight flags GetOrgResp
|
||||
, Api.getPersonsLight flags GetPersonResp
|
||||
, Api.getEquipments flags "" GetEquipResp
|
||||
, Api.getFolders flags "" False GetFolderResp
|
||||
, Cmd.map ItemDatePickerMsg dpc
|
||||
, Cmd.map DueDatePickerMsg dpc
|
||||
]
|
||||
|
||||
|
||||
isFolderMember : Model -> Bool
|
||||
isFolderMember model =
|
||||
let
|
||||
selected =
|
||||
Comp.Dropdown.getSelected model.folderModel
|
||||
|> List.head
|
||||
|> Maybe.map .id
|
||||
in
|
||||
Util.Folder.isFolderMember model.allFolders selected
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
type alias UpdateResult =
|
||||
{ model : Model
|
||||
, cmd : Cmd Msg
|
||||
, sub : Sub Msg
|
||||
, change : FormChange
|
||||
}
|
||||
|
||||
|
||||
resultNoCmd : FormChange -> Model -> UpdateResult
|
||||
resultNoCmd change model =
|
||||
UpdateResult model Cmd.none Sub.none change
|
||||
|
||||
|
||||
resultNone : Model -> UpdateResult
|
||||
resultNone model =
|
||||
resultNoCmd NoFormChange model
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> UpdateResult
|
||||
update flags msg model =
|
||||
case msg of
|
||||
TagDropdownMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.tagModel
|
||||
|
||||
newModel =
|
||||
{ model | tagModel = m2 }
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
Comp.Dropdown.getSelected newModel.tagModel
|
||||
|> Util.List.distinct
|
||||
|> List.map (\t -> IdName t.id t.name)
|
||||
|> ReferenceList
|
||||
|> TagChange
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
GetTagsResp (Ok tags) ->
|
||||
let
|
||||
tagList =
|
||||
Comp.Dropdown.SetOptions tags.items
|
||||
in
|
||||
update flags (TagDropdownMsg tagList) model
|
||||
|
||||
GetTagsResp (Err _) ->
|
||||
resultNone model
|
||||
|
||||
FolderDropdownMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.folderModel
|
||||
|
||||
newModel =
|
||||
{ model | folderModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
FolderChange idref
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
GetFolderResp (Ok fs) ->
|
||||
let
|
||||
model_ =
|
||||
{ model
|
||||
| allFolders = fs.items
|
||||
, folderModel =
|
||||
Comp.Dropdown.setMkOption
|
||||
(mkFolderOption flags fs.items)
|
||||
model.folderModel
|
||||
}
|
||||
|
||||
mkIdName fitem =
|
||||
IdName fitem.id fitem.name
|
||||
|
||||
opts =
|
||||
fs.items
|
||||
|> List.map mkIdName
|
||||
|> Comp.Dropdown.SetOptions
|
||||
in
|
||||
update flags (FolderDropdownMsg opts) model_
|
||||
|
||||
GetFolderResp (Err _) ->
|
||||
resultNone model
|
||||
|
||||
DirDropdownMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.directionModel
|
||||
|
||||
newModel =
|
||||
{ model | directionModel = m2 }
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
let
|
||||
dir =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
in
|
||||
case dir of
|
||||
Just d ->
|
||||
DirectionChange d
|
||||
|
||||
Nothing ->
|
||||
NoFormChange
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
OrgDropdownMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.corrOrgModel
|
||||
|
||||
newModel =
|
||||
{ model | corrOrgModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
OrgChange idref
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
GetOrgResp (Ok orgs) ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions orgs.items
|
||||
in
|
||||
update flags (OrgDropdownMsg opts) model
|
||||
|
||||
GetOrgResp (Err _) ->
|
||||
resultNone model
|
||||
|
||||
CorrPersonMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.corrPersonModel
|
||||
|
||||
newModel =
|
||||
{ model | corrPersonModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
CorrPersonChange idref
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
ConcPersonMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.concPersonModel
|
||||
|
||||
newModel =
|
||||
{ model | concPersonModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
ConcPersonChange idref
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
GetPersonResp (Ok ps) ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions ps.items
|
||||
|
||||
res1 =
|
||||
update flags (CorrPersonMsg opts) model
|
||||
|
||||
res2 =
|
||||
update flags (ConcPersonMsg opts) res1.model
|
||||
in
|
||||
res2
|
||||
|
||||
GetPersonResp (Err _) ->
|
||||
resultNone model
|
||||
|
||||
ConcEquipMsg m ->
|
||||
let
|
||||
( m2, _ ) =
|
||||
Comp.Dropdown.update m model.concEquipModel
|
||||
|
||||
newModel =
|
||||
{ model | concEquipModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
change =
|
||||
if isDropdownChangeMsg m then
|
||||
EquipChange idref
|
||||
|
||||
else
|
||||
NoFormChange
|
||||
in
|
||||
resultNoCmd change newModel
|
||||
|
||||
GetEquipResp (Ok equips) ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions
|
||||
(List.map (\e -> IdName e.id e.name)
|
||||
equips.items
|
||||
)
|
||||
in
|
||||
update flags (ConcEquipMsg opts) model
|
||||
|
||||
GetEquipResp (Err _) ->
|
||||
resultNone model
|
||||
|
||||
ItemDatePickerMsg m ->
|
||||
let
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.itemDatePicker
|
||||
in
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
let
|
||||
newModel =
|
||||
{ model | itemDatePicker = dp, itemDate = Just (Comp.DatePicker.midOfDay date) }
|
||||
in
|
||||
resultNoCmd (ItemDateChange newModel.itemDate) newModel
|
||||
|
||||
_ ->
|
||||
resultNone { model | itemDatePicker = dp }
|
||||
|
||||
RemoveDate ->
|
||||
resultNoCmd (ItemDateChange Nothing) { model | itemDate = Nothing }
|
||||
|
||||
DueDatePickerMsg m ->
|
||||
let
|
||||
( dp, event ) =
|
||||
Comp.DatePicker.updateDefault m model.dueDatePicker
|
||||
in
|
||||
case event of
|
||||
DatePicker.Picked date ->
|
||||
let
|
||||
newModel =
|
||||
{ model | dueDatePicker = dp, dueDate = Just (Comp.DatePicker.midOfDay date) }
|
||||
in
|
||||
resultNoCmd (DueDateChange newModel.dueDate) newModel
|
||||
|
||||
_ ->
|
||||
resultNone { model | dueDatePicker = dp }
|
||||
|
||||
RemoveDueDate ->
|
||||
resultNoCmd (DueDateChange Nothing) { model | dueDate = Nothing }
|
||||
|
||||
SetName str ->
|
||||
case Util.Maybe.fromString str of
|
||||
Just newName ->
|
||||
let
|
||||
cmd_ =
|
||||
Task.succeed ()
|
||||
|> Task.perform (\_ -> SaveName)
|
||||
|
||||
( newThrottle, cmd ) =
|
||||
Throttle.try cmd_ model.nameSaveThrottle
|
||||
|
||||
newModel =
|
||||
{ model
|
||||
| nameSaveThrottle = newThrottle
|
||||
, nameModel = newName
|
||||
}
|
||||
|
||||
sub =
|
||||
nameThrottleSub newModel
|
||||
in
|
||||
UpdateResult newModel cmd sub NoFormChange
|
||||
|
||||
Nothing ->
|
||||
resultNone { model | nameModel = str }
|
||||
|
||||
SaveName ->
|
||||
case Util.Maybe.fromString model.nameModel of
|
||||
Just n ->
|
||||
resultNoCmd (NameChange n) model
|
||||
|
||||
Nothing ->
|
||||
resultNone model
|
||||
|
||||
UpdateThrottle ->
|
||||
let
|
||||
( newThrottle, cmd ) =
|
||||
Throttle.update model.nameSaveThrottle
|
||||
|
||||
newModel =
|
||||
{ model | nameSaveThrottle = newThrottle }
|
||||
|
||||
sub =
|
||||
nameThrottleSub newModel
|
||||
in
|
||||
UpdateResult newModel cmd sub NoFormChange
|
||||
|
||||
|
||||
nameThrottleSub : Model -> Sub Msg
|
||||
nameThrottleSub model =
|
||||
Throttle.ifNeeded
|
||||
(Time.every 400 (\_ -> UpdateThrottle))
|
||||
model.nameSaveThrottle
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
type alias ViewConfig =
|
||||
{ menuClass : String
|
||||
, nameState : SaveNameState
|
||||
}
|
||||
|
||||
|
||||
defaultViewConfig : ViewConfig
|
||||
defaultViewConfig =
|
||||
{ menuClass = "ui vertical segment"
|
||||
, nameState = SaveSuccess
|
||||
}
|
||||
|
||||
|
||||
view : ViewConfig -> UiSettings -> Model -> Html Msg
|
||||
view =
|
||||
renderEditForm
|
||||
|
||||
|
||||
renderEditForm : ViewConfig -> UiSettings -> Model -> Html Msg
|
||||
renderEditForm cfg settings model =
|
||||
let
|
||||
fieldVisible field =
|
||||
Data.UiSettings.fieldVisible settings field
|
||||
|
||||
optional fields html =
|
||||
if
|
||||
List.map fieldVisible fields
|
||||
|> List.foldl (||) False
|
||||
then
|
||||
html
|
||||
|
||||
else
|
||||
span [ class "invisible hidden" ] []
|
||||
in
|
||||
div [ class cfg.menuClass ]
|
||||
[ div [ class "ui form warning" ]
|
||||
[ optional [ Data.Fields.Tag ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.tagsIcon "grey"
|
||||
, text "Tags"
|
||||
]
|
||||
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
|
||||
]
|
||||
, div [ class " field" ]
|
||||
[ label [] [ text "Name" ]
|
||||
, div [ class "ui icon input" ]
|
||||
[ input [ type_ "text", value model.nameModel, onInput SetName ] []
|
||||
, i
|
||||
[ classList
|
||||
[ ( "green check icon", cfg.nameState == SaveSuccess )
|
||||
, ( "red exclamation triangle icon", cfg.nameState == SaveFailed )
|
||||
, ( "sync loading icon", cfg.nameState == Saving )
|
||||
]
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
, optional [ Data.Fields.Folder ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.folderIcon "grey"
|
||||
, text "Folder"
|
||||
]
|
||||
, Html.map FolderDropdownMsg (Comp.Dropdown.view settings model.folderModel)
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui warning message", True )
|
||||
, ( "hidden", isFolderMember model )
|
||||
]
|
||||
]
|
||||
[ Markdown.toHtml [] """
|
||||
You are **not a member** of this folder. This item will be **hidden**
|
||||
from any search now. Use a folder where you are a member of to make this
|
||||
item visible. This message will disappear then.
|
||||
"""
|
||||
]
|
||||
]
|
||||
, optional [ Data.Fields.Direction ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.directionIcon "grey"
|
||||
, text "Direction"
|
||||
]
|
||||
, Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel)
|
||||
]
|
||||
, optional [ Data.Fields.Date ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.dateIcon "grey"
|
||||
, text "Date"
|
||||
]
|
||||
, div [ class "ui action input" ]
|
||||
[ Html.map ItemDatePickerMsg
|
||||
(Comp.DatePicker.viewTime
|
||||
model.itemDate
|
||||
actionInputDatePicker
|
||||
model.itemDatePicker
|
||||
)
|
||||
, a [ class "ui icon button", href "", onClick RemoveDate ]
|
||||
[ i [ class "trash alternate outline icon" ] []
|
||||
]
|
||||
]
|
||||
]
|
||||
, optional [ Data.Fields.DueDate ] <|
|
||||
div [ class " field" ]
|
||||
[ label []
|
||||
[ Icons.dueDateIcon "grey"
|
||||
, text "Due Date"
|
||||
]
|
||||
, div [ class "ui action input" ]
|
||||
[ Html.map DueDatePickerMsg
|
||||
(Comp.DatePicker.viewTime
|
||||
model.dueDate
|
||||
actionInputDatePicker
|
||||
model.dueDatePicker
|
||||
)
|
||||
, a [ class "ui icon button", href "", onClick RemoveDueDate ]
|
||||
[ i [ class "trash alternate outline icon" ] [] ]
|
||||
]
|
||||
]
|
||||
, optional [ Data.Fields.CorrOrg, Data.Fields.CorrPerson ] <|
|
||||
h4 [ class "ui dividing header" ]
|
||||
[ Icons.correspondentIcon ""
|
||||
, text "Correspondent"
|
||||
]
|
||||
, optional [ Data.Fields.CorrOrg ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.organizationIcon "grey"
|
||||
, text "Organization"
|
||||
]
|
||||
, Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel)
|
||||
]
|
||||
, optional [ Data.Fields.CorrPerson ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.personIcon "grey"
|
||||
, text "Person"
|
||||
]
|
||||
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
|
||||
]
|
||||
, optional [ Data.Fields.ConcPerson, Data.Fields.ConcEquip ] <|
|
||||
h4 [ class "ui dividing header" ]
|
||||
[ Icons.concernedIcon
|
||||
, text "Concerning"
|
||||
]
|
||||
, optional [ Data.Fields.ConcPerson ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.personIcon "grey"
|
||||
, text "Person"
|
||||
]
|
||||
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
|
||||
]
|
||||
, optional [ Data.Fields.ConcEquip ] <|
|
||||
div [ class "field" ]
|
||||
[ label []
|
||||
[ Icons.equipmentIcon "grey"
|
||||
, text "Equipment"
|
||||
]
|
||||
, Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel)
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
actionInputDatePicker : DatePicker.Settings
|
||||
actionInputDatePicker =
|
||||
let
|
||||
ds =
|
||||
Comp.DatePicker.defaultSettings
|
||||
in
|
||||
{ ds | containerClassList = [ ( "ui action input", True ) ] }
|
44
modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm
Normal file
44
modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm
Normal file
@ -0,0 +1,44 @@
|
||||
module Comp.ItemDetail.FormChange exposing
|
||||
( FormChange(..)
|
||||
, multiUpdate
|
||||
)
|
||||
|
||||
import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Api.Model.ItemsAndRefs exposing (ItemsAndRefs)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Data.Direction exposing (Direction)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Http
|
||||
import Set exposing (Set)
|
||||
|
||||
|
||||
type FormChange
|
||||
= NoFormChange
|
||||
| TagChange ReferenceList
|
||||
| FolderChange (Maybe IdName)
|
||||
| DirectionChange Direction
|
||||
| OrgChange (Maybe IdName)
|
||||
| CorrPersonChange (Maybe IdName)
|
||||
| ConcPersonChange (Maybe IdName)
|
||||
| EquipChange (Maybe IdName)
|
||||
| ItemDateChange (Maybe Int)
|
||||
| DueDateChange (Maybe Int)
|
||||
| NameChange String
|
||||
|
||||
|
||||
multiUpdate :
|
||||
Flags
|
||||
-> Set String
|
||||
-> FormChange
|
||||
-> (Result Http.Error BasicResult -> msg)
|
||||
-> Cmd msg
|
||||
multiUpdate flags ids change receive =
|
||||
let
|
||||
items =
|
||||
Set.toList ids
|
||||
in
|
||||
case change of
|
||||
_ ->
|
||||
Cmd.none
|
@ -24,7 +24,6 @@ import File exposing (File)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onCheck, onClick, onInput)
|
||||
import Html5.DragDrop as DD
|
||||
import Markdown
|
||||
import Page exposing (Page(..))
|
||||
import Set
|
||||
|
@ -6,6 +6,8 @@ module Comp.YesNoDimmer exposing
|
||||
, defaultSettings
|
||||
, disable
|
||||
, emptyModel
|
||||
, initActive
|
||||
, initInactive
|
||||
, update
|
||||
, view
|
||||
, view2
|
||||
@ -27,6 +29,18 @@ emptyModel =
|
||||
}
|
||||
|
||||
|
||||
initInactive : Model
|
||||
initInactive =
|
||||
{ active = False
|
||||
}
|
||||
|
||||
|
||||
initActive : Model
|
||||
initActive =
|
||||
{ active = True
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Activate
|
||||
| Disable
|
||||
@ -40,6 +54,7 @@ type alias Settings =
|
||||
, confirmButton : String
|
||||
, cancelButton : String
|
||||
, invertedDimmer : Bool
|
||||
, extraClass : String
|
||||
}
|
||||
|
||||
|
||||
@ -51,6 +66,7 @@ defaultSettings =
|
||||
, confirmButton = "Yes, do it!"
|
||||
, cancelButton = "No"
|
||||
, invertedDimmer = False
|
||||
, extraClass = ""
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +103,7 @@ view2 active settings model =
|
||||
div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( settings.extraClass, True )
|
||||
, ( "inverted", settings.invertedDimmer )
|
||||
, ( "active", active && model.active )
|
||||
]
|
||||
|
Reference in New Issue
Block a user