Eike Kettner 04ba14f802 Amend source form with tags and file-filter
Allow to define tags and a file filter per source.
2020-11-12 22:37:28 +01:00

413 lines
12 KiB
Elm

module Comp.SourceForm exposing
( Model
, Msg(..)
, getSource
, init
, isValid
, update
, view
)
import Api
import Api.Model.FolderItem exposing (FolderItem)
import Api.Model.FolderList exposing (FolderList)
import Api.Model.IdName exposing (IdName)
import Api.Model.SourceAndTags exposing (SourceAndTags)
import Api.Model.Tag exposing (Tag)
import Api.Model.TagList exposing (TagList)
import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.FixedDropdown
import Data.Flags exposing (Flags)
import Data.Priority exposing (Priority)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onInput)
import Http
import Markdown
import Util.Folder exposing (mkFolderOption)
import Util.Maybe
import Util.Tag
import Util.Update
type alias Model =
{ source : SourceAndTags
, abbrev : String
, description : Maybe String
, priorityModel : Comp.FixedDropdown.Model Priority
, priority : Priority
, enabled : Bool
, folderModel : Comp.Dropdown.Model IdName
, allFolders : List FolderItem
, folderId : Maybe String
, tagModel : Comp.Dropdown.Model Tag
, fileFilter : Maybe String
}
emptyModel : Model
emptyModel =
{ source = Api.Model.SourceAndTags.empty
, abbrev = ""
, description = Nothing
, priorityModel =
Comp.FixedDropdown.initMap
Data.Priority.toName
Data.Priority.all
, priority = Data.Priority.Low
, enabled = False
, folderModel =
Comp.Dropdown.makeSingle
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
, placeholder = ""
}
, allFolders = []
, folderId = Nothing
, tagModel = Util.Tag.makeDropdownModel
, fileFilter = Nothing
}
init : Flags -> ( Model, Cmd Msg )
init flags =
( emptyModel
, Cmd.batch
[ Api.getFolders flags "" False GetFolderResp
, Api.getTags flags "" GetTagResp
]
)
isValid : Model -> Bool
isValid model =
model.abbrev /= ""
getSource : Model -> SourceAndTags
getSource model =
let
st =
model.source
s =
st.source
tags =
Comp.Dropdown.getSelected model.tagModel
n =
{ s
| abbrev = model.abbrev
, description = model.description
, enabled = model.enabled
, priority = Data.Priority.toName model.priority
, folder = model.folderId
, fileFilter = model.fileFilter
}
in
{ st | source = n, tags = TagList (List.length tags) tags }
type Msg
= SetAbbrev String
| SetSource SourceAndTags
| SetDescr String
| ToggleEnabled
| PrioDropdownMsg (Comp.FixedDropdown.Msg Priority)
| GetFolderResp (Result Http.Error FolderList)
| FolderDropdownMsg (Comp.Dropdown.Msg IdName)
| GetTagResp (Result Http.Error TagList)
| TagDropdownMsg (Comp.Dropdown.Msg Tag)
| SetFileFilter String
--- Update
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
update flags msg model =
case msg of
SetSource t ->
let
stpost =
model.source
post =
stpost.source
np =
{ post
| id = t.source.id
, abbrev = t.source.abbrev
, description = t.source.description
, priority = t.source.priority
, enabled = t.source.enabled
, folder = t.source.folder
, fileFilter = t.source.fileFilter
}
newModel =
{ model
| source = { stpost | source = np }
, abbrev = t.source.abbrev
, description = t.source.description
, priority =
Data.Priority.fromString t.source.priority
|> Maybe.withDefault Data.Priority.Low
, enabled = t.source.enabled
, folderId = t.source.folder
, fileFilter = t.source.fileFilter
}
mkIdName id =
List.filterMap
(\f ->
if f.id == id then
Just (IdName id f.name)
else
Nothing
)
model.allFolders
sel =
case Maybe.map mkIdName t.source.folder of
Just idref ->
idref
Nothing ->
[]
tags =
Comp.Dropdown.SetSelection t.tags.items
in
Util.Update.andThen1
[ update flags (FolderDropdownMsg (Comp.Dropdown.SetSelection sel))
, update flags (TagDropdownMsg tags)
]
newModel
ToggleEnabled ->
( { model | enabled = not model.enabled }, Cmd.none )
SetAbbrev n ->
( { model | abbrev = n }, Cmd.none )
SetDescr d ->
( { model | description = Util.Maybe.fromString d }
, Cmd.none
)
PrioDropdownMsg m ->
let
( m2, p2 ) =
Comp.FixedDropdown.update m model.priorityModel
in
( { model
| priorityModel = m2
, priority = Maybe.withDefault model.priority p2
}
, Cmd.none
)
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 _) ->
( model, Cmd.none )
FolderDropdownMsg m ->
let
( m2, c2 ) =
Comp.Dropdown.update m model.folderModel
newModel =
{ model | folderModel = m2 }
idref =
Comp.Dropdown.getSelected m2 |> List.head
model_ =
if isDropdownChangeMsg m then
{ newModel | folderId = Maybe.map .id idref }
else
newModel
in
( model_, Cmd.map FolderDropdownMsg c2 )
GetTagResp (Ok list) ->
let
opts =
Comp.Dropdown.SetOptions list.items
in
update flags (TagDropdownMsg opts) model
GetTagResp (Err _) ->
( model, Cmd.none )
TagDropdownMsg lm ->
let
( m2, c2 ) =
Comp.Dropdown.update lm model.tagModel
newModel =
{ model | tagModel = m2 }
in
( newModel, Cmd.map TagDropdownMsg c2 )
SetFileFilter d ->
( { model | fileFilter = Util.Maybe.fromString d }
, Cmd.none
)
--- View
view : Flags -> UiSettings -> Model -> Html Msg
view flags settings model =
let
priorityItem =
Comp.FixedDropdown.Item
model.priority
(Data.Priority.toName model.priority)
in
div [ class "ui warning 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 "" |> value
, rows 3
]
[]
]
, 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.FixedDropdown.view
(Just priorityItem)
model.priorityModel
)
, div [ class "small-info" ]
[ text "The priority used by the scheduler when processing uploaded files."
]
]
, div [ class "ui dividing header" ]
[ text "Metadata"
]
, div [ class "ui message" ]
[ text "Metadata specified here is automatically attached to each item uploaded "
, text "through this source, unless it is overriden in the upload request meta data. "
, text "Tags from the request are added to those defined here."
]
, div [ class "field" ]
[ label []
[ text "Folder"
]
, Html.map FolderDropdownMsg (Comp.Dropdown.view settings model.folderModel)
, div [ class "small-info" ]
[ text "Choose a folder to automatically put items into."
]
, div
[ classList
[ ( "ui warning message", True )
, ( "hidden", isFolderMember model )
]
]
[ Markdown.toHtml [] """
You are **not a member** of this folder. Items created through this
link will be **hidden** from any search results. Use a folder where
you are a member of to make items visible. This message will
disappear then.
"""
]
]
, div [ class "field" ]
[ label [] [ text "Tags" ]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
, div [ class "small-info" ]
[ text "Choose tags that should be applied to items."
]
]
, div
[ class "field"
]
[ label [] [ text "File Filter" ]
, input
[ type_ "text"
, onInput SetFileFilter
, placeholder "File Filter"
, model.fileFilter
|> Maybe.withDefault ""
|> value
]
[]
, div [ class "small-info" ]
[ text "Specify a file glob to filter files when uploading archives (e.g. for email and zip). For example, to only extract pdf files: "
, code []
[ text "*.pdf"
]
]
]
]
isFolderMember : Model -> Bool
isFolderMember model =
let
selected =
Comp.Dropdown.getSelected model.folderModel
|> List.head
|> Maybe.map .id
in
Util.Folder.isFolderMember model.allFolders selected