Add routes and upload form to item detail

This commit is contained in:
Eike Kettner
2020-05-23 19:42:36 +02:00
parent f4949446e3
commit a5ca3b0325
6 changed files with 456 additions and 18 deletions

View File

@ -71,6 +71,7 @@ module Api exposing
, submitNotifyDueItems
, updateScanMailbox
, upload
, uploadAmend
, uploadSingle
, versionInfo
)
@ -429,7 +430,42 @@ createImapSettings flags mname ems receive =
--- Upload
upload : Flags -> Maybe String -> ItemUploadMeta -> List File -> (String -> Result Http.Error BasicResult -> msg) -> List (Cmd msg)
uploadAmend :
Flags
-> String
-> List File
-> (String -> Result Http.Error BasicResult -> msg)
-> List (Cmd msg)
uploadAmend flags itemId files receive =
let
mkReq file =
let
fid =
Util.File.makeFileId file
path =
"/api/v1/sec/upload/item/" ++ itemId
in
Http2.authPostTrack
{ url = flags.config.baseUrl ++ path
, account = getAccount flags
, body =
Http.multipartBody <|
[ Http.filePart "file[]" file ]
, expect = Http.expectJson (receive fid) Api.Model.BasicResult.decoder
, tracker = fid
}
in
List.map mkReq files
upload :
Flags
-> Maybe String
-> ItemUploadMeta
-> List File
-> (String -> Result Http.Error BasicResult -> msg)
-> List (Cmd msg)
upload flags sourceId meta files receive =
let
metaStr =
@ -457,7 +493,14 @@ upload flags sourceId meta files receive =
List.map mkReq files
uploadSingle : Flags -> Maybe String -> ItemUploadMeta -> String -> List File -> (Result Http.Error BasicResult -> msg) -> Cmd msg
uploadSingle :
Flags
-> Maybe String
-> ItemUploadMeta
-> String
-> List File
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
uploadSingle flags sourceId meta track files receive =
let
metaStr =

View File

@ -25,6 +25,7 @@ import Browser.Navigation as Nav
import Comp.AttachmentMeta
import Comp.DatePicker
import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.Dropzone
import Comp.ItemMail
import Comp.MarkdownInput
import Comp.SentMails
@ -34,12 +35,16 @@ import Data.Flags exposing (Flags)
import Data.Icons as Icons
import DatePicker exposing (DatePicker)
import Dict exposing (Dict)
import File exposing (File)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onClick, onInput)
import Http
import Markdown
import Page exposing (Page(..))
import Ports
import Set exposing (Set)
import Util.File exposing (makeFileId)
import Util.Http
import Util.List
import Util.Maybe
@ -77,6 +82,12 @@ type alias Model =
, attachMetaOpen : Bool
, pdfNativeView : Bool
, deleteAttachConfirm : Comp.YesNoDimmer.Model
, addFilesOpen : Bool
, addFilesModel : Comp.Dropzone.Model
, selectedFiles : List File
, completed : Set String
, errored : Set String
, loading : Set String
}
@ -165,6 +176,12 @@ emptyModel =
, attachMetaOpen = False
, pdfNativeView = False
, deleteAttachConfirm = Comp.YesNoDimmer.emptyModel
, addFilesOpen = False
, addFilesModel = Comp.Dropzone.init Comp.Dropzone.defaultSettings
, selectedFiles = []
, completed = Set.empty
, errored = Set.empty
, loading = Set.empty
}
@ -221,6 +238,12 @@ type Msg
| RequestDeleteAttachment String
| DeleteAttachConfirm String Comp.YesNoDimmer.Msg
| DeleteAttachResp (Result Http.Error BasicResult)
| AddFilesToggle
| AddFilesMsg Comp.Dropzone.Msg
| AddFilesSubmitUpload
| AddFilesUploadResp String (Result Http.Error BasicResult)
| AddFilesProgress String Http.Progress
| AddFilesReset
@ -334,6 +357,42 @@ setDueDate flags model date =
Api.setItemDueDate flags model.item.id (OptionalDate date) SaveResp
isLoading : Model -> File -> Bool
isLoading model file =
Set.member (makeFileId file) model.loading
isCompleted : Model -> File -> Bool
isCompleted model file =
Set.member (makeFileId file) model.completed
isError : Model -> File -> Bool
isError model file =
Set.member (makeFileId file) model.errored
isIdle : Model -> File -> Bool
isIdle model file =
not (isLoading model file || isCompleted model file || isError model file)
setCompleted : Model -> String -> Set String
setCompleted model fileid =
Set.insert fileid model.completed
setErrored : Model -> String -> Set String
setErrored model fileid =
Set.insert fileid model.errored
isSuccessAll : Model -> Bool
isSuccessAll model =
List.map makeFileId model.selectedFiles
|> List.all (\id -> Set.member id model.completed)
update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg )
update key flags next msg model =
case msg of
@ -430,6 +489,9 @@ update key flags next msg model =
)
m5
( m7, c7 ) =
update key flags next AddFilesReset m6
proposalCmd =
if item.state == "created" then
Api.getItemProposals flags item.id GetProposalResp
@ -437,7 +499,7 @@ update key flags next msg model =
else
Cmd.none
in
( { m6
( { m7
| item = item
, nameModel = item.name
, notesModel = item.notes
@ -453,6 +515,7 @@ update key flags next msg model =
, c4
, c5
, c6
, c7
, getOptions flags
, proposalCmd
, Api.getSentMails flags item.id SentMailsResp
@ -980,6 +1043,107 @@ update key flags next msg model =
(DeleteAttachConfirm id Comp.YesNoDimmer.activate)
model
AddFilesToggle ->
( { model | addFilesOpen = not model.addFilesOpen }
, Cmd.none
)
AddFilesMsg lm ->
let
( dm, dc, df ) =
Comp.Dropzone.update lm model.addFilesModel
nextFiles =
model.selectedFiles ++ df
in
( { model | addFilesModel = dm, selectedFiles = nextFiles }
, Cmd.map AddFilesMsg dc
)
AddFilesReset ->
( { model
| selectedFiles = []
, addFilesModel = Comp.Dropzone.init Comp.Dropzone.defaultSettings
, completed = Set.empty
, errored = Set.empty
, loading = Set.empty
}
, Cmd.none
)
AddFilesSubmitUpload ->
let
fileids =
List.map makeFileId model.selectedFiles
uploads =
Cmd.batch (Api.uploadAmend flags model.item.id model.selectedFiles AddFilesUploadResp)
tracker =
Sub.batch <| List.map (\id -> Http.track id (AddFilesProgress id)) fileids
( cm2, _, _ ) =
Comp.Dropzone.update (Comp.Dropzone.setActive False) model.addFilesModel
in
( { model | loading = Set.fromList fileids, addFilesModel = cm2 }, uploads )
AddFilesUploadResp fileid (Ok res) ->
let
compl =
if res.success then
setCompleted model fileid
else
model.completed
errs =
if not res.success then
setErrored model fileid
else
model.errored
load =
Set.remove fileid model.loading
newModel =
{ model | completed = compl, errored = errs, loading = load }
in
( newModel
, Ports.setProgress ( fileid, 100 )
)
AddFilesUploadResp fileid (Err _) ->
let
errs =
setErrored model fileid
load =
Set.remove fileid model.loading
in
( { model | errored = errs, loading = load }, Cmd.none )
AddFilesProgress fileid progress ->
let
percent =
case progress of
Http.Sending p ->
Http.fractionSent p
|> (*) 100
|> round
_ ->
0
updateBars =
if percent == 0 then
Cmd.none
else
Ports.setProgress ( fileid, percent )
in
( model, updateBars )
-- view
@ -1001,7 +1165,7 @@ view inav model =
, div
[ classList
[ ( "ui ablue-comp menu", True )
, ( "top attached", model.mailOpen )
, ( "top attached", model.mailOpen || model.addFilesOpen )
]
]
[ a [ class "item", Page.href HomePage ]
@ -1066,8 +1230,24 @@ view inav model =
]
[ Icons.editNotesIcon
]
, a
[ classList
[ ( "toggle item", True )
, ( "active", model.addFilesOpen )
]
, if model.addFilesOpen then
title "Close"
else
title "Add Files"
, onClick AddFilesToggle
, href "#"
]
[ Icons.addFilesIcon
]
]
, renderMailForm model
, renderAddFilesForm model
, div [ class "ui grid" ]
[ Html.map DeleteItemConfirm (Comp.YesNoDimmer.view model.deleteItemConfirm)
, div
@ -1756,3 +1936,94 @@ renderMailForm model =
|> text
]
]
renderAddFilesForm : Model -> Html Msg
renderAddFilesForm model =
div
[ classList
[ ( "ui bottom attached segment", True )
, ( "invisible hidden", not model.addFilesOpen )
]
]
[ h4 [ class "ui header" ]
[ text "Add more files to this item"
]
, Html.map AddFilesMsg (Comp.Dropzone.view model.addFilesModel)
, button
[ class "ui primary button"
, href "#"
, onClick AddFilesSubmitUpload
]
[ text "Submit"
]
, button
[ class "ui secondary button"
, href "#"
, onClick AddFilesReset
]
[ text "Reset"
]
, div
[ classList
[ ( "ui success message", True )
, ( "invisible hidden", model.selectedFiles == [] || not (isSuccessAll model) )
]
]
[ text "All files have been uploaded. They are being processed, some data "
, text "may not be available immediately. "
, a
[ class "link"
, href "#"
, onClick ReloadItem
]
[ text "Refresh now"
]
]
, div [ class "ui items" ]
(List.map (renderFileItem model) model.selectedFiles)
]
renderFileItem : Model -> File -> Html Msg
renderFileItem model file =
let
name =
File.name file
size =
File.size file
|> toFloat
|> Util.Size.bytesReadable Util.Size.B
in
div [ class "item" ]
[ i
[ classList
[ ( "large", True )
, ( "file outline icon", isIdle model file )
, ( "loading spinner icon", isLoading model file )
, ( "green check icon", isCompleted model file )
, ( "red bolt icon", isError model file )
]
]
[]
, div [ class "middle aligned content" ]
[ div [ class "header" ]
[ text name
]
, div [ class "right floated meta" ]
[ text size
]
, div [ class "description" ]
[ div
[ classList
[ ( "ui small indicating progress", True )
]
, id (makeFileId file)
]
[ div [ class "bar" ]
[]
]
]
]
]

View File

@ -1,5 +1,7 @@
module Data.Icons exposing
( concerned
( addFiles
, addFilesIcon
, concerned
, concernedIcon
, correspondent
, correspondentIcon
@ -51,3 +53,13 @@ editNotes =
editNotesIcon : Html msg
editNotesIcon =
i [ class editNotes ] []
addFiles : String
addFiles =
"file plus icon"
addFilesIcon : Html msg
addFilesIcon =
i [ class addFiles ] []

View File

@ -41,7 +41,12 @@ update sourceId flags msg model =
uploads =
if model.singleItem then
Api.uploadSingle flags sourceId meta uploadAllTracker model.files (SingleUploadResp uploadAllTracker)
Api.uploadSingle flags
sourceId
meta
uploadAllTracker
model.files
(SingleUploadResp uploadAllTracker)
else
Cmd.batch (Api.upload flags sourceId meta model.files SingleUploadResp)