Allow to select multiple items for deletion and edit

This commit is contained in:
Eike Kettner
2020-10-23 20:57:19 +02:00
parent c2d8f2b438
commit 55cfc4c908
11 changed files with 1326 additions and 50 deletions

View File

@ -2,12 +2,18 @@ module Page.Home.Data exposing
( Model
, Msg(..)
, SearchType(..)
, SelectActionMode(..)
, SelectViewModel
, ViewMode(..)
, defaultSearchType
, doSearchCmd
, init
, initSelectViewModel
, itemNav
, menuCollapsed
, resultsBelowLimit
, searchTypeString
, selectActive
)
import Api
@ -16,12 +22,16 @@ import Api.Model.ItemSearch
import Browser.Dom as Dom
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.EditMenu
import Comp.SearchMenu
import Comp.YesNoDimmer
import Data.Flags exposing (Flags)
import Data.ItemNav exposing (ItemNav)
import Data.ItemSelection exposing (ItemSelection)
import Data.Items
import Data.UiSettings exposing (UiSettings)
import Http
import Set exposing (Set)
import Throttle exposing (Throttle)
import Util.Html exposing (KeyCode(..))
import Util.ItemDragDrop as DD
@ -31,7 +41,7 @@ type alias Model =
{ searchMenuModel : Comp.SearchMenu.Model
, itemListModel : Comp.ItemCardList.Model
, searchInProgress : Bool
, menuCollapsed : Bool
, viewMode : ViewMode
, searchOffset : Int
, moreAvailable : Bool
, moreInProgress : Bool
@ -45,6 +55,29 @@ type alias Model =
}
type alias SelectViewModel =
{ ids : Set String
, action : SelectActionMode
, deleteAllConfirm : Comp.YesNoDimmer.Model
, editModel : Comp.ItemDetail.EditMenu.Model
}
initSelectViewModel : SelectViewModel
initSelectViewModel =
{ ids = Set.empty
, action = NoneAction
, deleteAllConfirm = Comp.YesNoDimmer.initActive
, editModel = Comp.ItemDetail.EditMenu.init
}
type ViewMode
= SimpleView
| SearchView
| SelectView SelectViewModel
init : Flags -> Model
init flags =
let
@ -58,7 +91,6 @@ init flags =
{ searchMenuModel = Comp.SearchMenu.init
, itemListModel = Comp.ItemCardList.init
, searchInProgress = False
, menuCollapsed = True
, searchOffset = 0
, moreAvailable = True
, moreInProgress = False
@ -72,6 +104,7 @@ init flags =
, dragDropData =
DD.DragDropData DD.init Nothing
, scrollToCard = Nothing
, viewMode = SimpleView
}
@ -84,6 +117,32 @@ defaultSearchType flags =
BasicSearch
menuCollapsed : Model -> Bool
menuCollapsed model =
case model.viewMode of
SimpleView ->
True
SearchView ->
False
SelectView _ ->
False
selectActive : Model -> Bool
selectActive model =
case model.viewMode of
SimpleView ->
False
SearchView ->
False
SelectView _ ->
True
type Msg
= Init
| SearchMenuMsg Comp.SearchMenu.Msg
@ -93,6 +152,7 @@ type Msg
| ItemSearchAddResp (Result Http.Error ItemLightList)
| DoSearch
| ToggleSearchMenu
| ToggleSelectView
| LoadMore
| UpdateThrottle
| SetBasicSearch String
@ -101,6 +161,12 @@ type Msg
| SetContentOnly String
| ScrollResult (Result Dom.Error ())
| ClearItemDetailId
| SelectAllItems
| SelectNoItems
| RequestDeleteSelected
| DeleteSelectedConfirmMsg Comp.YesNoDimmer.Msg
| EditSelectedItems
| EditMenuMsg Comp.ItemDetail.EditMenu.Msg
type SearchType
@ -109,6 +175,12 @@ type SearchType
| ContentOnlySearch
type SelectActionMode
= NoneAction
| DeleteSelected
| EditSelected
searchTypeString : SearchType -> String
searchTypeString st =
case st of

View File

@ -3,13 +3,18 @@ module Page.Home.Update exposing (update)
import Browser.Navigation as Nav
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.EditMenu
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
import Task
import Throttle
import Time
@ -82,10 +87,19 @@ update mId key flags settings msg model =
flags
m
model.itemListModel
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 ]
@ -159,11 +173,43 @@ update mId key flags settings msg model =
doSearch flags settings False nm
ToggleSearchMenu ->
let
nextView =
case model.viewMode of
SimpleView ->
SearchView
SearchView ->
SimpleView
SelectView _ ->
SimpleView
in
withSub
( { model | menuCollapsed = not model.menuCollapsed }
( { 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
@ -253,6 +299,139 @@ update mId key flags settings msg model =
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
Cmd.none
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 )
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 }
cmd_ =
Cmd.map EditMenuMsg res.cmd
sub_ =
Sub.map EditMenuMsg res.sub
_ =
Debug.log "change" res.change
in
( { model | viewMode = SelectView svm_ }, cmd_, sub_ )
_ ->
noSub ( model, Cmd.none )
--- Helpers
@ -275,12 +454,17 @@ scrollToCard mId model =
( 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 model.menuCollapsed
not (menuCollapsed model)
|| Util.String.isNothingOrBlank model.contentOnlySearch
then
BasicSearch

View File

@ -3,26 +3,51 @@ module Page.Home.View exposing (view)
import Api.Model.ItemSearch
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.EditMenu
import Comp.SearchMenu
import Comp.YesNoDimmer
import Data.Flags exposing (Flags)
import Data.ItemSelection
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick, onInput)
import Page exposing (Page(..))
import Page.Home.Data exposing (..)
import Set
import Util.Html
view : Flags -> UiSettings -> Model -> Html Msg
view flags settings model =
let
itemViewCfg =
case model.viewMode of
SelectView svm ->
Comp.ItemCardList.ViewConfig
model.scrollToCard
(Data.ItemSelection.Active svm.ids)
_ ->
Comp.ItemCardList.ViewConfig
model.scrollToCard
Data.ItemSelection.Inactive
selectAction =
case model.viewMode of
SelectView svm ->
svm.action
_ ->
NoneAction
in
div [ class "home-page ui padded grid" ]
[ div
[ classList
[ ( "sixteen wide mobile six wide tablet four wide computer search-menu column"
, True
)
, ( "invisible hidden", model.menuCollapsed )
, ( "invisible hidden", menuCollapsed model )
]
]
[ div
@ -38,6 +63,17 @@ view flags settings model =
]
, div [ class "right floated menu" ]
[ a
[ classList
[ ( "borderless item", True )
, ( "active", selectActive model )
]
, href "#"
, title "Select items"
, onClick ToggleSelectView
]
[ i [ class "tasks icon" ] []
]
, a
[ class "borderless item"
, onClick ResetSearch
, title "Reset form"
@ -63,26 +99,30 @@ view flags settings model =
]
]
, div [ class "" ]
[ Html.map SearchMenuMsg
(Comp.SearchMenu.viewDrop model.dragDropData
flags
settings
model.searchMenuModel
)
]
(viewLeftMenu flags settings model)
]
, div
[ classList
[ ( "sixteen wide mobile ten wide tablet twelve wide computer column"
, not model.menuCollapsed
, not (menuCollapsed model)
)
, ( "sixteen wide column", model.menuCollapsed )
, ( "sixteen wide column", menuCollapsed model )
, ( "item-card-list", True )
]
]
[ viewSearchBar flags model
[ viewBar flags model
, case model.viewMode of
SelectView svm ->
Html.map DeleteSelectedConfirmMsg
(Comp.YesNoDimmer.view2 (selectAction == DeleteSelected)
deleteAllDimmer
svm.deleteAllConfirm
)
_ ->
span [ class "invisible" ] []
, Html.map ItemCardListMsg
(Comp.ItemCardList.view model.scrollToCard settings model.itemListModel)
(Comp.ItemCardList.view itemViewCfg settings model.itemListModel)
]
, div
[ classList
@ -117,6 +157,113 @@ view flags settings model =
]
viewLeftMenu : Flags -> UiSettings -> Model -> List (Html Msg)
viewLeftMenu flags settings model =
let
searchMenu =
[ Html.map SearchMenuMsg
(Comp.SearchMenu.viewDrop model.dragDropData
flags
settings
model.searchMenuModel
)
]
in
case model.viewMode of
SelectView svm ->
case svm.action of
EditSelected ->
let
cfg =
Comp.ItemDetail.EditMenu.defaultViewConfig
in
[ div [ class "ui dividing header" ]
[ text "Multi-Edit"
]
, div [ class "ui info message" ]
[ text "Note that a change here immediatly affects all selected items on the right!"
]
, Html.map EditMenuMsg
(Comp.ItemDetail.EditMenu.view cfg settings svm.editModel)
]
_ ->
searchMenu
_ ->
searchMenu
viewBar : Flags -> Model -> Html Msg
viewBar flags model =
case model.viewMode of
SimpleView ->
viewSearchBar flags model
SearchView ->
div [ class "hidden invisible" ] []
SelectView svm ->
viewActionBar flags svm model
viewActionBar : Flags -> SelectViewModel -> Model -> Html Msg
viewActionBar _ svm model =
let
selectCount =
Set.size svm.ids |> String.fromInt
in
div
[ class "ui ablue-comp icon menu"
]
[ a
[ classList
[ ( "borderless item", True )
, ( "active", svm.action == EditSelected )
]
, href "#"
, title <| "Edit " ++ selectCount ++ " selected items"
, onClick EditSelectedItems
]
[ i [ class "ui edit icon" ] []
]
, a
[ classList
[ ( "borderless item", True )
, ( "active", svm.action == DeleteSelected )
]
, href "#"
, title <| "Delete " ++ selectCount ++ " selected items"
, onClick RequestDeleteSelected
]
[ i [ class "trash icon" ] []
]
, div [ class "right menu" ]
[ a
[ class "item"
, href "#"
, onClick SelectAllItems
, title "Select all"
]
[ i [ class "check square outline icon" ] []
]
, a
[ class "borderless item"
, href "#"
, title "Select none"
, onClick SelectNoItems
]
[ i [ class "square outline icon" ] []
]
, div [ class "borderless label item" ]
[ div [ class "ui circular purple icon label" ]
[ text selectCount
]
]
]
]
viewSearchBar : Flags -> Model -> Html Msg
viewSearchBar flags model =
let
@ -145,7 +292,7 @@ viewSearchBar flags model =
in
div
[ classList
[ ( "invisible hidden", not model.menuCollapsed )
[ ( "invisible hidden", not (menuCollapsed model) )
, ( "ui secondary stackable menu container", True )
]
]
@ -221,3 +368,15 @@ hasMoreSearch model =
Api.Model.ItemSearch.empty
in
is_ /= Api.Model.ItemSearch.empty
deleteAllDimmer : Comp.YesNoDimmer.Settings
deleteAllDimmer =
{ message = "Really delete all selected items?"
, headerIcon = "exclamation icon"
, headerClass = "ui inverted icon header"
, confirmButton = "Yes"
, cancelButton = "No"
, invertedDimmer = False
, extraClass = "top aligned"
}