Allow to hide fields in menus based on ui settings

This commit is contained in:
Eike Kettner 2020-08-08 22:44:45 +02:00
parent 795b8edb51
commit e793b63248
6 changed files with 535 additions and 187 deletions

View File

@ -0,0 +1,69 @@
module Comp.FieldListSelect exposing (..)
import Data.Fields exposing (Field)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck)
type alias Model =
List Field
type Msg
= Toggle Field
--- Update
update : Msg -> Model -> Model
update msg model =
case msg of
Toggle field ->
if List.member field model then
removeField model field
else
addField model field
removeField : Model -> Field -> Model
removeField selected field =
List.filter (\f -> f /= field) selected
|> Data.Fields.sort
addField : Model -> Field -> Model
addField selected field =
Data.Fields.sort (field :: selected)
--- View
view : Model -> Html Msg
view selected =
div [ class "grouped fields" ]
(List.map (fieldCheckbox selected) Data.Fields.all)
fieldCheckbox : Model -> Field -> Html Msg
fieldCheckbox selected field =
let
isChecked =
List.member field selected
in
div [ class "field" ]
[ div [ class "ui checkbox" ]
[ input
[ type_ "checkbox"
, checked isChecked
, onCheck (\_ -> Toggle field)
]
[]
, label [] [ text (Data.Fields.label field) ]
]
]

View File

@ -13,6 +13,7 @@ import Comp.MarkdownInput
import Comp.SentMails
import Comp.YesNoDimmer
import Data.Direction
import Data.Fields exposing (Field)
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings)
import DatePicker
@ -754,17 +755,34 @@ renderEditForm settings model =
]
[ i [ class "grey pencil alternate link icon" ] []
]
fieldVisible field =
Data.UiSettings.fieldVisible settings field
fieldHidden field =
Data.UiSettings.fieldHidden settings field
optional fields html =
if
List.map fieldVisible fields
|> List.foldl (||) False
then
html
else
span [ class "invisible hidden" ] []
in
div [ class "ui attached segment" ]
[ div [ class "ui form warning" ]
[ div [ class "field" ]
[ label []
[ Icons.tagsIcon "grey"
, text "Tags"
, addIconLink "Add new tag" StartTagModal
[ optional [ Data.Fields.Tag ] <|
div [ class "field" ]
[ label []
[ Icons.tagsIcon "grey"
, text "Tags"
, addIconLink "Add new tag" StartTagModal
]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
]
, div [ class " field" ]
[ label [] [ text "Name" ]
, div [ class "ui action input" ]
@ -777,121 +795,131 @@ renderEditForm settings model =
]
]
]
, 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 )
, optional [ Data.Fields.Folder ] <|
div [ class "field" ]
[ label []
[ Icons.folderIcon "grey"
, text "Folder"
]
]
[ Markdown.toHtml [] """
, 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.
"""
]
]
, div [ class "field" ]
[ label []
[ Icons.directionIcon "grey"
, text "Direction"
]
, Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel)
]
, 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" ] []
]
]
, renderItemDateSuggestions model
]
, div [ class " field" ]
[ label []
[ Icons.dueDateIcon "grey"
, text "Due Date"
, optional [ Data.Fields.Direction ] <|
div [ class "field" ]
[ label []
[ Icons.directionIcon "grey"
, text "Direction"
]
, Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel)
]
, 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.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" ] []
]
]
, renderItemDateSuggestions model
]
, renderDueDateSuggestions model
]
, h4 [ class "ui dividing header" ]
[ Icons.correspondentIcon ""
, text "Correspondent"
]
, div [ class "field" ]
[ label []
[ Icons.organizationIcon "grey"
, text "Organization"
, addIconLink "Add new organization" StartCorrOrgModal
, editIconLink "Edit organization" model.corrOrgModel StartEditCorrOrgModal
, 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" ] [] ]
]
, renderDueDateSuggestions model
]
, Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel)
, renderOrgSuggestions model
]
, div [ class "field" ]
[ label []
[ Icons.personIcon "grey"
, text "Person"
, addIconLink "Add new correspondent person" StartCorrPersonModal
, editIconLink "Edit person"
model.corrPersonModel
(StartEditPersonModal model.corrPersonModel)
, optional [ Data.Fields.CorrOrg, Data.Fields.CorrPerson ] <|
h4 [ class "ui dividing header" ]
[ Icons.correspondentIcon ""
, text "Correspondent"
]
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
, renderCorrPersonSuggestions model
]
, h4 [ class "ui dividing header" ]
[ Icons.concernedIcon
, text "Concerning"
]
, div [ class "field" ]
[ label []
[ Icons.personIcon "grey"
, text "Person"
, addIconLink "Add new concerning person" StartConcPersonModal
, editIconLink "Edit person"
model.concPersonModel
(StartEditPersonModal model.concPersonModel)
, optional [ Data.Fields.CorrOrg ] <|
div [ class "field" ]
[ label []
[ Icons.organizationIcon "grey"
, text "Organization"
, addIconLink "Add new organization" StartCorrOrgModal
, editIconLink "Edit organization" model.corrOrgModel StartEditCorrOrgModal
]
, Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel)
, renderOrgSuggestions model
]
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
, renderConcPersonSuggestions model
]
, div [ class "field" ]
[ label []
[ Icons.equipmentIcon "grey"
, text "Equipment"
, addIconLink "Add new equipment" StartEquipModal
, editIconLink "Edit equipment"
model.concEquipModel
StartEditEquipModal
, optional [ Data.Fields.CorrPerson ] <|
div [ class "field" ]
[ label []
[ Icons.personIcon "grey"
, text "Person"
, addIconLink "Add new correspondent person" StartCorrPersonModal
, editIconLink "Edit person"
model.corrPersonModel
(StartEditPersonModal model.corrPersonModel)
]
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
, renderCorrPersonSuggestions model
]
, 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"
, addIconLink "Add new concerning person" StartConcPersonModal
, editIconLink "Edit person"
model.concPersonModel
(StartEditPersonModal model.concPersonModel)
]
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
, renderConcPersonSuggestions model
]
, optional [ Data.Fields.ConcEquip ] <|
div [ class "field" ]
[ label []
[ Icons.equipmentIcon "grey"
, text "Equipment"
, addIconLink "Add new equipment" StartEquipModal
, editIconLink "Edit equipment"
model.concEquipModel
StartEditEquipModal
]
, Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel)
, renderConcEquipSuggestions model
]
, Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel)
, renderConcEquipSuggestions model
]
]
]

View File

@ -24,6 +24,7 @@ import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.FolderSelect
import Comp.TagSelect
import Data.Direction exposing (Direction)
import Data.Fields
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings)
@ -625,6 +626,22 @@ viewDrop ddd flags settings model =
segmentClass =
"ui vertical segment"
fieldVisible field =
Data.UiSettings.fieldVisible settings field
fieldHidden field =
Data.UiSettings.fieldHidden settings field
optional fields html =
if
List.map fieldVisible fields
|> List.foldl (||) False
then
html
else
span [ class "invisible hidden" ] []
in
div [ class "ui form" ]
[ div [ class segmentClass ]
@ -642,41 +659,68 @@ viewDrop ddd flags settings model =
]
]
]
, div [ class segmentClass ]
[ Html.map TagSelectMsg (Comp.TagSelect.viewTagsDrop ddd.model settings model.tagSelectModel)
, Html.map TagSelectMsg (Comp.TagSelect.viewCats settings model.tagSelectModel)
, Html.map FolderSelectMsg
(Comp.FolderSelect.viewDrop ddd.model settings.searchMenuFolderCount model.folderList)
, div
[ classList
[ ( segmentClass, True )
, ( "invisible hidden", fieldHidden Data.Fields.Tag && fieldHidden Data.Fields.Folder )
]
]
, div [ class segmentClass ]
[ formHeader (Icons.correspondentIcon "")
(case getDirection model of
Just Data.Direction.Incoming ->
"Sender"
[ optional [ Data.Fields.Tag ] <|
Html.map TagSelectMsg (Comp.TagSelect.viewTagsDrop ddd.model settings model.tagSelectModel)
, optional [ Data.Fields.Tag ] <|
Html.map TagSelectMsg (Comp.TagSelect.viewCats settings model.tagSelectModel)
, optional [ Data.Fields.Folder ] <|
Html.map FolderSelectMsg
(Comp.FolderSelect.viewDrop ddd.model settings.searchMenuFolderCount model.folderList)
]
, div
[ classList
[ ( segmentClass, True )
, ( "hidden invisible", fieldHidden Data.Fields.CorrOrg && fieldHidden Data.Fields.CorrPerson )
]
]
[ optional
[ Data.Fields.CorrOrg
, Data.Fields.CorrPerson
]
<|
formHeader (Icons.correspondentIcon "")
(case getDirection model of
Just Data.Direction.Incoming ->
"Sender"
Just Data.Direction.Outgoing ->
"Recipient"
Just Data.Direction.Outgoing ->
"Recipient"
Nothing ->
"Correspondent"
)
, div [ class "field" ]
[ label [] [ text "Organization" ]
, Html.map OrgMsg (Comp.Dropdown.view settings model.orgModel)
]
, div [ class "field" ]
[ label [] [ text "Person" ]
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
]
, formHeader Icons.concernedIcon "Concerned"
, div [ class "field" ]
[ label [] [ text "Person" ]
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
]
, div [ class "field" ]
[ label [] [ text "Equipment" ]
, Html.map ConcEquipmentMsg (Comp.Dropdown.view settings model.concEquipmentModel)
Nothing ->
"Correspondent"
)
, optional [ Data.Fields.CorrOrg ] <|
div [ class "field" ]
[ label [] [ text "Organization" ]
, Html.map OrgMsg (Comp.Dropdown.view settings model.orgModel)
]
, optional [ Data.Fields.CorrPerson ] <|
div [ class "field" ]
[ label [] [ text "Person" ]
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
]
, optional
[ Data.Fields.ConcPerson
, Data.Fields.ConcEquip
]
<|
formHeader Icons.concernedIcon "Concerned"
, optional [ Data.Fields.ConcPerson ] <|
div [ class "field" ]
[ label [] [ text "Person" ]
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
]
, optional [ Data.Fields.ConcEquip ] <|
div [ class "field" ]
[ label [] [ text "Equipment" ]
, Html.map ConcEquipmentMsg (Comp.Dropdown.view settings model.concEquipmentModel)
]
]
, div [ class segmentClass ]
[ formHeader (Icons.searchIcon "") "Text Search"
@ -740,55 +784,69 @@ viewDrop ddd flags settings model =
]
]
]
, div [ class segmentClass ]
[ formHeader (Icons.dateIcon "") "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
)
]
]
, formHeader (Icons.dueDateIcon "") "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
[ classList
[ ( segmentClass, True )
, ( "invisible hidden", fieldHidden Data.Fields.Date && fieldHidden Data.Fields.DueDate )
]
]
[ optional [ Data.Fields.Date ] <|
formHeader (Icons.dateIcon "") "Date"
, optional [ Data.Fields.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
)
]
]
, optional [ Data.Fields.DueDate ] <|
formHeader (Icons.dueDateIcon "") "Due Date"
, optional [ Data.Fields.DueDate ] <|
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
[ classList
[ ( segmentClass, True )
, ( "invisible hidden", fieldHidden Data.Fields.Direction )
]
]
, div [ class segmentClass ]
[ formHeader (Icons.directionIcon "") "Direction"
, div [ class "field" ]
[ Html.map DirectionMsg (Comp.Dropdown.view settings model.directionModel)

View File

@ -9,8 +9,10 @@ module Comp.UiSettingsForm exposing
import Api
import Api.Model.TagList exposing (TagList)
import Comp.ColorTagger
import Comp.FieldListSelect
import Comp.IntField
import Data.Color exposing (Color)
import Data.Fields exposing (Field)
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (Pos(..), UiSettings)
import Dict exposing (Dict)
@ -36,6 +38,7 @@ type alias Model =
, searchMenuTagCountModel : Comp.IntField.Model
, searchMenuTagCatCount : Maybe Int
, searchMenuTagCatCountModel : Comp.IntField.Model
, formFields : List Field
}
@ -83,6 +86,7 @@ init flags settings =
(Just 2000)
False
"Number of categories in search menu"
, formFields = settings.formFields
}
, Api.getTags flags "" GetTagsResp
)
@ -98,6 +102,7 @@ type Msg
| SearchMenuFolderMsg Comp.IntField.Msg
| SearchMenuTagMsg Comp.IntField.Msg
| SearchMenuTagCatMsg Comp.IntField.Msg
| FieldListMsg Comp.FieldListSelect.Msg
@ -240,6 +245,22 @@ update sett msg model =
GetTagsResp (Err _) ->
( model, Nothing )
FieldListMsg lm ->
let
selected =
Comp.FieldListSelect.update lm model.formFields
newSettings =
{ sett | formFields = selected }
in
( { model | formFields = selected }
, if selected /= model.formFields then
Just newSettings
else
Nothing
)
--- View
@ -355,4 +376,11 @@ view flags _ model =
tagColorViewOpts
model.tagColorModel
)
, div [ class "ui dividing header" ]
[ text "Fields"
]
, span [ class "small-info" ]
[ text "Choose which fields to display in search and edit menus."
]
, Html.map FieldListMsg (Comp.FieldListSelect.view model.formFields)
]

View File

@ -0,0 +1,142 @@
module Data.Fields exposing
( Field(..)
, all
, fromList
, fromString
, label
, sort
, toString
)
type Field
= Tag
| Folder
| CorrOrg
| CorrPerson
| ConcPerson
| ConcEquip
| Date
| DueDate
| Direction
all : List Field
all =
sort
[ Tag
, Folder
, CorrOrg
, CorrPerson
, ConcPerson
, ConcEquip
, Date
, DueDate
, Direction
]
sort : List Field -> List Field
sort fields =
List.sortBy toString fields
fromString : String -> Maybe Field
fromString str =
case String.toLower str of
"tag" ->
Just Tag
"folder" ->
Just Folder
"corrorg" ->
Just CorrOrg
"corrperson" ->
Just CorrPerson
"concperson" ->
Just ConcPerson
"concequip" ->
Just ConcEquip
"date" ->
Just Date
"duedate" ->
Just DueDate
"direction" ->
Just Direction
_ ->
Nothing
toString : Field -> String
toString field =
case field of
Tag ->
"tag"
Folder ->
"folder"
CorrOrg ->
"corrorg"
CorrPerson ->
"corrperson"
ConcPerson ->
"concperson"
ConcEquip ->
"concequip"
Date ->
"date"
DueDate ->
"duedate"
Direction ->
"direction"
label : Field -> String
label field =
case field of
Tag ->
"Tag"
Folder ->
"Folder"
CorrOrg ->
"Correspondent Organization"
CorrPerson ->
"Correspondent Person"
ConcPerson ->
"Concerning Person"
ConcEquip ->
"Concerned Equipment"
Date ->
"Date"
DueDate ->
"Due Date"
Direction ->
"Direction"
fromList : List String -> List Field
fromList strings =
List.filterMap fromString strings

View File

@ -5,6 +5,8 @@ module Data.UiSettings exposing
, catColor
, catColorString
, defaults
, fieldHidden
, fieldVisible
, merge
, mergeDefaults
, posFromString
@ -16,6 +18,7 @@ module Data.UiSettings exposing
import Api.Model.Tag exposing (Tag)
import Data.Color exposing (Color)
import Data.Fields exposing (Field)
import Dict exposing (Dict)
@ -36,6 +39,7 @@ type alias StoredUiSettings =
, searchMenuFolderCount : Maybe Int
, searchMenuTagCount : Maybe Int
, searchMenuTagCatCount : Maybe Int
, formFields : Maybe (List String)
}
@ -55,6 +59,7 @@ type alias UiSettings =
, searchMenuFolderCount : Int
, searchMenuTagCount : Int
, searchMenuTagCatCount : Int
, formFields : List Field
}
@ -96,6 +101,7 @@ defaults =
, searchMenuFolderCount = 3
, searchMenuTagCount = 6
, searchMenuTagCatCount = 3
, formFields = Data.Fields.all
}
@ -124,6 +130,10 @@ merge given fallback =
choose given.searchMenuTagCount fallback.searchMenuTagCount
, searchMenuTagCatCount =
choose given.searchMenuTagCatCount fallback.searchMenuTagCatCount
, formFields =
choose
(Maybe.map Data.Fields.fromList given.formFields)
fallback.formFields
}
@ -144,6 +154,9 @@ toStoredUiSettings settings =
, searchMenuFolderCount = Just settings.searchMenuFolderCount
, searchMenuTagCount = Just settings.searchMenuTagCount
, searchMenuTagCatCount = Just settings.searchMenuTagCatCount
, formFields =
List.map Data.Fields.toString settings.formFields
|> Just
}
@ -171,6 +184,16 @@ tagColorString tag settings =
|> Maybe.withDefault ""
fieldVisible : UiSettings -> Field -> Bool
fieldVisible settings field =
List.member field settings.formFields
fieldHidden : UiSettings -> Field -> Bool
fieldHidden settings field =
fieldVisible settings field |> not
--- Helpers