Merge pull request #437 from eikek/upload-improvements

Upload improvements
This commit is contained in:
mergify[bot]
2020-11-12 22:58:08 +00:00
committed by GitHub
35 changed files with 1081 additions and 191 deletions

View File

@ -15,6 +15,9 @@ import Api.Model.FolderList exposing (FolderList)
import Api.Model.IdName exposing (IdName)
import Api.Model.ImapSettingsList exposing (ImapSettingsList)
import Api.Model.ScanMailboxSettings exposing (ScanMailboxSettings)
import Api.Model.StringList exposing (StringList)
import Api.Model.Tag exposing (Tag)
import Api.Model.TagList exposing (TagList)
import Comp.CalEventInput
import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.IntField
@ -34,6 +37,7 @@ import Util.Folder exposing (mkFolderOption)
import Util.Http
import Util.List
import Util.Maybe
import Util.Tag
import Util.Update
@ -56,6 +60,9 @@ type alias Model =
, folderModel : Comp.Dropdown.Model IdName
, allFolders : List FolderItem
, itemFolderId : Maybe String
, tagModel : Comp.Dropdown.Model Tag
, existingTags : List String
, fileFilter : Maybe String
}
@ -84,6 +91,9 @@ type Msg
| YesNoDeleteMsg Comp.YesNoDimmer.Msg
| GetFolderResp (Result Http.Error FolderList)
| FolderDropdownMsg (Comp.Dropdown.Msg IdName)
| GetTagResp (Result Http.Error TagList)
| TagDropdownMsg (Comp.Dropdown.Msg Tag)
| SetFileFilter String
initWith : Flags -> ScanMailboxSettings -> ( Model, Cmd Msg )
@ -120,12 +130,18 @@ initWith flags s =
, formMsg = Nothing
, yesNoDelete = Comp.YesNoDimmer.emptyModel
, itemFolderId = s.itemFolder
, tagModel = Util.Tag.makeDropdownModel
, existingTags =
Maybe.map .items s.tags
|> Maybe.withDefault []
, fileFilter = s.fileFilter
}
, Cmd.batch
[ Api.getImapSettings flags "" ConnResp
, nc
, Cmd.map CalEventMsg sc
, Api.getFolders flags "" False GetFolderResp
, Api.getTags flags "" GetTagResp
]
)
@ -134,7 +150,7 @@ init : Flags -> ( Model, Cmd Msg )
init flags =
let
initialSchedule =
Data.Validated.Unknown Data.CalEvent.everyMonth
Data.Validated.Valid Data.CalEvent.everyMonth
sm =
Comp.CalEventInput.initDefault
@ -156,7 +172,7 @@ init flags =
, schedule = initialSchedule
, scheduleModel = sm
, formMsg = Nothing
, loading = 2
, loading = 3
, yesNoDelete = Comp.YesNoDimmer.emptyModel
, folderModel =
Comp.Dropdown.makeSingle
@ -165,10 +181,14 @@ init flags =
}
, allFolders = []
, itemFolderId = Nothing
, tagModel = Util.Tag.makeDropdownModel
, existingTags = []
, fileFilter = Nothing
}
, Cmd.batch
[ Api.getImapSettings flags "" ConnResp
, Api.getFolders flags "" False GetFolderResp
, Api.getTags flags "" GetTagResp
]
)
@ -196,9 +216,9 @@ makeSettings model =
else
Valid model.folders
make smtp timer folders =
make imap timer folders =
{ prev
| imapConnection = smtp
| imapConnection = imap
, enabled = model.enabled
, receivedSinceHours = model.receivedHours
, deleteMail = model.deleteMail
@ -207,6 +227,16 @@ makeSettings model =
, direction = Maybe.map Data.Direction.toString model.direction
, schedule = Data.CalEvent.makeEvent timer
, itemFolder = model.itemFolderId
, fileFilter = model.fileFilter
, tags =
case Comp.Dropdown.getSelected model.tagModel of
[] ->
Nothing
els ->
List.map .id els
|> StringList
|> Just
}
in
Data.Validated.map3 make
@ -501,6 +531,61 @@ update flags msg model =
in
( model_, NoAction, Cmd.map FolderDropdownMsg c2 )
GetTagResp (Ok list) ->
let
contains el =
List.member el model.existingTags
isExistingTag t =
contains t.id || contains t.name
selected =
List.filter isExistingTag list.items
|> Comp.Dropdown.SetSelection
opts =
Comp.Dropdown.SetOptions list.items
( tagModel_, tagcmd ) =
Util.Update.andThen1
[ Comp.Dropdown.update selected
, Comp.Dropdown.update opts
]
model.tagModel
nextModel =
{ model
| loading = model.loading - 1
, tagModel = tagModel_
}
in
( nextModel
, NoAction
, Cmd.map TagDropdownMsg tagcmd
)
GetTagResp (Err _) ->
( { model | loading = model.loading - 1 }
, NoAction
, Cmd.none
)
TagDropdownMsg lm ->
let
( m2, c2 ) =
Comp.Dropdown.update lm model.tagModel
newModel =
{ model | tagModel = m2 }
in
( newModel, NoAction, Cmd.map TagDropdownMsg c2 )
SetFileFilter str ->
( { model | fileFilter = Util.Maybe.fromString str }
, NoAction
, Cmd.none
)
--- View
@ -603,6 +688,9 @@ view extraClasses settings model =
, text " is not set."
]
]
, div [ class "ui dividing header" ]
[ text "Metadata"
]
, div [ class "required field" ]
[ label [] [ text "Item direction" ]
, div [ class "grouped fields" ]
@ -668,6 +756,49 @@ 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 attachments. For example, to only extract pdf files: "
, code []
[ text "*.pdf"
]
, text ". If you want to include the mail body, allow html files or "
, code []
[ text "mail.html"
]
, text ". Globs can be combined via OR, like this: "
, code []
[ text "*.pdf|mail.html"
]
, text "No file filter defaults to "
, code []
[ text "*"
]
, text " that includes all"
]
]
, div [ class "ui dividing header" ]
[ text "Schedule"
]
, div [ class "required field" ]
[ label []
[ text "Schedule"

View File

@ -12,7 +12,9 @@ import Api
import Api.Model.FolderItem exposing (FolderItem)
import Api.Model.FolderList exposing (FolderList)
import Api.Model.IdName exposing (IdName)
import Api.Model.Source exposing (Source)
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)
@ -24,10 +26,13 @@ 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 : Source
{ source : SourceAndTags
, abbrev : String
, description : Maybe String
, priorityModel : Comp.FixedDropdown.Model Priority
@ -36,12 +41,14 @@ type alias Model =
, 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.Source.empty
{ source = Api.Model.SourceAndTags.empty
, abbrev = ""
, description = Nothing
, priorityModel =
@ -57,13 +64,18 @@ emptyModel =
}
, allFolders = []
, folderId = Nothing
, tagModel = Util.Tag.makeDropdownModel
, fileFilter = Nothing
}
init : Flags -> ( Model, Cmd Msg )
init flags =
( emptyModel
, Api.getFolders flags "" False GetFolderResp
, Cmd.batch
[ Api.getFolders flags "" False GetFolderResp
, Api.getTags flags "" GetTagResp
]
)
@ -72,29 +84,42 @@ isValid model =
model.abbrev /= ""
getSource : Model -> Source
getSource : Model -> SourceAndTags
getSource model =
let
s =
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
{ s
| abbrev = model.abbrev
, description = model.description
, enabled = model.enabled
, priority = Data.Priority.toName model.priority
, folder = model.folderId
}
{ st | source = n, tags = TagList (List.length tags) tags }
type Msg
= SetAbbrev String
| SetSource Source
| 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
@ -106,29 +131,34 @@ update flags msg model =
case msg of
SetSource t ->
let
post =
stpost =
model.source
post =
stpost.source
np =
{ post
| id = t.id
, abbrev = t.abbrev
, description = t.description
, priority = t.priority
, enabled = t.enabled
, folder = t.folder
| 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 = np
, abbrev = t.abbrev
, description = t.description
| source = { stpost | source = np }
, abbrev = t.source.abbrev
, description = t.source.description
, priority =
Data.Priority.fromString t.priority
Data.Priority.fromString t.source.priority
|> Maybe.withDefault Data.Priority.Low
, enabled = t.enabled
, folderId = t.folder
, enabled = t.source.enabled
, folderId = t.source.folder
, fileFilter = t.source.fileFilter
}
mkIdName id =
@ -143,14 +173,21 @@ update flags msg model =
model.allFolders
sel =
case Maybe.map mkIdName t.folder of
case Maybe.map mkIdName t.source.folder of
Just idref ->
idref
Nothing ->
[]
tags =
Comp.Dropdown.SetSelection t.tags.items
in
update flags (FolderDropdownMsg (Comp.Dropdown.SetSelection sel)) newModel
Util.Update.andThen1
[ update flags (FolderDropdownMsg (Comp.Dropdown.SetSelection sel))
, update flags (TagDropdownMsg tags)
]
newModel
ToggleEnabled ->
( { model | enabled = not model.enabled }, Cmd.none )
@ -159,14 +196,7 @@ update flags msg model =
( { model | abbrev = n }, Cmd.none )
SetDescr d ->
( { model
| description =
if d /= "" then
Just d
else
Nothing
}
( { model | description = Util.Maybe.fromString d }
, Cmd.none
)
@ -226,6 +256,31 @@ update flags msg model =
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
@ -260,6 +315,7 @@ view flags settings model =
, textarea
[ onInput SetDescr
, model.description |> Maybe.withDefault "" |> value
, rows 3
]
[]
]
@ -281,12 +337,26 @@ view flags settings model =
(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 )
@ -301,6 +371,38 @@ 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 "
, text "(e.g. for email and zip). For example, to only extract pdf files: "
, code []
[ text "*.pdf"
]
, text ". Globs can be combined via OR, like this: "
, code []
[ text "*.pdf|mail.html"
]
]
]
]

View File

@ -8,8 +8,9 @@ module Comp.SourceManage exposing
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.Source exposing (Source)
import Api.Model.SourceAndTags exposing (SourceAndTags)
import Api.Model.SourceList exposing (SourceList)
import Api.Model.SourceTagIn exposing (SourceTagIn)
import Comp.SourceForm
import Comp.SourceTable exposing (SelectMode(..))
import Comp.YesNoDimmer
@ -31,7 +32,7 @@ type alias Model =
, formError : Maybe String
, loading : Bool
, deleteConfirm : Comp.YesNoDimmer.Model
, sources : List Source
, sources : List SourceAndTags
}
@ -145,7 +146,7 @@ update flags msg model =
InitNewSource ->
let
source =
Api.Model.Source.empty
Api.Model.SourceAndTags.empty
nm =
{ model | viewMode = Edit source, formError = Nothing }
@ -196,7 +197,7 @@ update flags msg model =
cmd =
if confirmed then
Api.deleteSource flags src.id SubmitResp
Api.deleteSource flags src.source.id SubmitResp
else
Cmd.none
@ -248,22 +249,22 @@ viewTable model =
]
viewLinks : Flags -> UiSettings -> Source -> Html Msg
viewLinks : Flags -> UiSettings -> SourceAndTags -> Html Msg
viewLinks flags _ source =
let
appUrl =
flags.config.baseUrl ++ "/app/upload/" ++ source.id
flags.config.baseUrl ++ "/app/upload/" ++ source.source.id
apiUrl =
flags.config.baseUrl ++ "/api/v1/open/upload/item/" ++ source.id
flags.config.baseUrl ++ "/api/v1/open/upload/item/" ++ source.source.id
in
div
[]
[ h3 [ class "ui dividing header" ]
[ text "Public Uploads: "
, text source.abbrev
, text source.source.abbrev
, div [ class "sub header" ]
[ text source.id
[ text source.source.id
]
]
, p []
@ -273,7 +274,7 @@ viewLinks flags _ source =
]
, p []
[ text "There have been "
, String.fromInt source.counter |> text
, String.fromInt source.source.counter |> text
, text " items created through this source."
]
, h4 [ class "ui header" ]
@ -358,7 +359,7 @@ viewForm : Flags -> UiSettings -> Model -> List (Html Msg)
viewForm flags settings model =
let
newSource =
model.formModel.source.id == ""
model.formModel.source.source.id == ""
in
[ if newSource then
h3 [ class "ui top attached header" ]
@ -367,10 +368,10 @@ viewForm flags settings model =
else
h3 [ class "ui top attached header" ]
[ text ("Edit: " ++ model.formModel.source.abbrev)
[ text ("Edit: " ++ model.formModel.source.source.abbrev)
, div [ class "sub header" ]
[ text "Id: "
, text model.formModel.source.id
, text model.formModel.source.source.id
]
]
, Html.form [ class "ui attached segment", onSubmit Submit ]

View File

@ -6,7 +6,7 @@ module Comp.SourceTable exposing
, view
)
import Api.Model.Source exposing (Source)
import Api.Model.SourceAndTags exposing (SourceAndTags)
import Data.Flags exposing (Flags)
import Data.Priority
import Html exposing (..)
@ -15,8 +15,8 @@ import Html.Events exposing (onClick)
type SelectMode
= Edit Source
| Display Source
= Edit SourceAndTags
| Display SourceAndTags
| None
@ -34,8 +34,8 @@ isEdit m =
type Msg
= Select Source
| Show Source
= Select SourceAndTags
| Show SourceAndTags
update : Flags -> Msg -> ( Cmd Msg, SelectMode )
@ -48,7 +48,7 @@ update _ msg =
( Cmd.none, Display source )
view : List Source -> Html Msg
view : List SourceAndTags -> Html Msg
view sources =
table [ class "ui table" ]
[ thead []
@ -66,7 +66,7 @@ view sources =
]
renderSourceLine : Source -> Html Msg
renderSourceLine : SourceAndTags -> Html Msg
renderSourceLine source =
tr
[]
@ -82,10 +82,10 @@ renderSourceLine source =
, a
[ classList
[ ( "ui basic tiny primary button", True )
, ( "disabled", not source.enabled )
, ( "disabled", not source.source.enabled )
]
, href "#"
, disabled (not source.enabled)
, disabled (not source.source.enabled)
, onClick (Show source)
]
[ i [ class "eye icon" ] []
@ -93,25 +93,25 @@ renderSourceLine source =
]
]
, td [ class "collapsing" ]
[ text source.abbrev
[ text source.source.abbrev
]
, td [ class "collapsing" ]
[ if source.enabled then
[ if source.source.enabled then
i [ class "check square outline icon" ] []
else
i [ class "minus square outline icon" ] []
]
, td [ class "collapsing" ]
[ source.counter |> String.fromInt |> text
[ source.source.counter |> String.fromInt |> text
]
, td [ class "collapsing" ]
[ Data.Priority.fromString source.priority
[ Data.Priority.fromString source.source.priority
|> Maybe.map Data.Priority.toName
|> Maybe.withDefault source.priority
|> Maybe.withDefault source.source.priority
|> text
]
, td []
[ text source.id
[ text source.source.id
]
]