Check query in client

This commit is contained in:
Eike Kettner
2021-03-07 23:46:31 +01:00
parent 31e2e99c36
commit c6032ff279
9 changed files with 267 additions and 24 deletions

View File

@ -0,0 +1,177 @@
module Comp.PowerSearchInput exposing
( Action(..)
, Model
, Msg
, init
, update
, viewInput
, viewResult
)
import Data.DropdownStyle
import Data.QueryParseResult exposing (QueryParseResult)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import Ports
import Styles as S
import Throttle exposing (Throttle)
import Time
import Util.Html exposing (KeyCode(..))
import Util.Maybe
type alias Model =
{ input : Maybe String
, result : QueryParseResult
, parseThrottle : Throttle Msg
}
init : Model
init =
{ input = Nothing
, result = Data.QueryParseResult.success
, parseThrottle = Throttle.create 1
}
type Msg
= SetSearch String
| KeyUpMsg (Maybe KeyCode)
| ParseResultMsg QueryParseResult
| UpdateThrottle
type Action
= NoAction
| SubmitSearch
type alias Result =
{ model : Model
, cmd : Cmd Msg
, action : Action
, subs : Sub Msg
}
--- Update
update : Msg -> Model -> Result
update msg model =
case msg of
SetSearch str ->
let
parseCmd =
Ports.checkSearchQueryString str
parseSub =
Ports.receiveCheckQueryResult ParseResultMsg
( newThrottle, cmd ) =
Throttle.try parseCmd model.parseThrottle
model_ =
{ model
| input = Util.Maybe.fromString str
, parseThrottle = newThrottle
, result =
if str == "" then
Data.QueryParseResult.success
else
model.result
}
in
{ model = model_
, cmd = cmd
, action = NoAction
, subs = Sub.batch [ throttleUpdate model_, parseSub ]
}
KeyUpMsg (Just Enter) ->
Result model Cmd.none SubmitSearch Sub.none
KeyUpMsg _ ->
let
parseSub =
Ports.receiveCheckQueryResult ParseResultMsg
in
Result model Cmd.none NoAction (Sub.batch [ throttleUpdate model, parseSub ])
ParseResultMsg lm ->
Result { model | result = lm } Cmd.none NoAction Sub.none
UpdateThrottle ->
let
parseSub =
Ports.receiveCheckQueryResult ParseResultMsg
( newThrottle, cmd ) =
Throttle.update model.parseThrottle
model_ =
{ model | parseThrottle = newThrottle }
in
{ model = model_
, cmd = cmd
, action = NoAction
, subs = Sub.batch [ throttleUpdate model_, parseSub ]
}
throttleUpdate : Model -> Sub Msg
throttleUpdate model =
Throttle.ifNeeded
(Time.every 100 (\_ -> UpdateThrottle))
model.parseThrottle
--- View
viewInput : List (Attribute Msg) -> Model -> Html Msg
viewInput attrs model =
input
(attrs
++ [ type_ "text"
, placeholder "Search query "
, onInput SetSearch
, Util.Html.onKeyUpCode KeyUpMsg
, Maybe.map value model.input
|> Maybe.withDefault (value "")
, class S.textInput
, class "text-sm "
]
)
[]
viewResult : List ( String, Bool ) -> Model -> Html Msg
viewResult classes model =
div
[ classList [ ( "hidden", model.result.success ) ]
, classList classes
, class resultStyle
]
[ p [ class "font-mono text-sm" ]
[ text model.result.input
]
, pre [ class "font-mono text-sm" ]
[ List.repeat model.result.index " "
|> String.join ""
|> text
, text "^"
]
, ul []
(List.map (\line -> li [] [ text line ]) model.result.messages)
]
resultStyle : String
resultStyle =
S.warnMessageColors ++ " absolute left-0 max-h-44 w-full overflow-y-auto z-50 shadow-lg transition duration-200 top-9 border-0 border-b border-l border-r rounded-b px-2 py-2"

View File

@ -106,8 +106,8 @@ render q =
"=" "="
quoteStr = quoteStr =
--TODO escape quotes String.replace "\"" "\\\""
surround "\"" >> surround "\""
in in
case q of case q of
And inner -> And inner ->

View File

@ -0,0 +1,14 @@
module Data.QueryParseResult exposing (QueryParseResult, success)
type alias QueryParseResult =
{ success : Bool
, input : String
, index : Int
, messages : List String
}
success : QueryParseResult
success =
QueryParseResult True "" 0 []

View File

@ -27,6 +27,7 @@ import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange) import Comp.ItemDetail.FormChange exposing (FormChange)
import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..)) import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
import Comp.LinkTarget exposing (LinkTarget) import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu import Comp.SearchMenu
import Comp.YesNoDimmer import Comp.YesNoDimmer
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
@ -56,7 +57,7 @@ type alias Model =
, dragDropData : DD.DragDropData , dragDropData : DD.DragDropData
, scrollToCard : Maybe String , scrollToCard : Maybe String
, searchStats : SearchStats , searchStats : SearchStats
, powerSearchInput : Maybe String , powerSearchInput : Comp.PowerSearchInput.Model
} }
@ -122,7 +123,7 @@ init flags viewMode =
, scrollToCard = Nothing , scrollToCard = Nothing
, viewMode = viewMode , viewMode = viewMode
, searchStats = Api.Model.SearchStats.empty , searchStats = Api.Model.SearchStats.empty
, powerSearchInput = Nothing , powerSearchInput = Comp.PowerSearchInput.init
} }
@ -196,7 +197,7 @@ type Msg
| SetLinkTarget LinkTarget | SetLinkTarget LinkTarget
| SearchStatsResp (Result Http.Error SearchStats) | SearchStatsResp (Result Http.Error SearchStats)
| TogglePreviewFullWidth | TogglePreviewFullWidth
| SetPowerSearch String | PowerSearchMsg Comp.PowerSearchInput.Msg
| KeyUpPowerSearchbarMsg (Maybe KeyCode) | KeyUpPowerSearchbarMsg (Maybe KeyCode)
@ -247,7 +248,7 @@ doSearchDefaultCmd param model =
Q.request <| Q.request <|
Q.and Q.and
[ Comp.SearchMenu.getItemQuery model.searchMenuModel [ Comp.SearchMenu.getItemQuery model.searchMenuModel
, Maybe.map Q.Fragment model.powerSearchInput , Maybe.map Q.Fragment model.powerSearchInput.input
] ]
mask = mask =

View File

@ -1,15 +1,14 @@
module Page.Home.Update exposing (update) module Page.Home.Update exposing (update)
import Api import Api
import Api.Model.IdList exposing (IdList)
import Api.Model.ItemLightList exposing (ItemLightList) import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemQuery
import Browser.Navigation as Nav import Browser.Navigation as Nav
import Comp.FixedDropdown import Comp.FixedDropdown
import Comp.ItemCardList import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange(..)) import Comp.ItemDetail.FormChange exposing (FormChange(..))
import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..)) import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
import Comp.LinkTarget exposing (LinkTarget) import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu import Comp.SearchMenu
import Comp.YesNoDimmer import Comp.YesNoDimmer
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
@ -54,7 +53,7 @@ update mId key flags settings msg model =
ResetSearch -> ResetSearch ->
let let
nm = nm =
{ model | searchOffset = 0, powerSearchInput = Nothing } { model | searchOffset = 0, powerSearchInput = Comp.PowerSearchInput.init }
in in
update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm
@ -580,8 +579,23 @@ update mId key flags settings msg model =
in in
noSub ( model, cmd ) noSub ( model, cmd )
SetPowerSearch str -> PowerSearchMsg lm ->
noSub ( { model | powerSearchInput = Util.Maybe.fromString str }, Cmd.none ) let
result =
Comp.PowerSearchInput.update lm model.powerSearchInput
cmd_ =
Cmd.map PowerSearchMsg result.cmd
model_ =
{ model | powerSearchInput = result.model }
in
case result.action of
Comp.PowerSearchInput.NoAction ->
( model_, cmd_, Sub.map PowerSearchMsg result.subs )
Comp.PowerSearchInput.SubmitSearch ->
update mId key flags settings (DoSearch model_.searchTypeDropdownValue) model_
KeyUpPowerSearchbarMsg (Just Enter) -> KeyUpPowerSearchbarMsg (Just Enter) ->
update mId key flags settings (DoSearch model.searchTypeDropdownValue) model update mId key flags settings (DoSearch model.searchTypeDropdownValue) model

View File

@ -3,6 +3,7 @@ module Page.Home.View2 exposing (viewContent, viewSidebar)
import Comp.Basic as B import Comp.Basic as B
import Comp.ItemCardList import Comp.ItemCardList
import Comp.MenuBar as MB import Comp.MenuBar as MB
import Comp.PowerSearchInput
import Comp.SearchMenu import Comp.SearchMenu
import Comp.SearchStatsView import Comp.SearchStatsView
import Comp.YesNoDimmer import Comp.YesNoDimmer
@ -135,17 +136,12 @@ defaultMenuBar _ settings model =
powerSearchBar = powerSearchBar =
div div
[ class "relative flex flex-grow flex-row" ] [ class "relative flex flex-grow flex-row" ]
[ input [ Html.map PowerSearchMsg
[ type_ "text" (Comp.PowerSearchInput.viewInput []
, placeholder "Search query " model.powerSearchInput
, onInput SetPowerSearch )
, Util.Html.onKeyUpCode KeyUpPowerSearchbarMsg , Html.map PowerSearchMsg
, Maybe.map value model.powerSearchInput (Comp.PowerSearchInput.viewResult [] model.powerSearchInput)
|> Maybe.withDefault (value "")
, class S.textInput
, class "text-sm "
]
[]
] ]
in in
MB.view MB.view

View File

@ -1,8 +1,10 @@
port module Ports exposing port module Ports exposing
( getUiSettings ( checkSearchQueryString
, getUiSettings
, initClipboard , initClipboard
, loadUiSettings , loadUiSettings
, onUiSettingsSaved , onUiSettingsSaved
, receiveCheckQueryResult
, removeAccount , removeAccount
, setAccount , setAccount
, setUiTheme , setUiTheme
@ -10,7 +12,9 @@ port module Ports exposing
) )
import Api.Model.AuthResult exposing (AuthResult) import Api.Model.AuthResult exposing (AuthResult)
import Api.Model.BasicResult exposing (BasicResult)
import Data.Flags exposing (Flags) import Data.Flags exposing (Flags)
import Data.QueryParseResult exposing (QueryParseResult)
import Data.UiSettings exposing (StoredUiSettings, UiSettings) import Data.UiSettings exposing (StoredUiSettings, UiSettings)
import Data.UiTheme exposing (UiTheme) import Data.UiTheme exposing (UiTheme)
@ -38,6 +42,12 @@ port uiSettingsSaved : (() -> msg) -> Sub msg
port internalSetUiTheme : String -> Cmd msg port internalSetUiTheme : String -> Cmd msg
port checkSearchQueryString : String -> Cmd msg
port receiveCheckQueryResult : (QueryParseResult -> msg) -> Sub msg
setUiTheme : UiTheme -> Cmd msg setUiTheme : UiTheme -> Cmd msg
setUiTheme theme = setUiTheme theme =
internalSetUiTheme (Data.UiTheme.toString theme) internalSetUiTheme (Data.UiTheme.toString theme)

View File

@ -43,7 +43,12 @@ errorMessage =
warnMessage : String warnMessage : String
warnMessage = warnMessage =
" border border-yellow-800 bg-yellow-50 text-yellow-800 dark:border-amber-200 dark:bg-amber-800 dark:text-amber-200 dark:bg-opacity-25 px-2 py-2 rounded " warnMessageColors ++ " border dark:bg-opacity-25 px-2 py-2 rounded "
warnMessageColors : String
warnMessageColors =
" border-yellow-800 bg-yellow-50 text-yellow-800 dark:border-amber-200 dark:bg-amber-800 dark:text-amber-200 "
infoMessage : String infoMessage : String

View File

@ -97,3 +97,29 @@ elmApp.ports.initClipboard.subscribe(function(args) {
docspell_clipboards[page] = new ClipboardJS(sel); docspell_clipboards[page] = new ClipboardJS(sel);
} }
}); });
elmApp.ports.checkSearchQueryString.subscribe(function(args) {
var qStr = args;
if (qStr && DsItemQueryParser && DsItemQueryParser['parseToFailure']) {
var result = DsItemQueryParser.parseToFailure(qStr);
var answer;
if (result) {
answer =
{ success: false,
input: result.input,
index: result.failedAt,
messages: result.messages
};
} else {
answer =
{ success: true,
input: qStr,
index: 0,
messages: []
};
}
console.log("Sending: " + answer.success);
elmApp.ports.receiveCheckQueryResult.send(answer);
}
});