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 =
--TODO escape quotes
surround "\""
String.replace "\"" "\\\""
>> surround "\""
in
case q of
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.MultiEditMenu exposing (SaveNameState(..))
import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.YesNoDimmer
import Data.Flags exposing (Flags)
@ -56,7 +57,7 @@ type alias Model =
, dragDropData : DD.DragDropData
, scrollToCard : Maybe String
, searchStats : SearchStats
, powerSearchInput : Maybe String
, powerSearchInput : Comp.PowerSearchInput.Model
}
@ -122,7 +123,7 @@ init flags viewMode =
, scrollToCard = Nothing
, viewMode = viewMode
, searchStats = Api.Model.SearchStats.empty
, powerSearchInput = Nothing
, powerSearchInput = Comp.PowerSearchInput.init
}
@ -196,7 +197,7 @@ type Msg
| SetLinkTarget LinkTarget
| SearchStatsResp (Result Http.Error SearchStats)
| TogglePreviewFullWidth
| SetPowerSearch String
| PowerSearchMsg Comp.PowerSearchInput.Msg
| KeyUpPowerSearchbarMsg (Maybe KeyCode)
@ -247,7 +248,7 @@ doSearchDefaultCmd param model =
Q.request <|
Q.and
[ Comp.SearchMenu.getItemQuery model.searchMenuModel
, Maybe.map Q.Fragment model.powerSearchInput
, Maybe.map Q.Fragment model.powerSearchInput.input
]
mask =

View File

@ -1,15 +1,14 @@
module Page.Home.Update exposing (update)
import Api
import Api.Model.IdList exposing (IdList)
import Api.Model.ItemLightList exposing (ItemLightList)
import Api.Model.ItemQuery
import Browser.Navigation as Nav
import Comp.FixedDropdown
import Comp.ItemCardList
import Comp.ItemDetail.FormChange exposing (FormChange(..))
import Comp.ItemDetail.MultiEditMenu exposing (SaveNameState(..))
import Comp.LinkTarget exposing (LinkTarget)
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.YesNoDimmer
import Data.Flags exposing (Flags)
@ -54,7 +53,7 @@ update mId key flags settings msg model =
ResetSearch ->
let
nm =
{ model | searchOffset = 0, powerSearchInput = Nothing }
{ model | searchOffset = 0, powerSearchInput = Comp.PowerSearchInput.init }
in
update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm
@ -580,8 +579,23 @@ update mId key flags settings msg model =
in
noSub ( model, cmd )
SetPowerSearch str ->
noSub ( { model | powerSearchInput = Util.Maybe.fromString str }, Cmd.none )
PowerSearchMsg lm ->
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) ->
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.ItemCardList
import Comp.MenuBar as MB
import Comp.PowerSearchInput
import Comp.SearchMenu
import Comp.SearchStatsView
import Comp.YesNoDimmer
@ -135,17 +136,12 @@ defaultMenuBar _ settings model =
powerSearchBar =
div
[ class "relative flex flex-grow flex-row" ]
[ input
[ type_ "text"
, placeholder "Search query "
, onInput SetPowerSearch
, Util.Html.onKeyUpCode KeyUpPowerSearchbarMsg
, Maybe.map value model.powerSearchInput
|> Maybe.withDefault (value "")
, class S.textInput
, class "text-sm "
]
[]
[ Html.map PowerSearchMsg
(Comp.PowerSearchInput.viewInput []
model.powerSearchInput
)
, Html.map PowerSearchMsg
(Comp.PowerSearchInput.viewResult [] model.powerSearchInput)
]
in
MB.view

View File

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

View File

@ -43,7 +43,12 @@ errorMessage =
warnMessage : String
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

View File

@ -97,3 +97,29 @@ elmApp.ports.initClipboard.subscribe(function(args) {
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);
}
});