mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-27 01:25:05 +00:00
690 lines
20 KiB
Elm
690 lines
20 KiB
Elm
module Page.Home.Update exposing (update)
|
|
|
|
import Api
|
|
import Api.Model.IdList exposing (IdList)
|
|
import Api.Model.ItemLightList exposing (ItemLightList)
|
|
import Api.Model.ItemSearch
|
|
import Browser.Navigation as Nav
|
|
import Comp.FixedDropdown
|
|
import Comp.ItemCard
|
|
import Comp.ItemCardList
|
|
import Comp.ItemDetail.EditMenu exposing (SaveNameState(..))
|
|
import Comp.ItemDetail.FormChange exposing (FormChange(..))
|
|
import Comp.SearchMenu
|
|
import Comp.YesNoDimmer
|
|
import Data.Flags exposing (Flags)
|
|
import Data.ItemSelection
|
|
import Data.Items
|
|
import Data.UiSettings exposing (UiSettings)
|
|
import Page exposing (Page(..))
|
|
import Page.Home.Data exposing (..)
|
|
import Process
|
|
import Scroll
|
|
import Set exposing (Set)
|
|
import Task
|
|
import Throttle
|
|
import Time
|
|
import Util.Html exposing (KeyCode(..))
|
|
import Util.ItemDragDrop as DD
|
|
import Util.Maybe
|
|
import Util.String
|
|
import Util.Update
|
|
|
|
|
|
update : Maybe String -> Nav.Key -> Flags -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
|
|
update mId key flags settings msg model =
|
|
case msg of
|
|
Init ->
|
|
Util.Update.andThen2
|
|
[ update mId key flags settings (SearchMenuMsg Comp.SearchMenu.Init)
|
|
, doSearch flags settings True
|
|
]
|
|
model
|
|
|
|
ResetSearch ->
|
|
let
|
|
nm =
|
|
{ model
|
|
| searchOffset = 0
|
|
, searchType = defaultSearchType flags
|
|
}
|
|
in
|
|
update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm
|
|
|
|
SearchMenuMsg m ->
|
|
let
|
|
nextState =
|
|
Comp.SearchMenu.updateDrop
|
|
model.dragDropData.model
|
|
flags
|
|
settings
|
|
m
|
|
model.searchMenuModel
|
|
|
|
dropCmd =
|
|
DD.makeUpdateCmd flags (\_ -> DoSearch) nextState.dragDrop.dropped
|
|
|
|
newModel =
|
|
{ model
|
|
| searchMenuModel = nextState.model
|
|
, dragDropData = nextState.dragDrop
|
|
}
|
|
|
|
( m2, c2, s2 ) =
|
|
if nextState.stateChange && not model.searchInProgress then
|
|
doSearch flags settings False newModel
|
|
|
|
else
|
|
withSub ( newModel, Cmd.none )
|
|
in
|
|
( m2
|
|
, Cmd.batch
|
|
[ c2
|
|
, Cmd.map SearchMenuMsg nextState.cmd
|
|
, dropCmd
|
|
]
|
|
, s2
|
|
)
|
|
|
|
ItemCardListMsg m ->
|
|
let
|
|
result =
|
|
Comp.ItemCardList.updateDrag model.dragDropData.model
|
|
flags
|
|
m
|
|
model.itemListModel
|
|
|
|
searchMsg =
|
|
case result.linkTarget of
|
|
Comp.ItemCard.LinkNone ->
|
|
Cmd.none
|
|
|
|
Comp.ItemCard.LinkCorrOrg id ->
|
|
Util.Update.cmdUnit (SearchMenuMsg (Comp.SearchMenu.SetCorrOrg id))
|
|
|
|
Comp.ItemCard.LinkCorrPerson id ->
|
|
Util.Update.cmdUnit (SearchMenuMsg (Comp.SearchMenu.SetCorrPerson id))
|
|
|
|
Comp.ItemCard.LinkConcPerson id ->
|
|
Util.Update.cmdUnit (SearchMenuMsg (Comp.SearchMenu.SetConcPerson id))
|
|
|
|
Comp.ItemCard.LinkConcEquip id ->
|
|
Util.Update.cmdUnit (SearchMenuMsg (Comp.SearchMenu.SetConcEquip id))
|
|
|
|
Comp.ItemCard.LinkFolder id ->
|
|
Util.Update.cmdUnit (SearchMenuMsg (Comp.SearchMenu.SetFolder id))
|
|
|
|
nextView =
|
|
case ( model.viewMode, result.selection ) of
|
|
( SelectView svm, Data.ItemSelection.Active ids ) ->
|
|
SelectView { svm | ids = ids }
|
|
|
|
( v, _ ) ->
|
|
v
|
|
in
|
|
withSub
|
|
( { model
|
|
| itemListModel = result.model
|
|
, viewMode = nextView
|
|
, dragDropData = DD.DragDropData result.dragModel Nothing
|
|
}
|
|
, Cmd.batch [ Cmd.map ItemCardListMsg result.cmd, searchMsg ]
|
|
)
|
|
|
|
ItemSearchResp scroll (Ok list) ->
|
|
let
|
|
noff =
|
|
settings.itemSearchPageSize
|
|
|
|
m =
|
|
{ model
|
|
| searchInProgress = False
|
|
, searchOffset = noff
|
|
, moreAvailable = list.groups /= []
|
|
}
|
|
in
|
|
Util.Update.andThen2
|
|
[ update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.SetResults list))
|
|
, if scroll then
|
|
scrollToCard mId
|
|
|
|
else
|
|
\next -> ( next, Cmd.none, Sub.none )
|
|
]
|
|
m
|
|
|
|
ItemSearchAddResp (Ok list) ->
|
|
let
|
|
noff =
|
|
model.searchOffset + settings.itemSearchPageSize
|
|
|
|
m =
|
|
{ model
|
|
| searchInProgress = False
|
|
, moreInProgress = False
|
|
, searchOffset = noff
|
|
, moreAvailable = list.groups /= []
|
|
}
|
|
in
|
|
Util.Update.andThen2
|
|
[ update mId key flags settings (ItemCardListMsg (Comp.ItemCardList.AddResults list))
|
|
]
|
|
m
|
|
|
|
ItemSearchAddResp (Err _) ->
|
|
withSub
|
|
( { model
|
|
| moreInProgress = False
|
|
}
|
|
, Cmd.none
|
|
)
|
|
|
|
ItemSearchResp _ (Err _) ->
|
|
withSub
|
|
( { model
|
|
| searchInProgress = False
|
|
}
|
|
, Cmd.none
|
|
)
|
|
|
|
DoSearch ->
|
|
let
|
|
nm =
|
|
{ model | searchOffset = 0 }
|
|
in
|
|
if model.searchInProgress then
|
|
withSub ( model, Cmd.none )
|
|
|
|
else
|
|
doSearch flags settings False nm
|
|
|
|
ToggleSearchMenu ->
|
|
let
|
|
nextView =
|
|
case model.viewMode of
|
|
SimpleView ->
|
|
SearchView
|
|
|
|
SearchView ->
|
|
SimpleView
|
|
|
|
SelectView _ ->
|
|
SimpleView
|
|
in
|
|
withSub
|
|
( { model | viewMode = nextView }
|
|
, Cmd.none
|
|
)
|
|
|
|
ToggleSelectView ->
|
|
let
|
|
( nextView, cmd ) =
|
|
case model.viewMode of
|
|
SimpleView ->
|
|
( SelectView initSelectViewModel, loadEditModel flags )
|
|
|
|
SearchView ->
|
|
( SelectView initSelectViewModel, loadEditModel flags )
|
|
|
|
SelectView _ ->
|
|
( SearchView, Cmd.none )
|
|
in
|
|
withSub
|
|
( { model
|
|
| viewMode = nextView
|
|
}
|
|
, cmd
|
|
)
|
|
|
|
LoadMore ->
|
|
if model.moreAvailable then
|
|
doSearchMore flags settings model |> withSub
|
|
|
|
else
|
|
withSub ( model, Cmd.none )
|
|
|
|
UpdateThrottle ->
|
|
let
|
|
( newThrottle, cmd ) =
|
|
Throttle.update model.throttle
|
|
in
|
|
withSub ( { model | throttle = newThrottle }, cmd )
|
|
|
|
SetBasicSearch str ->
|
|
let
|
|
smMsg =
|
|
case model.searchTypeForm of
|
|
BasicSearch ->
|
|
SearchMenuMsg (Comp.SearchMenu.SetAllName str)
|
|
|
|
ContentSearch ->
|
|
SearchMenuMsg (Comp.SearchMenu.SetFulltext str)
|
|
|
|
ContentOnlySearch ->
|
|
SetContentOnly str
|
|
in
|
|
update mId key flags settings smMsg model
|
|
|
|
SetContentOnly str ->
|
|
withSub
|
|
( { model | contentOnlySearch = Util.Maybe.fromString str }
|
|
, Cmd.none
|
|
)
|
|
|
|
SearchTypeMsg lm ->
|
|
let
|
|
( sm, mv ) =
|
|
Comp.FixedDropdown.update lm model.searchTypeDropdown
|
|
|
|
mvChange =
|
|
Util.Maybe.filter (\a -> a /= model.searchTypeForm) mv
|
|
|
|
m0 =
|
|
{ model
|
|
| searchTypeDropdown = sm
|
|
, searchTypeForm = Maybe.withDefault model.searchTypeForm mv
|
|
}
|
|
|
|
next =
|
|
case mvChange of
|
|
Just BasicSearch ->
|
|
Just
|
|
( { m0 | contentOnlySearch = Nothing }
|
|
, Maybe.withDefault "" model.contentOnlySearch
|
|
)
|
|
|
|
Just ContentOnlySearch ->
|
|
Just
|
|
( { m0 | contentOnlySearch = model.searchMenuModel.allNameModel }
|
|
, ""
|
|
)
|
|
|
|
_ ->
|
|
Nothing
|
|
in
|
|
case next of
|
|
Just ( m_, nstr ) ->
|
|
update mId key flags settings (SearchMenuMsg (Comp.SearchMenu.SetAllName nstr)) m_
|
|
|
|
Nothing ->
|
|
withSub ( m0, Cmd.none )
|
|
|
|
KeyUpMsg (Just Enter) ->
|
|
update mId key flags settings DoSearch model
|
|
|
|
KeyUpMsg _ ->
|
|
withSub ( model, Cmd.none )
|
|
|
|
ScrollResult _ ->
|
|
let
|
|
cmd =
|
|
Process.sleep 800 |> Task.perform (always ClearItemDetailId)
|
|
in
|
|
withSub ( model, cmd )
|
|
|
|
ClearItemDetailId ->
|
|
noSub ( { model | scrollToCard = Nothing }, Cmd.none )
|
|
|
|
SelectAllItems ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
let
|
|
visible =
|
|
Data.Items.idSet model.itemListModel.results
|
|
|
|
svm_ =
|
|
{ svm | ids = Set.union svm.ids visible }
|
|
in
|
|
noSub
|
|
( { model | viewMode = SelectView svm_ }
|
|
, Cmd.none
|
|
)
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
SelectNoItems ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
let
|
|
svm_ =
|
|
{ svm | ids = Set.empty }
|
|
in
|
|
noSub
|
|
( { model | viewMode = SelectView svm_ }
|
|
, Cmd.none
|
|
)
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
DeleteSelectedConfirmMsg lmsg ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
let
|
|
( confirmModel, confirmed ) =
|
|
Comp.YesNoDimmer.update lmsg svm.deleteAllConfirm
|
|
|
|
cmd =
|
|
if confirmed then
|
|
Api.deleteAllItems flags svm.ids DeleteAllResp
|
|
|
|
else
|
|
Cmd.none
|
|
|
|
act =
|
|
if confirmModel.active || confirmed then
|
|
DeleteSelected
|
|
|
|
else
|
|
NoneAction
|
|
in
|
|
noSub
|
|
( { model
|
|
| viewMode =
|
|
SelectView
|
|
{ svm
|
|
| deleteAllConfirm = confirmModel
|
|
, action = act
|
|
}
|
|
}
|
|
, cmd
|
|
)
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
DeleteAllResp (Ok res) ->
|
|
if res.success then
|
|
let
|
|
nm =
|
|
{ model | viewMode = SearchView }
|
|
in
|
|
doSearch flags settings False nm
|
|
|
|
else
|
|
noSub ( model, Cmd.none )
|
|
|
|
DeleteAllResp (Err _) ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
RequestDeleteSelected ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
if svm.ids == Set.empty then
|
|
noSub ( model, Cmd.none )
|
|
|
|
else
|
|
let
|
|
lmsg =
|
|
DeleteSelectedConfirmMsg Comp.YesNoDimmer.activate
|
|
|
|
model_ =
|
|
{ model | viewMode = SelectView { svm | action = DeleteSelected } }
|
|
in
|
|
update mId key flags settings lmsg model_
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
EditSelectedItems ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
if svm.action == EditSelected then
|
|
noSub
|
|
( { model | viewMode = SelectView { svm | action = NoneAction } }
|
|
, Cmd.none
|
|
)
|
|
|
|
else if svm.ids == Set.empty then
|
|
noSub ( model, Cmd.none )
|
|
|
|
else
|
|
noSub
|
|
( { model | viewMode = SelectView { svm | action = EditSelected } }
|
|
, Cmd.none
|
|
)
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
EditMenuMsg lmsg ->
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
let
|
|
res =
|
|
Comp.ItemDetail.EditMenu.update flags lmsg svm.editModel
|
|
|
|
svm_ =
|
|
{ svm
|
|
| editModel = res.model
|
|
, saveNameState =
|
|
case res.change of
|
|
NameChange _ ->
|
|
Saving
|
|
|
|
_ ->
|
|
svm.saveNameState
|
|
}
|
|
|
|
cmd_ =
|
|
Cmd.map EditMenuMsg res.cmd
|
|
|
|
sub_ =
|
|
Sub.map EditMenuMsg res.sub
|
|
|
|
upCmd =
|
|
Comp.ItemDetail.FormChange.multiUpdate flags
|
|
svm.ids
|
|
res.change
|
|
(MultiUpdateResp res.change)
|
|
in
|
|
( { model | viewMode = SelectView svm_ }
|
|
, Cmd.batch [ cmd_, upCmd ]
|
|
, sub_
|
|
)
|
|
|
|
_ ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
MultiUpdateResp change (Ok res) ->
|
|
let
|
|
nm =
|
|
updateSelectViewNameState res.success model change
|
|
in
|
|
if res.success then
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
-- replace changed items in the view
|
|
noSub ( nm, loadChangedItems flags svm.ids )
|
|
|
|
_ ->
|
|
noSub ( nm, Cmd.none )
|
|
|
|
else
|
|
noSub ( nm, Cmd.none )
|
|
|
|
MultiUpdateResp change (Err _) ->
|
|
( updateSelectViewNameState False model change
|
|
, Cmd.none
|
|
, Sub.none
|
|
)
|
|
|
|
ReplaceChangedItemsResp (Ok items) ->
|
|
noSub ( replaceItems model items, Cmd.none )
|
|
|
|
ReplaceChangedItemsResp (Err _) ->
|
|
noSub ( model, Cmd.none )
|
|
|
|
UiSettingsUpdated ->
|
|
let
|
|
defaultViewMode =
|
|
if settings.searchMenuVisible then
|
|
SearchView
|
|
|
|
else
|
|
SimpleView
|
|
|
|
viewMode =
|
|
case model.viewMode of
|
|
SimpleView ->
|
|
defaultViewMode
|
|
|
|
SearchView ->
|
|
defaultViewMode
|
|
|
|
sv ->
|
|
sv
|
|
|
|
model_ =
|
|
{ model | viewMode = viewMode }
|
|
in
|
|
update mId key flags settings DoSearch model_
|
|
|
|
|
|
|
|
--- Helpers
|
|
|
|
|
|
updateSelectViewNameState : Bool -> Model -> FormChange -> Model
|
|
updateSelectViewNameState success model change =
|
|
case model.viewMode of
|
|
SelectView svm ->
|
|
case change of
|
|
NameChange _ ->
|
|
let
|
|
svm_ =
|
|
{ svm
|
|
| saveNameState =
|
|
if success then
|
|
SaveSuccess
|
|
|
|
else
|
|
SaveFailed
|
|
}
|
|
in
|
|
{ model | viewMode = SelectView svm_ }
|
|
|
|
_ ->
|
|
model
|
|
|
|
_ ->
|
|
model
|
|
|
|
|
|
replaceItems : Model -> ItemLightList -> Model
|
|
replaceItems model newItems =
|
|
let
|
|
listModel =
|
|
model.itemListModel
|
|
|
|
changed =
|
|
Data.Items.replaceIn listModel.results newItems
|
|
|
|
newList =
|
|
{ listModel | results = changed }
|
|
in
|
|
{ model | itemListModel = newList }
|
|
|
|
|
|
loadChangedItems : Flags -> Set String -> Cmd Msg
|
|
loadChangedItems flags ids =
|
|
if Set.isEmpty ids then
|
|
Cmd.none
|
|
|
|
else
|
|
let
|
|
searchInit =
|
|
Api.Model.ItemSearch.empty
|
|
|
|
idList =
|
|
IdList (Set.toList ids)
|
|
|
|
search =
|
|
{ searchInit
|
|
| itemSubset = Just idList
|
|
, limit = Set.size ids
|
|
}
|
|
in
|
|
Api.itemSearch flags search ReplaceChangedItemsResp
|
|
|
|
|
|
scrollToCard : Maybe String -> Model -> ( Model, Cmd Msg, Sub Msg )
|
|
scrollToCard mId model =
|
|
let
|
|
scroll id =
|
|
Scroll.scroll id 0.5 0.5 0.5 0.5
|
|
in
|
|
case mId of
|
|
Just id ->
|
|
( { model | scrollToCard = mId }
|
|
, Task.attempt ScrollResult (scroll id)
|
|
, Sub.none
|
|
)
|
|
|
|
Nothing ->
|
|
( model, Cmd.none, Sub.none )
|
|
|
|
|
|
loadEditModel : Flags -> Cmd Msg
|
|
loadEditModel flags =
|
|
Cmd.map EditMenuMsg (Comp.ItemDetail.EditMenu.loadModel flags)
|
|
|
|
|
|
doSearch : Flags -> UiSettings -> Bool -> Model -> ( Model, Cmd Msg, Sub Msg )
|
|
doSearch flags settings scroll model =
|
|
let
|
|
stype =
|
|
if
|
|
not (menuCollapsed model)
|
|
|| Util.String.isNothingOrBlank model.contentOnlySearch
|
|
then
|
|
BasicSearch
|
|
|
|
else
|
|
model.searchTypeForm
|
|
|
|
model_ =
|
|
{ model | searchType = stype }
|
|
|
|
searchCmd =
|
|
doSearchCmd flags settings 0 scroll model_
|
|
|
|
( newThrottle, cmd ) =
|
|
Throttle.try searchCmd model.throttle
|
|
in
|
|
withSub
|
|
( { model_
|
|
| searchInProgress = cmd /= Cmd.none
|
|
, searchOffset = 0
|
|
, throttle = newThrottle
|
|
}
|
|
, cmd
|
|
)
|
|
|
|
|
|
doSearchMore : Flags -> UiSettings -> Model -> ( Model, Cmd Msg )
|
|
doSearchMore flags settings model =
|
|
let
|
|
cmd =
|
|
doSearchCmd flags settings model.searchOffset False model
|
|
in
|
|
( { model | moreInProgress = True }
|
|
, cmd
|
|
)
|
|
|
|
|
|
withSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg )
|
|
withSub ( m, c ) =
|
|
( m
|
|
, c
|
|
, Throttle.ifNeeded
|
|
(Time.every 500 (\_ -> UpdateThrottle))
|
|
m.throttle
|
|
)
|
|
|
|
|
|
noSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg )
|
|
noSub ( m, c ) =
|
|
( m, c, Sub.none )
|