Merge pull request #499 from eikek/search-improvements

Search improvements
This commit is contained in:
mergify[bot] 2020-12-05 22:11:38 +00:00 committed by GitHub
commit 9bd731e252
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 317 additions and 202 deletions

View File

@ -184,7 +184,10 @@ val openapiScalaSettings = Seq(
case "glob" => case "glob" =>
field => field.copy(typeDef = TypeDef("Glob", Imports("docspell.common.Glob"))) field => field.copy(typeDef = TypeDef("Glob", Imports("docspell.common.Glob")))
case "customfieldtype" => case "customfieldtype" =>
field => field.copy(typeDef = TypeDef("CustomFieldType", Imports("docspell.common.CustomFieldType"))) field =>
field.copy(typeDef =
TypeDef("CustomFieldType", Imports("docspell.common.CustomFieldType"))
)
})) }))
) )
@ -465,6 +468,7 @@ val restserver = project
Dependencies.circe ++ Dependencies.circe ++
Dependencies.pureconfig ++ Dependencies.pureconfig ++
Dependencies.yamusca ++ Dependencies.yamusca ++
Dependencies.kittens ++
Dependencies.webjars ++ Dependencies.webjars ++
Dependencies.loggingApi ++ Dependencies.loggingApi ++
Dependencies.logging.map(_ % Runtime), Dependencies.logging.map(_ % Runtime),
@ -681,7 +685,7 @@ def packageTools(logger: Logger, dir: File, version: String): Seq[File] = {
(dir ** "*") (dir ** "*")
.filter(f => !excludes.exists(p => f.absolutePath.startsWith(p.absolutePath))) .filter(f => !excludes.exists(p => f.absolutePath.startsWith(p.absolutePath)))
.pair(sbt.io.Path.relativeTo(dir)) .pair(sbt.io.Path.relativeTo(dir))
.map({case (f, name) => (f, s"docspell-tools-${version}/$name") }) .map({ case (f, name) => (f, s"docspell-tools-${version}/$name") })
IO.zip( IO.zip(
Seq( Seq(

View File

@ -5033,7 +5033,8 @@ components:
fullText: fullText:
type: string type: string
description: | description: |
A query searching the contents of documents. A query searching the contents of documents. If only this
field is set, then a fulltext-only search is done.
corrOrg: corrOrg:
type: string type: string
format: ident format: ident

View File

@ -3,6 +3,7 @@ package docspell.restserver.routes
import cats.data.NonEmptyList import cats.data.NonEmptyList
import cats.effect._ import cats.effect._
import cats.implicits._ import cats.implicits._
import cats.Monoid
import docspell.backend.BackendApp import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken import docspell.backend.auth.AuthToken
@ -10,7 +11,7 @@ import docspell.backend.ops.OCustomFields.{RemoveValue, SetValue}
import docspell.backend.ops.OFulltext import docspell.backend.ops.OFulltext
import docspell.backend.ops.OItemSearch.Batch import docspell.backend.ops.OItemSearch.Batch
import docspell.common.syntax.all._ import docspell.common.syntax.all._
import docspell.common.{Ident, ItemState} import docspell.common._
import docspell.restapi.model._ import docspell.restapi.model._
import docspell.restserver.Config import docspell.restserver.Config
import docspell.restserver.conv.Conversions import docspell.restserver.conv.Conversions
@ -51,8 +52,19 @@ object ItemRoutes {
_ <- logger.ftrace(s"Got search mask: $mask") _ <- logger.ftrace(s"Got search mask: $mask")
query = Conversions.mkQuery(mask, user.account) query = Conversions.mkQuery(mask, user.account)
_ <- logger.ftrace(s"Running query: $query") _ <- logger.ftrace(s"Running query: $query")
resp <- mask.fullText match { resp <- mask match {
case Some(fq) if cfg.fullTextSearch.enabled => case SearchFulltextOnly(ftq) if cfg.fullTextSearch.enabled =>
val ftsIn = OFulltext.FtsInput(ftq.query)
for {
items <- backend.fulltext.findIndexOnly(cfg.maxNoteLength)(
ftsIn,
user.account,
Batch(mask.offset, mask.limit).restrictLimitTo(cfg.maxItemPageSize)
)
ok <- Ok(Conversions.mkItemListWithTagsFtsPlain(items))
} yield ok
case SearchWithFulltext(fq) if cfg.fullTextSearch.enabled =>
for { for {
items <- backend.fulltext.findItems(cfg.maxNoteLength)( items <- backend.fulltext.findItems(cfg.maxNoteLength)(
query, query,
@ -61,6 +73,7 @@ object ItemRoutes {
) )
ok <- Ok(Conversions.mkItemListFts(items)) ok <- Ok(Conversions.mkItemListFts(items))
} yield ok } yield ok
case _ => case _ =>
for { for {
items <- backend.itemSearch.findItems(cfg.maxNoteLength)( items <- backend.itemSearch.findItems(cfg.maxNoteLength)(
@ -78,8 +91,19 @@ object ItemRoutes {
_ <- logger.ftrace(s"Got search mask: $mask") _ <- logger.ftrace(s"Got search mask: $mask")
query = Conversions.mkQuery(mask, user.account) query = Conversions.mkQuery(mask, user.account)
_ <- logger.ftrace(s"Running query: $query") _ <- logger.ftrace(s"Running query: $query")
resp <- mask.fullText match { resp <- mask match {
case Some(fq) if cfg.fullTextSearch.enabled => case SearchFulltextOnly(ftq) if cfg.fullTextSearch.enabled =>
val ftsIn = OFulltext.FtsInput(ftq.query)
for {
items <- backend.fulltext.findIndexOnly(cfg.maxNoteLength)(
ftsIn,
user.account,
Batch(mask.offset, mask.limit).restrictLimitTo(cfg.maxItemPageSize)
)
ok <- Ok(Conversions.mkItemListWithTagsFtsPlain(items))
} yield ok
case SearchWithFulltext(fq) if cfg.fullTextSearch.enabled =>
for { for {
items <- backend.fulltext.findItemsWithTags(cfg.maxNoteLength)( items <- backend.fulltext.findItemsWithTags(cfg.maxNoteLength)(
query, query,
@ -390,4 +414,40 @@ object ItemRoutes {
def notEmpty: Option[String] = def notEmpty: Option[String] =
opt.map(_.trim).filter(_.nonEmpty) opt.map(_.trim).filter(_.nonEmpty)
} }
object SearchFulltextOnly {
implicit private val identMonoid: Monoid[Ident] =
Monoid.instance(Ident.unsafe(""), _ / _)
implicit private val timestampMonoid: Monoid[Timestamp] =
Monoid.instance(Timestamp.Epoch, (a, _) => a)
implicit private val directionMonoid: Monoid[Direction] =
Monoid.instance(Direction.Incoming, (a, _) => a)
implicit private val idListMonoid: Monoid[IdList] =
Monoid.instance(IdList(Nil), (a, b) => IdList(a.ids ++ b.ids))
implicit private val boolMonoid: Monoid[Boolean] =
Monoid.instance(false, _ || _)
private val itemSearchMonoid: Monoid[ItemSearch] =
cats.derived.semiauto.monoid
def unapply(m: ItemSearch): Option[ItemFtsSearch] =
m.fullText match {
case Some(fq) =>
val me = m.copy(fullText = None, offset = 0, limit = 0)
if (itemSearchMonoid.empty == me)
Some(ItemFtsSearch(m.offset, m.limit, fq))
else None
case _ =>
None
}
}
object SearchWithFulltext {
def unapply(m: ItemSearch): Option[String] =
m.fullText
}
} }

View File

@ -335,10 +335,13 @@ personMatchesOrg model =
Comp.Dropdown.getSelected model.corrOrgModel Comp.Dropdown.getSelected model.corrOrgModel
|> List.head |> List.head
persOrg = pers =
Comp.Dropdown.getSelected model.corrPersonModel Comp.Dropdown.getSelected model.corrPersonModel
|> List.head |> List.head
persOrg =
pers
|> Maybe.andThen (\idref -> Dict.get idref.id model.allPersons) |> Maybe.andThen (\idref -> Dict.get idref.id model.allPersons)
|> Maybe.andThen .organization |> Maybe.andThen .organization
in in
org == Nothing || org == persOrg org == Nothing || pers == Nothing || org == persOrg

View File

@ -2,8 +2,12 @@ module Comp.SearchMenu exposing
( Model ( Model
, Msg(..) , Msg(..)
, NextState , NextState
, TextSearchModel
, getItemSearch , getItemSearch
, init , init
, isFulltextSearch
, isNamesSearch
, textSearchString
, update , update
, updateDrop , updateDrop
, view , view
@ -66,18 +70,21 @@ type alias Model =
, untilDueDateModel : DatePicker , untilDueDateModel : DatePicker
, untilDueDate : Maybe Int , untilDueDate : Maybe Int
, nameModel : Maybe String , nameModel : Maybe String
, allNameModel : Maybe String , textSearchModel : TextSearchModel
, fulltextModel : Maybe String
, datePickerInitialized : Bool , datePickerInitialized : Bool
, showNameHelp : Bool
, customFieldModel : Comp.CustomFieldMultiInput.Model , customFieldModel : Comp.CustomFieldMultiInput.Model
, customValues : CustomFieldValueCollect , customValues : CustomFieldValueCollect
, sourceModel : Maybe String , sourceModel : Maybe String
} }
init : Model type TextSearchModel
init = = Fulltext (Maybe String)
| Names (Maybe String)
init : Flags -> Model
init flags =
{ tagSelectModel = Comp.TagSelect.init Comp.TagSelect.emptySelection [] { tagSelectModel = Comp.TagSelect.init Comp.TagSelect.emptySelection []
, tagSelection = Comp.TagSelect.emptySelection , tagSelection = Comp.TagSelect.emptySelection
, directionModel = , directionModel =
@ -124,16 +131,87 @@ init =
, untilDueDateModel = Comp.DatePicker.emptyModel , untilDueDateModel = Comp.DatePicker.emptyModel
, untilDueDate = Nothing , untilDueDate = Nothing
, nameModel = Nothing , nameModel = Nothing
, allNameModel = Nothing , textSearchModel =
, fulltextModel = Nothing if flags.config.fullTextSearchEnabled then
Fulltext Nothing
else
Names Nothing
, datePickerInitialized = False , datePickerInitialized = False
, showNameHelp = False
, customFieldModel = Comp.CustomFieldMultiInput.initWith [] , customFieldModel = Comp.CustomFieldMultiInput.initWith []
, customValues = Data.CustomFieldChange.emptyCollect , customValues = Data.CustomFieldChange.emptyCollect
, sourceModel = Nothing , 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 -> Maybe Direction
getDirection model = getDirection model =
let let
@ -164,6 +242,9 @@ getItemSearch model =
else else
"*" ++ s ++ "*" "*" ++ s ++ "*"
textSearch =
textSearchValue model.textSearchModel
in in
{ e { e
| tagsInclude = model.tagSelection.includeTags |> List.map .tag |> List.map .id | tagsInclude = model.tagSelection.includeTags |> List.map .tag |> List.map .id
@ -186,9 +267,9 @@ getItemSearch model =
model.nameModel model.nameModel
|> Maybe.map amendWildcards |> Maybe.map amendWildcards
, allNames = , allNames =
model.allNameModel textSearch.nameSearch
|> Maybe.map amendWildcards |> Maybe.map amendWildcards
, fullText = model.fulltextModel , fullText = textSearch.fullText
, tagCategoriesInclude = model.tagSelection.includeCats |> List.map .name , tagCategoriesInclude = model.tagSelection.includeCats |> List.map .name
, tagCategoriesExclude = model.tagSelection.excludeCats |> List.map .name , tagCategoriesExclude = model.tagSelection.excludeCats |> List.map .name
, customValues = Data.CustomFieldChange.toFieldValues model.customValues , customValues = Data.CustomFieldChange.toFieldValues model.customValues
@ -225,8 +306,13 @@ resetModel model =
, fromDueDate = Nothing , fromDueDate = Nothing
, untilDueDate = Nothing , untilDueDate = Nothing
, nameModel = Nothing , nameModel = Nothing
, allNameModel = Nothing , textSearchModel =
, fulltextModel = Nothing case model.textSearchModel of
Fulltext _ ->
Fulltext Nothing
Names _ ->
Names Nothing
, customFieldModel = , customFieldModel =
Comp.CustomFieldMultiInput.reset Comp.CustomFieldMultiInput.reset
model.customFieldModel model.customFieldModel
@ -257,11 +343,12 @@ type Msg
| GetEquipResp (Result Http.Error EquipmentList) | GetEquipResp (Result Http.Error EquipmentList)
| GetPersonResp (Result Http.Error PersonList) | GetPersonResp (Result Http.Error PersonList)
| SetName String | SetName String
| SetAllName String | SetTextSearch String
| SetFulltext String | SwapTextSearch
| SetFulltextSearch
| SetNamesSearch
| ResetForm | ResetForm
| KeyUpMsg (Maybe KeyCode) | KeyUpMsg (Maybe KeyCode)
| ToggleNameHelp
| FolderSelectMsg Comp.FolderSelect.Msg | FolderSelectMsg Comp.FolderSelect.Msg
| GetFolderResp (Result Http.Error FolderList) | GetFolderResp (Result Http.Error FolderList)
| SetCorrOrg IdName | SetCorrOrg IdName
@ -641,27 +728,59 @@ updateDrop ddm flags settings msg model =
, dragDrop = DD.DragDropData ddm Nothing , dragDrop = DD.DragDropData ddm Nothing
} }
SetAllName str -> SetTextSearch str ->
let { model = { model | textSearchModel = updateTextSearch str model.textSearchModel }
next =
Util.Maybe.fromString str
in
{ model = { model | allNameModel = next }
, cmd = Cmd.none , cmd = Cmd.none
, stateChange = False , stateChange = False
, dragDrop = DD.DragDropData ddm Nothing , dragDrop = DD.DragDropData ddm Nothing
} }
SetFulltext str -> SwapTextSearch ->
let if flags.config.fullTextSearchEnabled then
next = { model = { model | textSearchModel = swapTextSearch model.textSearchModel }
Util.Maybe.fromString str , cmd = Cmd.none
in , stateChange = False
{ model = { model | fulltextModel = next } , dragDrop = DD.DragDropData ddm Nothing
, 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) -> KeyUpMsg (Just Enter) ->
{ model = model { model = model
@ -677,13 +796,6 @@ updateDrop ddm flags settings msg model =
, dragDrop = DD.DragDropData ddm Nothing , 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) -> GetFolderResp (Ok fs) ->
let let
model_ = 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 , div
[ classList [ classList
[ ( segmentClass, True ) [ ( segmentClass, True )
@ -883,68 +1043,6 @@ viewDrop ddd flags settings model =
model.customFieldModel 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 , div
[ classList [ classList
[ ( segmentClass, True ) [ ( segmentClass, True )

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@ object Dependencies {
val Icu4jVersion = "68.1" val Icu4jVersion = "68.1"
val JsoupVersion = "1.13.1" val JsoupVersion = "1.13.1"
val KindProjectorVersion = "0.10.3" val KindProjectorVersion = "0.10.3"
val KittensVersion = "2.2.0"
val LevigoJbig2Version = "2.0" val LevigoJbig2Version = "2.0"
val Log4sVersion = "1.9.0" val Log4sVersion = "1.9.0"
val LogbackVersion = "1.2.3" val LogbackVersion = "1.2.3"
@ -41,6 +42,11 @@ object Dependencies {
val JQueryVersion = "3.5.1" val JQueryVersion = "3.5.1"
val ViewerJSVersion = "0.5.8" val ViewerJSVersion = "0.5.8"
val kittens = Seq(
"org.typelevel" %% "kittens" % KittensVersion
)
val calevCore = Seq( val calevCore = Seq(
"com.github.eikek" %% "calev-core" % CalevVersion "com.github.eikek" %% "calev-core" % CalevVersion
) )