remove suggestions feature (#141)

This commit is contained in:
Rok Garbas 2020-07-24 23:01:16 +02:00 committed by GitHub
parent 3bf4907596
commit 44cbea8547
Failed to generate hash of commit
14 changed files with 78 additions and 715 deletions

View file

@ -1 +1 @@
9
10

View file

@ -10,11 +10,6 @@
version = "1.1.3";
};
"ohanhi/keyboard" = {
sha256 = "10sbq8v2kydnc3lkydl367g36q2b0xizxl031xyakrgl4zlh07ic";
version = "2.0.1";
};
"truqu/elm-base64" = {
sha256 = "12w68b4idbs2vn0gm0lj354pm745jb7n0fj69408mpvh5r1z4m1b";
version = "2.0.4";
@ -35,16 +30,6 @@
version = "1.0.2";
};
"Gizra/elm-debouncer" = {
sha256 = "009yw0rb418ar2a458ilr25m8gxrxsv5nvs3ld3l6sy12v12n0yn";
version = "2.0.0";
};
"Skinney/keyboard-events" = {
sha256 = "10qjlpa4byk78sra071w4ghc7b9p2brnppx7aqyy9cmbrmp5nf86";
version = "2.0.1";
};
"elm/core" = {
sha256 = "0gyk7lx3b6vx2jlfbxdsb4xffn0wdvg5yxldq50jr2kk5dzc2prj";
version = "1.0.4";
@ -90,11 +75,6 @@
version = "1.1.0";
};
"elm-community/list-extra" = {
sha256 = "1rvr1c8cfb3dwf3li17l9ziax6d1fshkliasspnw6rviva38lw34";
version = "8.2.4";
};
"elm/time" = {
sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1";
version = "1.0.0";

View file

@ -1,43 +1,39 @@
{
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"Gizra/elm-debouncer": "2.0.0",
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
"Skinney/keyboard-events": "2.0.1",
"elm/browser": "1.0.2",
"elm/core": "1.0.4",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/regex": "1.0.0",
"elm/url": "1.0.0",
"hecrj/html-parser": "2.3.4",
"krisajenkins/remotedata": "6.0.1",
"ohanhi/keyboard": "2.0.1",
"truqu/elm-base64": "2.0.4"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2",
"elm-community/list-extra": "8.2.4",
"rtfeldman/elm-hex": "1.0.0"
}
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
"elm/browser": "1.0.2",
"elm/core": "1.0.4",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/regex": "1.0.0",
"elm/url": "1.0.0",
"hecrj/html-parser": "2.3.4",
"krisajenkins/remotedata": "6.0.1",
"truqu/elm-base64": "2.0.4"
},
"test-dependencies": {
"direct": {
"elm-explorations/test": "1.2.2"
},
"indirect": {
"elm/random": "1.0.0",
"elm/svg": "1.0.1"
}
"indirect": {
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2",
"rtfeldman/elm-hex": "1.0.0"
}
},
"test-dependencies": {
"direct": {
"elm-explorations/test": "1.2.2"
},
"indirect": {
"elm/random": "1.0.0",
"elm/svg": "1.0.1"
}
}
}

View file

@ -1,14 +1,12 @@
{
"nodes": {
"nixpkgs": {
"info": {
"lastModified": 1592376843,
"narHash": "sha256-vKchUGsNMQC9vCmTnpssHMV/+cKXA5QhbEoFm0zua1U="
},
"locked": {
"lastModified": 1595175601,
"narHash": "sha256-NMxaD3mdKyp+6nidFkZe7XOzVXtWMpOH1v4KYZxo/Z0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "14fcd947a0150b78d7a37bef56c87fcd57808247",
"rev": "5717d9d2f7ca0662291910c52f1d7b95b568fec2",
"type": "github"
},
"original": {
@ -18,14 +16,12 @@
}
},
"nixpkgs_2": {
"info": {
"lastModified": 1592514044,
"narHash": "sha256-jGQJmq14vh9ASt9d5Z9yBPsrbUgroiNVNhsoBabsw0k="
},
"locked": {
"lastModified": 1595619256,
"narHash": "sha256-TOSvHwfQevzE/uTFBWYAt1I/F9F3YRkOV8gUrqUQfkk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e051dab9ff8a58455f6b8375856ac2802c6cd261",
"rev": "fd0febffda9af90d6d369ecb4cb9aaf347116bce",
"type": "github"
},
"original": {
@ -34,17 +30,15 @@
}
},
"poetry2nix": {
"info": {
"lastModified": 1592121810,
"narHash": "sha256-9cGTKtL7JpllwABxa4iRVU4Qw/YwniLni4RATyONz+s="
},
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1595517229,
"narHash": "sha256-5eMk3+Twb2fDyFX5sm33JYSRaPAvKe9vHV5w/HjbiHs=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "e7c69a288c10e4d97816fdabda5ae3f38e21914e",
"rev": "270a0b26b773e566ad59927c51d40a5e9b8ff08d",
"type": "github"
},
"original": {
@ -61,5 +55,5 @@
}
},
"root": "root",
"version": 5
"version": 7
}

View file

@ -16,7 +16,6 @@ import shlex
import subprocess
import sys
import tqdm # type: ignore
import typing
import xml.etree.ElementTree
logger = logging.getLogger("import-channel")
@ -47,12 +46,6 @@ MAPPING = {
"properties": {
"type": {"type": "keyword"},
# Package fields
"package_suggestions": {
"type": "completion",
"analyzer": "lowercase",
"search_analyzer": "lowercase",
"preserve_position_increments": False,
},
"package_hydra_build": {
"type": "nested",
"properties": {
@ -96,12 +89,6 @@ MAPPING = {
"package_homepage": {"type": "keyword"},
"package_system": {"type": "keyword"},
# Options fields
"option_suggestions": {
"type": "completion",
"analyzer": "lowercase",
"search_analyzer": "lowercase",
"preserve_position_increments": False,
},
"option_name": {"type": "keyword", "normalizer": "lowercase"},
"option_name_query": {"type": "keyword", "normalizer": "lowercase"},
"option_description": {"type": "text"},
@ -113,28 +100,6 @@ MAPPING = {
}
def parse_suggestions(text: str) -> typing.List[typing.Dict[str, object]]:
"""Tokenize option_name
Example:
services.nginx.extraConfig
- services.nginx.extraConfig
- services.nginx.
- services.
"""
results: typing.List[typing.Dict[str, object]] = [
{"input": text, "weight": 1000 - (((len(text.split(".")) - 1) * 10))},
]
for i in range(len(text.split(".")) - 1):
result = {
"input": ".".join(text.split(".")[: -(i + 1)]) + ".",
"weight": 1000 - ((len(text.split(".")) - 2 - i) * 10) + 1,
}
results.append(result)
return results
def parse_query(text):
"""Tokenize package attr_name
@ -371,7 +336,6 @@ def get_packages(evaluation, evaluation_builds):
yield dict(
type="package",
package_suggestions=parse_suggestions(attr_name),
package_hydra=hydra,
package_attr_name=attr_name,
package_attr_name_query=list(parse_query(attr_name)),
@ -438,7 +402,6 @@ def get_options(evaluation):
yield dict(
type="option",
option_suggestions=parse_suggestions(name),
option_name=name,
option_name_query=parse_query(name),
option_description=description,

View file

@ -1,52 +0,0 @@
module Example exposing (fuzzTest, unitTest, viewTest)
import Expect exposing (Expectation)
import Fuzz exposing (Fuzzer, int, list, string)
import Main exposing (..)
import Test exposing (..)
import Test.Html.Query as Query
import Test.Html.Selector exposing (tag, text)
{-| See <https://github.com/elm-community/elm-test>
-}
unitTest : Test
unitTest =
describe "simple unit test"
[ test "Inc adds one" <|
\() ->
update Inc (Model 0 "")
|> Tuple.first
|> .counter
|> Expect.equal 1
]
{-| See <https://github.com/elm-community/elm-test>
-}
fuzzTest : Test
fuzzTest =
describe "simple fuzz test"
[ fuzz int "Inc ALWAYS adds one" <|
\ct ->
update Inc (Model ct "")
|> Tuple.first
|> .counter
|> Expect.equal (ct + 1)
]
{-| see <https://github.com/eeue56/elm-html-test>
-}
viewTest : Test
viewTest =
describe "Testing view function"
[ test "Button has the expected text" <|
\() ->
Model 0 ""
|> view
|> Query.fromHtml
|> Query.findAll [ tag "button" ]
|> Query.first
|> Query.has [ text "+ 1" ]
]

View file

@ -1,42 +1,6 @@
import pytest # type: ignore
@pytest.mark.parametrize(
"text,expected",
[
(
"services.grafana.analytics.reporting.enable",
[
{"input": "services.grafana.analytics.reporting.enable", "weight": 960},
{"input": "services.grafana.analytics.reporting.", "weight": 971},
{"input": "services.grafana.analytics.", "weight": 981},
{"input": "services.grafana.", "weight": 991},
{"input": "services.", "weight": 1001},
],
),
(
"services.nginx.extraConfig",
[
{"input": "services.nginx.extraConfig", "weight": 980},
{"input": "services.nginx.", "weight": 991},
{"input": "services.", "weight": 1001},
],
),
(
"python37Packages.test1_name-test2",
[
{"input": "python37Packages.test1_name-test2", "weight": 990},
{"input": "python37Packages.", "weight": 1001},
],
),
],
)
def test_parse_suggestions(text, expected):
import import_scripts.channel
assert import_scripts.channel.parse_suggestions(text) == expected
@pytest.mark.parametrize(
"text,expected",
[

View file

@ -240,11 +240,11 @@ update msg model =
|> updateWith Home HomeMsg model
( PackagesMsg subMsg, Packages subModel ) ->
Page.Packages.update model.navKey model.elasticsearch subMsg subModel
Page.Packages.update model.navKey subMsg subModel
|> updateWith Packages PackagesMsg model
( OptionsMsg subMsg, Options subModel ) ->
Page.Options.update model.navKey model.elasticsearch subMsg subModel
Page.Options.update model.navKey subMsg subModel
|> updateWith Options OptionsMsg model
( _, _ ) ->

View file

@ -26,7 +26,9 @@ type Msg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
( model, Cmd.none )
case msg of
NoOp ->
( model, Cmd.none )
@ -34,5 +36,5 @@ update msg model =
view : Model -> Html Msg
view model =
view _ =
div [] [ text "Home" ]

View file

@ -17,8 +17,6 @@ import Html
, div
, dl
, dt
, li
, p
, pre
, span
, table
@ -28,7 +26,6 @@ import Html
, th
, thead
, tr
, ul
)
import Html.Attributes
exposing
@ -42,7 +39,6 @@ import Html.Events
)
import Html.Parser
import Html.Parser.Util
import Http
import Json.Decode
import Json.Encode
import Regex
@ -94,8 +90,12 @@ type Msg
= SearchMsg (Search.Msg ResultItemSource)
update : Browser.Navigation.Key -> Search.Options -> Msg -> Model -> ( Model, Cmd Msg )
update navKey options msg model =
update :
Browser.Navigation.Key
-> Msg
-> Model
-> ( Model, Cmd Msg )
update navKey msg model =
case msg of
SearchMsg subMsg ->
let
@ -103,9 +103,6 @@ update navKey options msg model =
Search.update
"options"
navKey
"option"
options
decodeResultItemSource
subMsg
model
in
@ -211,9 +208,6 @@ viewResultItemDetails channel item =
asCode value =
pre [] [ text value ]
asLink value =
a [ href value ] [ text value ]
githubUrlPrefix branch =
"https://github.com/NixOS/nixpkgs-channels/blob/" ++ branch ++ "/"
@ -305,7 +299,7 @@ makeRequest options channel queryRaw from size sort =
[ ( field
, Json.Encode.object
[ ( "query", Json.Encode.string query )
, ( "boost", Json.Encode.float boost )
, ( "boost", Json.Encode.float <| boost_base * boost )
, ( "analyzer", Json.Encode.string "whitespace" )
, ( "fuzziness", Json.Encode.string "1" )
, ( "_name"
@ -332,7 +326,7 @@ makeRequest options channel queryRaw from size sort =
[ ( field
, Json.Encode.object
[ ( "query", Json.Encode.string query )
, ( "boost", Json.Encode.float boost )
, ( "boost", Json.Encode.float <| boost_base * boost )
, ( "analyzer", Json.Encode.string "whitespace" )
, ( "fuzziness", Json.Encode.string "1" )
, ( "_name"

View file

@ -19,7 +19,6 @@ import Html
, dl
, dt
, li
, p
, table
, tbody
, td
@ -39,7 +38,6 @@ import Html.Events
exposing
( onClick
)
import Http
import Json.Decode
import Json.Decode.Pipeline
import Json.Encode
@ -129,8 +127,12 @@ type Msg
= SearchMsg (Search.Msg ResultItemSource)
update : Browser.Navigation.Key -> Search.Options -> Msg -> Model -> ( Model, Cmd Msg )
update navKey options msg model =
update :
Browser.Navigation.Key
-> Msg
-> Model
-> ( Model, Cmd Msg )
update navKey msg model =
case msg of
SearchMsg subMsg ->
let
@ -138,9 +140,6 @@ update navKey options msg model =
Search.update
"packages"
navKey
"package"
options
decodeResultItemSource
subMsg
model
in

View file

@ -15,12 +15,9 @@ module Search exposing
, view
)
import Array
import Base64
import Browser.Dom
import Browser.Navigation
import Debouncer.Messages
import Dict
import Html
exposing
( Html
@ -44,7 +41,6 @@ import Html
import Html.Attributes
exposing
( attribute
, autocomplete
, autofocus
, class
, classList
@ -57,16 +53,13 @@ import Html.Attributes
)
import Html.Events
exposing
( custom
, onClick
( onClick
, onInput
, onSubmit
)
import Http
import Json.Decode
import Json.Encode
import Keyboard
import Keyboard.Events
import RemoteData
import Task
import Url.Builder
@ -75,9 +68,6 @@ import Url.Builder
type alias Model a =
{ channel : String
, query : Maybe String
, queryDebounce : Debouncer.Messages.Debouncer (Msg a)
, querySuggest : RemoteData.WebData (SearchResult a)
, querySelectedSuggestion : Maybe String
, result : RemoteData.WebData (SearchResult a)
, show : Maybe String
, from : Int
@ -88,20 +78,6 @@ type alias Model a =
type alias SearchResult a =
{ hits : ResultHits a
, suggest : Maybe (SearchSuggest a)
}
type alias SearchSuggest a =
{ query : Maybe (List (SearchSuggestQuery a))
}
type alias SearchSuggestQuery a =
{ text : String
, offset : Int
, length : Int
, options : List (ResultItem a)
}
@ -161,25 +137,7 @@ init channel query show from size sort model =
|> Maybe.withDefault 15
in
( { channel = Maybe.withDefault defaultChannel channel
, queryDebounce =
Debouncer.Messages.manual
|> Debouncer.Messages.settleWhenQuietFor (Just <| Debouncer.Messages.fromSeconds 0.4)
|> Debouncer.Messages.toDebouncer
, query = query
, querySuggest =
query
|> Maybe.map
(\selected ->
if String.endsWith "." selected then
model
|> Maybe.map .querySuggest
|> Maybe.withDefault RemoteData.NotAsked
else
RemoteData.NotAsked
)
|> Maybe.withDefault RemoteData.NotAsked
, querySelectedSuggestion = Nothing
, result =
model
|> Maybe.map (\x -> x.result)
@ -207,34 +165,19 @@ type Msg a
= NoOp
| SortChange String
| ChannelChange String
| QueryInputDebounce (Debouncer.Messages.Msg (Msg a))
| QueryInput String
| QueryInputSuggestionsSubmit
| QueryInputSuggestionsResponse (RemoteData.WebData (SearchResult a))
| QueryInputSubmit
| QueryResponse (RemoteData.WebData (SearchResult a))
| ShowDetails String
| SuggestionsMoveDown
| SuggestionsMoveUp
| SuggestionsSelect
| SuggestionsClickSelect String
| SuggestionsClose
update :
String
-> Browser.Navigation.Key
-> String
-> Options
-> Json.Decode.Decoder a
-> Msg a
-> Model a
-> ( Model a, Cmd (Msg a) )
update path navKey result_type options decodeResultItemSource msg model =
let
requestQuerySuggestionsTracker =
"query-" ++ result_type ++ "-suggestions"
in
update path navKey msg model =
case msg of
NoOp ->
( model
@ -283,94 +226,8 @@ update path navKey result_type options decodeResultItemSource msg model =
|> Browser.Navigation.pushUrl navKey
)
QueryInputDebounce subMsg ->
Debouncer.Messages.update
(update path navKey result_type options decodeResultItemSource)
{ mapMsg = QueryInputDebounce
, getDebouncer = .queryDebounce
, setDebouncer = \debouncer m -> { m | queryDebounce = debouncer }
}
subMsg
model
QueryInput query ->
update path
navKey
result_type
options
decodeResultItemSource
(QueryInputDebounce (Debouncer.Messages.provideInput QueryInputSuggestionsSubmit))
{ model
| query = Just query
, querySuggest = RemoteData.Loading
, querySelectedSuggestion = Nothing
}
|> Tuple.mapSecond
(\cmd ->
if RemoteData.isLoading model.querySuggest then
Cmd.batch
[ cmd
, Http.cancel requestQuerySuggestionsTracker
]
else
cmd
)
QueryInputSuggestionsSubmit ->
let
body =
Http.jsonBody
(Json.Encode.object
[ ( "from", Json.Encode.int 0 )
, ( "size", Json.Encode.int 0 )
, ( "suggest"
, Json.Encode.object
[ ( "query"
, Json.Encode.object
[ ( "text", Json.Encode.string (Maybe.withDefault "" model.query) )
, ( "completion"
, Json.Encode.object
[ ( "field", Json.Encode.string (result_type ++ "_suggestions") )
, ( "skip_duplicates", Json.Encode.bool True )
, ( "size", Json.Encode.int 1000 )
]
)
]
)
]
)
]
)
in
( { model
| querySuggest =
model.query
|> Maybe.map
(\selected ->
if String.endsWith "." selected then
model.querySuggest
else
RemoteData.NotAsked
)
|> Maybe.withDefault RemoteData.NotAsked
, querySelectedSuggestion = Nothing
}
, makeRequest
body
("latest-" ++ String.fromInt options.mappingSchemaVersion ++ "-" ++ model.channel)
decodeResultItemSource
options
QueryInputSuggestionsResponse
(Just requestQuerySuggestionsTracker)
)
QueryInputSuggestionsResponse querySuggest ->
( { model
| querySuggest = querySuggest
, querySelectedSuggestion = Nothing
}
( { model | query = Just query }
, Cmd.none
)
@ -414,155 +271,6 @@ update path navKey result_type options decodeResultItemSource msg model =
|> Browser.Navigation.pushUrl navKey
)
SuggestionsMoveDown ->
( { model
| querySelectedSuggestion =
getMovedSuggestion
model.query
model.querySuggest
model.querySelectedSuggestion
(\x -> x + 1)
}
, scrollToSelected "dropdown-menu"
)
SuggestionsMoveUp ->
( { model
| querySelectedSuggestion =
getMovedSuggestion
model.query
model.querySuggest
model.querySelectedSuggestion
(\x -> x - 1)
}
, scrollToSelected "dropdown-menu"
)
SuggestionsSelect ->
case model.querySelectedSuggestion of
Just selected ->
update path
navKey
result_type
options
decodeResultItemSource
(SuggestionsClickSelect selected)
model
Nothing ->
( model
, Task.attempt (\_ -> QueryInputSubmit) (Task.succeed ())
)
SuggestionsClickSelect selected ->
( { model
| querySuggest =
if String.endsWith "." selected then
model.querySuggest
else
RemoteData.NotAsked
, querySelectedSuggestion = Nothing
, query = Just selected
}
, Cmd.batch
[ Task.attempt (\_ -> QueryInputSuggestionsSubmit) (Task.succeed ())
, Task.attempt (\_ -> QueryInputSubmit) (Task.succeed ())
]
)
SuggestionsClose ->
( { model
| querySuggest = RemoteData.NotAsked
, querySelectedSuggestion = Nothing
}
, Cmd.none
)
scrollToSelected :
String
-> Cmd (Msg a)
scrollToSelected id =
let
scroll y =
Browser.Dom.setViewportOf id 0 y
|> Task.onError (\_ -> Task.succeed ())
in
Task.sequence
[ Browser.Dom.getElement (id ++ "-selected")
|> Task.map (\x -> ( x.element.y, x.element.height ))
, Browser.Dom.getElement id
|> Task.map (\x -> ( x.element.y, x.element.height ))
, Browser.Dom.getViewportOf id
|> Task.map (\x -> ( x.viewport.y, x.viewport.height ))
]
|> Task.andThen
(\x ->
case x of
( elementY, elementHeight ) :: ( viewportY, viewportHeight ) :: ( viewportScrollTop, _ ) :: [] ->
let
scrollTop =
scroll (viewportScrollTop + (elementY - viewportY))
scrollBottom =
scroll (viewportScrollTop + (elementY - viewportY) + (elementHeight - viewportHeight))
in
if elementHeight > viewportHeight then
scrollTop
else if elementY < viewportY then
scrollTop
else if elementY + elementHeight > viewportY + viewportHeight then
scrollBottom
else
Task.succeed ()
_ ->
Task.succeed ()
)
|> Task.attempt (\_ -> NoOp)
getMovedSuggestion :
Maybe String
-> RemoteData.WebData (SearchResult a)
-> Maybe String
-> (Int -> Int)
-> Maybe String
getMovedSuggestion query querySuggest querySelectedSuggestion moveIndex =
let
suggestions =
getSuggestions query querySuggest
|> List.filterMap .text
getIndex key =
suggestions
|> List.indexedMap (\i a -> ( a, i ))
|> Dict.fromList
|> Dict.get key
|> Maybe.map moveIndex
|> Maybe.map
(\x ->
if x < 0 then
x + List.length suggestions
else
x
)
getKey index =
suggestions
|> Array.fromList
|> Array.get index
in
querySelectedSuggestion
|> Maybe.andThen getIndex
|> Maybe.withDefault 0
|> getKey
createUrl :
String
@ -736,48 +444,6 @@ fromSortId id =
Nothing
getSuggestions :
Maybe String
-> RemoteData.WebData (SearchResult a)
-> List (ResultItem a)
getSuggestions query querySuggest =
let
maybeList f x =
x
|> Maybe.map f
|> Maybe.withDefault []
in
case querySuggest of
RemoteData.Success result ->
let
suggestions =
result.suggest
|> maybeList (\x -> x.query |> maybeList (List.map .options))
|> List.concat
|> List.filter
(\x ->
if String.endsWith "." (Maybe.withDefault "" query) then
x.text /= query
else
True
)
firstItemText items =
items
|> List.head
|> Maybe.andThen .text
in
if List.length suggestions == 1 && firstItemText suggestions == query then
[]
else
suggestions
_ ->
[]
view :
String
-> String
@ -786,48 +452,10 @@ view :
-> (Msg a -> b)
-> Html b
view path title model viewSuccess outMsg =
let
suggestions =
getSuggestions model.query model.querySuggest
viewSuggestion x =
li
[]
[ a
([ href "#" ]
|> List.append
(x.text
|> Maybe.map (\text -> [ onClick <| outMsg (SuggestionsClickSelect text) ])
|> Maybe.withDefault []
)
|> List.append
(if x.text == model.querySelectedSuggestion then
[ id "dropdown-menu-selected" ]
else
[]
)
)
[ text <| Maybe.withDefault "" x.text ]
]
in
div
[ classList
[ ( "search-page", True )
, ( "with-suggestions", RemoteData.isSuccess model.querySuggest && List.length suggestions > 0 )
, ( "with-suggestions-loading"
, (model.query /= Nothing)
&& (model.query /= Just "")
&& not (RemoteData.isSuccess model.querySuggest || RemoteData.isNotAsked model.querySuggest)
)
]
[ class "search-page"
]
[ h1 [ class "page-header" ] [ text title ]
, div
[ class "search-backdrop"
, onClick <| outMsg SuggestionsClose
]
[]
, div
[ class "search-input"
]
@ -863,60 +491,19 @@ view path title model viewSuccess outMsg =
[ class "input-append"
]
[ input
([ type_ "text"
, id "search-query-input"
, autocomplete False
, autofocus True
, placeholder <| "Search for " ++ path
, onInput (\x -> outMsg (QueryInput x))
, value <| Maybe.withDefault "" model.query
]
|> List.append
(if RemoteData.isSuccess model.querySuggest && List.length suggestions > 0 then
[ Keyboard.Events.custom Keyboard.Events.Keydown
{ preventDefault = True
, stopPropagation = True
}
([ ( Keyboard.ArrowDown, SuggestionsMoveDown )
, ( Keyboard.ArrowUp, SuggestionsMoveUp )
, ( Keyboard.Tab, SuggestionsMoveDown )
, ( Keyboard.Enter, SuggestionsSelect )
, ( Keyboard.Escape, SuggestionsClose )
]
|> List.map (\( k, m ) -> ( k, outMsg m ))
)
]
else if RemoteData.isNotAsked model.querySuggest then
[ Keyboard.Events.custom Keyboard.Events.Keydown
{ preventDefault = True
, stopPropagation = True
}
([ ( Keyboard.ArrowDown, QueryInputSuggestionsSubmit )
, ( Keyboard.ArrowUp, QueryInputSuggestionsSubmit )
]
|> List.map (\( k, m ) -> ( k, outMsg m ))
)
]
else
[]
)
)
[ type_ "text"
, id "search-query-input"
, autofocus True
, placeholder <| "Search for " ++ path
, onInput (\x -> outMsg (QueryInput x))
, value <| Maybe.withDefault "" model.query
]
[]
, div [ class "loader" ] []
, div [ class "btn-group" ]
[ button [ class "btn" ] [ text "Search" ]
]
]
, ul
[ id "dropdown-menu", class "dropdown-menu" ]
(if RemoteData.isSuccess model.querySuggest && List.length suggestions > 0 then
List.map viewSuggestion suggestions
else
[]
)
]
]
, case model.result of
@ -1299,24 +886,8 @@ decodeResult :
Json.Decode.Decoder a
-> Json.Decode.Decoder (SearchResult a)
decodeResult decodeResultItemSource =
Json.Decode.map2 SearchResult
Json.Decode.map SearchResult
(Json.Decode.field "hits" (decodeResultHits decodeResultItemSource))
(Json.Decode.maybe (Json.Decode.field "suggest" (decodeSuggest decodeResultItemSource)))
decodeSuggest : Json.Decode.Decoder a -> Json.Decode.Decoder (SearchSuggest a)
decodeSuggest decodeResultItemSource =
Json.Decode.map SearchSuggest
(Json.Decode.maybe (Json.Decode.field "query" (Json.Decode.list (decodeSuggestQuery decodeResultItemSource))))
decodeSuggestQuery : Json.Decode.Decoder a -> Json.Decode.Decoder (SearchSuggestQuery a)
decodeSuggestQuery decodeResultItemSource =
Json.Decode.map4 SearchSuggestQuery
(Json.Decode.field "text" Json.Decode.string)
(Json.Decode.field "offset" Json.Decode.int)
(Json.Decode.field "length" Json.Decode.int)
(Json.Decode.field "options" (Json.Decode.list (decodeResultItem decodeResultItemSource)))
decodeResultHits : Json.Decode.Decoder a -> Json.Decode.Decoder (ResultHits a)

View file

@ -29,56 +29,8 @@ header .navbar.navbar-static-top {
}
}
.search-page.with-suggestions-loading {
.input-append div.loader {
display: block;
}
}
.search-page.with-suggestions {
ul.dropdown-menu {
display: block;
}
.input-append input {
border-radius: 4px 0 0 0;
}
.search-backdrop {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 999;
}
}
.search-input {
position: relative;
ul.dropdown-menu {
font-size: 18px;
width: 25.6em;
height: auto;
max-height: 200px;
border-radius: 0;
margin-top: -10px;
border-top: 0;
overflow-y: scroll;
li > a {
font-size: 14px;
}
li > a#dropdown-menu-selected {
color: #fff;
text-decoration: none;
background-color: #0081c2;
background-image: -moz-linear-gradient(top,#08c,#0077b3);
background-image: -webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));
background-image: -webkit-linear-gradient(top,#08c,#0077b3);
background-image: -o-linear-gradient(top,#08c,#0077b3);
background-image: linear-gradient(to bottom,#08c,#0077b3);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0);
}
}
.input-append {
position: relative;
input {
font-size: 18px;
height: 40px;

Binary file not shown.