Simplify search bar and search menu

The functionality of the search bar is now in the search menu, too.
The search menu shows one input field for "textual search", which is
either the fulltext search (if enabled) or a basic search in various
names.
This commit is contained in:
Eike Kettner 2020-12-05 22:38:27 +01:00
parent 5882405f30
commit 2aed7ba142
4 changed files with 233 additions and 192 deletions

View File

@ -2,8 +2,12 @@ module Comp.SearchMenu exposing
( Model
, Msg(..)
, NextState
, TextSearchModel
, getItemSearch
, init
, isFulltextSearch
, isNamesSearch
, textSearchString
, update
, updateDrop
, view
@ -66,18 +70,21 @@ type alias Model =
, untilDueDateModel : DatePicker
, untilDueDate : Maybe Int
, nameModel : Maybe String
, allNameModel : Maybe String
, fulltextModel : Maybe String
, textSearchModel : TextSearchModel
, datePickerInitialized : Bool
, showNameHelp : Bool
, customFieldModel : Comp.CustomFieldMultiInput.Model
, customValues : CustomFieldValueCollect
, sourceModel : Maybe String
}
init : Model
init =
type TextSearchModel
= Fulltext (Maybe String)
| Names (Maybe String)
init : Flags -> Model
init flags =
{ tagSelectModel = Comp.TagSelect.init Comp.TagSelect.emptySelection []
, tagSelection = Comp.TagSelect.emptySelection
, directionModel =
@ -124,16 +131,87 @@ init =
, untilDueDateModel = Comp.DatePicker.emptyModel
, untilDueDate = Nothing
, nameModel = Nothing
, allNameModel = Nothing
, fulltextModel = Nothing
, textSearchModel =
if flags.config.fullTextSearchEnabled then
Fulltext Nothing
else
Names Nothing
, datePickerInitialized = False
, showNameHelp = False
, customFieldModel = Comp.CustomFieldMultiInput.initWith []
, customValues = Data.CustomFieldChange.emptyCollect
, sourceModel = Nothing
}
updateTextSearch : String -> TextSearchModel -> TextSearchModel
updateTextSearch str model =
let
next =
Util.Maybe.fromString str
in
case model of
Fulltext _ ->
Fulltext next
Names _ ->
Names next
swapTextSearch : TextSearchModel -> TextSearchModel
swapTextSearch model =
case model of
Fulltext s ->
Names s
Names s ->
Fulltext s
textSearchValue : TextSearchModel -> { nameSearch : Maybe String, fullText : Maybe String }
textSearchValue model =
case model of
Fulltext s ->
{ nameSearch = Nothing
, fullText = s
}
Names s ->
{ nameSearch = s
, fullText = Nothing
}
textSearchString : TextSearchModel -> Maybe String
textSearchString model =
case model of
Fulltext s ->
s
Names s ->
s
isFulltextSearch : Model -> Bool
isFulltextSearch model =
case model.textSearchModel of
Fulltext _ ->
True
Names _ ->
False
isNamesSearch : Model -> Bool
isNamesSearch model =
case model.textSearchModel of
Fulltext _ ->
False
Names _ ->
True
getDirection : Model -> Maybe Direction
getDirection model =
let
@ -164,6 +242,9 @@ getItemSearch model =
else
"*" ++ s ++ "*"
textSearch =
textSearchValue model.textSearchModel
in
{ e
| tagsInclude = model.tagSelection.includeTags |> List.map .tag |> List.map .id
@ -186,9 +267,9 @@ getItemSearch model =
model.nameModel
|> Maybe.map amendWildcards
, allNames =
model.allNameModel
textSearch.nameSearch
|> Maybe.map amendWildcards
, fullText = model.fulltextModel
, fullText = textSearch.fullText
, tagCategoriesInclude = model.tagSelection.includeCats |> List.map .name
, tagCategoriesExclude = model.tagSelection.excludeCats |> List.map .name
, customValues = Data.CustomFieldChange.toFieldValues model.customValues
@ -225,8 +306,13 @@ resetModel model =
, fromDueDate = Nothing
, untilDueDate = Nothing
, nameModel = Nothing
, allNameModel = Nothing
, fulltextModel = Nothing
, textSearchModel =
case model.textSearchModel of
Fulltext _ ->
Fulltext Nothing
Names _ ->
Names Nothing
, customFieldModel =
Comp.CustomFieldMultiInput.reset
model.customFieldModel
@ -257,11 +343,12 @@ type Msg
| GetEquipResp (Result Http.Error EquipmentList)
| GetPersonResp (Result Http.Error PersonList)
| SetName String
| SetAllName String
| SetFulltext String
| SetTextSearch String
| SwapTextSearch
| SetFulltextSearch
| SetNamesSearch
| ResetForm
| KeyUpMsg (Maybe KeyCode)
| ToggleNameHelp
| FolderSelectMsg Comp.FolderSelect.Msg
| GetFolderResp (Result Http.Error FolderList)
| SetCorrOrg IdName
@ -641,27 +728,59 @@ updateDrop ddm flags settings msg model =
, dragDrop = DD.DragDropData ddm Nothing
}
SetAllName str ->
let
next =
Util.Maybe.fromString str
in
{ model = { model | allNameModel = next }
SetTextSearch str ->
{ model = { model | textSearchModel = updateTextSearch str model.textSearchModel }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
SetFulltext str ->
let
next =
Util.Maybe.fromString str
in
{ model = { model | fulltextModel = next }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
SwapTextSearch ->
if flags.config.fullTextSearchEnabled then
{ model = { model | textSearchModel = swapTextSearch model.textSearchModel }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
else
{ model = model
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
SetFulltextSearch ->
case model.textSearchModel of
Fulltext _ ->
{ model = model
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
Names s ->
{ model = { model | textSearchModel = Fulltext s }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
SetNamesSearch ->
case model.textSearchModel of
Fulltext s ->
{ model = { model | textSearchModel = Names s }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
Names _ ->
{ model = model
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
KeyUpMsg (Just Enter) ->
{ model = model
@ -677,13 +796,6 @@ updateDrop ddm flags settings msg model =
, dragDrop = DD.DragDropData ddm Nothing
}
ToggleNameHelp ->
{ model = { model | showNameHelp = not model.showNameHelp }
, cmd = Cmd.none
, stateChange = False
, dragDrop = DD.DragDropData ddm Nothing
}
GetFolderResp (Ok fs) ->
let
model_ =
@ -804,6 +916,54 @@ viewDrop ddd flags settings model =
]
]
]
, div [ class segmentClass ]
[ div
[ class "field"
]
[ label []
[ text
(case model.textSearchModel of
Fulltext _ ->
"Fulltext Search"
Names _ ->
"Search in names"
)
, a
[ classList
[ ( "right-float", True )
, ( "invisible hidden", not flags.config.fullTextSearchEnabled )
]
, href "#"
, onClick SwapTextSearch
, title "Switch between text search modes"
]
[ i [ class "small grey exchange alternate icon" ] []
]
]
, input
[ type_ "text"
, onInput SetTextSearch
, Util.Html.onKeyUpCode KeyUpMsg
, textSearchString model.textSearchModel |> Maybe.withDefault "" |> value
, case model.textSearchModel of
Fulltext _ ->
placeholder "Content search"
Names _ ->
placeholder "Search in various names"
]
[]
, span [ class "small-info" ]
[ case model.textSearchModel of
Fulltext _ ->
text "Fulltext search in document contents and notes."
Names _ ->
text "Looks in correspondents, concerned entities, item name and notes."
]
]
]
, div
[ classList
[ ( segmentClass, True )
@ -883,68 +1043,6 @@ viewDrop ddd flags settings model =
model.customFieldModel
)
]
, div [ class segmentClass ]
[ formHeader (Icons.searchIcon "") "Text Search"
, div
[ classList
[ ( "field", True )
, ( "invisible hidden", not flags.config.fullTextSearchEnabled )
]
]
[ label [] [ text "Fulltext Search" ]
, input
[ type_ "text"
, onInput SetFulltext
, Util.Html.onKeyUpCode KeyUpMsg
, model.fulltextModel |> Maybe.withDefault "" |> value
, placeholder "Fulltext search in results"
]
[]
, span [ class "small-info" ]
[ text "Fulltext search in document contents and notes."
]
]
, div [ class "field" ]
[ label []
[ text "Names"
, a
[ class "right-float"
, href "#"
, onClick ToggleNameHelp
]
[ i [ class "small grey help link icon" ] []
]
]
, input
[ type_ "text"
, onInput SetAllName
, Util.Html.onKeyUpCode KeyUpMsg
, model.allNameModel |> Maybe.withDefault "" |> value
, placeholder "Search in various names"
]
[]
, span
[ classList
[ ( "small-info", True )
]
]
[ text "Looks in correspondents, concerned entities, item name and notes."
]
, p
[ classList
[ ( "small-info", True )
, ( "invisible hidden", not model.showNameHelp )
]
]
[ text "Use wildcards "
, code [] [ text "*" ]
, text " at beginning or end. They are added automatically on both sides "
, text "if not present in the search term and the term is not quoted. Press "
, em [] [ text "Enter" ]
, text " to start searching."
]
]
]
, div
[ classList
[ ( segmentClass, True )

View File

@ -6,7 +6,6 @@ module Page.Home.Data exposing
, SelectActionMode(..)
, SelectViewModel
, ViewMode(..)
, defaultSearchType
, doSearchCmd
, init
, initSelectViewModel
@ -20,7 +19,6 @@ module Page.Home.Data exposing
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemSearch
import Browser.Dom as Dom
import Comp.FixedDropdown
import Comp.ItemCardList
@ -52,7 +50,6 @@ type alias Model =
, searchTypeDropdown : Comp.FixedDropdown.Model SearchType
, searchTypeDropdownValue : SearchType
, lastSearchType : SearchType
, contentOnlySearch : Maybe String
, dragDropData : DD.DragDropData
, scrollToCard : Maybe String
}
@ -88,6 +85,9 @@ type ViewMode
init : Flags -> ViewMode -> Model
init flags viewMode =
let
searchMenuModel =
Comp.SearchMenu.init flags
searchTypeOptions =
if flags.config.fullTextSearchEnabled then
[ BasicSearch, ContentOnlySearch ]
@ -95,7 +95,7 @@ init flags viewMode =
else
[ BasicSearch ]
in
{ searchMenuModel = Comp.SearchMenu.init
{ searchMenuModel = searchMenuModel
, itemListModel = Comp.ItemCardList.init
, searchInProgress = False
, searchOffset = 0
@ -105,9 +105,13 @@ init flags viewMode =
, searchTypeDropdown =
Comp.FixedDropdown.initMap searchTypeString
searchTypeOptions
, searchTypeDropdownValue = defaultSearchType flags
, searchTypeDropdownValue =
if Comp.SearchMenu.isFulltextSearch searchMenuModel then
ContentOnlySearch
else
BasicSearch
, lastSearchType = BasicSearch
, contentOnlySearch = Nothing
, dragDropData =
DD.DragDropData DD.init Nothing
, scrollToCard = Nothing
@ -115,15 +119,6 @@ init flags viewMode =
}
defaultSearchType : Flags -> SearchType
defaultSearchType flags =
if flags.config.fullTextSearchEnabled then
ContentOnlySearch
else
BasicSearch
menuCollapsed : Model -> Bool
menuCollapsed model =
case model.viewMode of
@ -165,7 +160,6 @@ type Msg
| SetBasicSearch String
| SearchTypeMsg (Comp.FixedDropdown.Msg SearchType)
| KeyUpSearchbarMsg (Maybe KeyCode)
| SetContentOnly String
| ScrollResult (Result Dom.Error ())
| ClearItemDetailId
| SelectAllItems
@ -227,12 +221,7 @@ itemNav id model =
doSearchCmd : SearchParam -> Model -> Cmd Msg
doSearchCmd param model =
case param.searchType of
BasicSearch ->
doSearchDefaultCmd param model
ContentOnlySearch ->
doSearchIndexCmd param model
doSearchDefaultCmd param model
doSearchDefaultCmd : SearchParam -> Model -> Cmd Msg
@ -254,36 +243,6 @@ doSearchDefaultCmd param model =
Api.itemSearch param.flags mask ItemSearchAddResp
doSearchIndexCmd : SearchParam -> Model -> Cmd Msg
doSearchIndexCmd param model =
case model.contentOnlySearch of
Just q ->
let
mask =
{ query = q
, limit = param.pageSize
, offset = param.offset
}
in
if param.offset == 0 then
Api.itemIndexSearch param.flags mask (ItemSearchResp param.scroll)
else
Api.itemIndexSearch param.flags mask ItemSearchAddResp
Nothing ->
-- If there is no fulltext query, render simply the most
-- current ones
let
emptyMask =
Api.Model.ItemSearch.empty
mask =
{ emptyMask | limit = param.pageSize }
in
Api.itemSearch param.flags mask (ItemSearchResp param.scroll)
resultsBelowLimit : UiSettings -> Model -> Bool
resultsBelowLimit settings model =
let

View File

@ -52,10 +52,7 @@ update mId key flags settings msg model =
ResetSearch ->
let
nm =
{ model
| searchOffset = 0
, contentOnlySearch = Nothing
}
{ model | searchOffset = 0 }
in
update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm
@ -76,6 +73,12 @@ update mId key flags settings msg model =
{ model
| searchMenuModel = nextState.model
, dragDropData = nextState.dragDrop
, searchTypeDropdownValue =
if Comp.SearchMenu.isFulltextSearch nextState.model then
ContentOnlySearch
else
BasicSearch
}
( m2, c2, s2 ) =
@ -261,21 +264,10 @@ update mId key flags settings msg model =
SetBasicSearch str ->
let
smMsg =
case model.searchTypeDropdownValue of
BasicSearch ->
SearchMenuMsg (Comp.SearchMenu.SetAllName str)
ContentOnlySearch ->
SetContentOnly str
SearchMenuMsg (Comp.SearchMenu.SetTextSearch 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 ) =
@ -293,23 +285,17 @@ update mId key flags settings msg model =
next =
case mvChange of
Just BasicSearch ->
Just
( { m0 | contentOnlySearch = Nothing }
, Maybe.withDefault "" model.contentOnlySearch
)
Just Comp.SearchMenu.SetNamesSearch
Just ContentOnlySearch ->
Just
( { m0 | contentOnlySearch = model.searchMenuModel.allNameModel }
, ""
)
Just Comp.SearchMenu.SetFulltextSearch
_ ->
Nothing
in
case next of
Just ( m_, nstr ) ->
update mId key flags settings (SearchMenuMsg (Comp.SearchMenu.SetAllName nstr)) m_
Just lm_ ->
update mId key flags settings (SearchMenuMsg lm_) m0
Nothing ->
withSub ( m0, Cmd.none )

View File

@ -285,12 +285,8 @@ viewSearchBar flags model =
(searchTypeString model.searchTypeDropdownValue)
searchInput =
case model.searchTypeDropdownValue of
BasicSearch ->
model.searchMenuModel.allNameModel
ContentOnlySearch ->
model.contentOnlySearch
Comp.SearchMenu.textSearchString
model.searchMenuModel.textSearchModel
searchTypeClass =
if flags.config.fullTextSearchEnabled then
@ -328,7 +324,7 @@ viewSearchBar flags model =
, href "#"
, onClick (DoSearch model.searchTypeDropdownValue)
]
(if hasMoreSearch model && model.searchTypeDropdownValue == BasicSearch then
(if hasMoreSearch model then
[ i [ class "icons search-corner-icons" ]
[ i [ class "tiny blue circle icon" ] []
]
@ -339,7 +335,14 @@ viewSearchBar flags model =
)
, input
[ type_ "text"
, placeholder "Quick Search "
, placeholder
(case model.searchTypeDropdownValue of
ContentOnlySearch ->
"Content search"
BasicSearch ->
"Search in names"
)
, onInput SetBasicSearch
, Util.Html.onKeyUpCode KeyUpSearchbarMsg
, Maybe.map value searchInput
@ -381,12 +384,7 @@ hasMoreSearch model =
Comp.SearchMenu.getItemSearch model.searchMenuModel
is_ =
case model.lastSearchType of
BasicSearch ->
{ is | allNames = Nothing }
ContentOnlySearch ->
Api.Model.ItemSearch.empty
{ is | allNames = Nothing, fullText = Nothing }
in
is_ /= Api.Model.ItemSearch.empty