Refine ComboBox.StaticSearch (#3172)

This commit makes static search more strict by rejecting matches with a score less than 0.6. Here's an example of suggestion that was matching with a 0.5 score that should not be suggested. This makes the suggestion list smaller and more reasonable.

Co-authored by: Robert Joonas <robertjoonas16@gmail.com>
This commit is contained in:
Vini Brasil 2023-07-24 10:18:40 +01:00 committed by GitHub
parent a9603a44c9
commit 60e418b357
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 33 deletions

View File

@ -252,16 +252,15 @@ defmodule PlausibleWeb.Live.Components.ComboBox do
socket
end
if input_len > 0 do
suggestions =
input
|> suggest_mod.suggest(options)
|> Enum.take(suggestions_limit(socket.assigns))
suggestions =
if input_len > 0 do
suggest_mod.suggest(input, options)
else
options
end
|> Enum.take(suggestions_limit(socket.assigns))
{:noreply, assign(socket, %{suggestions: suggestions})}
else
{:noreply, socket}
end
{:noreply, assign(socket, %{suggestions: suggestions})}
end
defp do_select(socket, submit_value, display_value) do

View File

@ -11,25 +11,28 @@ defmodule PlausibleWeb.Live.Components.ComboBox.StaticSearch do
@spec suggest(String.t(), [{any(), any()}]) :: [{any(), any()}]
def suggest(input, options) do
input_len = String.length(input)
options
|> Enum.reject(fn {_, value} ->
input_len > String.length(to_string(value))
end)
|> Enum.sort_by(
fn {_, value} ->
if to_string(value) == input do
3
else
value = to_string(value)
input = String.downcase(input)
value = String.downcase(value)
weight = if String.contains?(value, input), do: 1, else: 0
weight + String.jaro_distance(value, input)
end
end,
:desc
)
|> Enum.map(fn {_, value} = option -> {option, weight(value, input)} end)
|> Enum.reject(fn {_option, weight} -> weight < 0.6 end)
|> Enum.sort_by(fn {_option, weight} -> weight end, :desc)
|> Enum.map(fn {option, _weight} -> option end)
end
defp weight(value, input) do
value = to_string(value)
case {value, input} do
{value, input} when value == input ->
3
{value, input} when byte_size(input) > byte_size(value) ->
0
{value, input} ->
input = String.downcase(input)
value = String.downcase(value)
weight = if String.contains?(value, input), do: 1, else: 0
weight + String.jaro_distance(value, input)
end
end
end

View File

@ -24,9 +24,12 @@ defmodule PlausibleWeb.Live.Components.ComboBox.StaticSearchTest do
test "allows fuzzy matching" do
options = fake_options(["/url/0xC0FFEE", "/url/0xDEADBEEF", "/url/other"])
assert [{_, "/url/0xC0FFEE"}] = StaticSearch.suggest("0x FF", options)
end
assert [{_, "/url/0xC0FFEE"}, {_, "/url/0xDEADBEEF"}, {_, "/url/other"}] =
StaticSearch.suggest("0x FF", options)
test "filters out bad matches" do
options = fake_options(["OS", "Version", "Logged In"])
assert [] = StaticSearch.suggest("cow", options)
end
end

View File

@ -191,6 +191,14 @@ defmodule PlausibleWeb.Live.Components.ComboBoxTest do
refute element_exists?(doc, suggestion_li(8))
refute element_exists?(doc, suggestion_li(9))
end
test "clearing search input resets to all options", %{conn: conn} do
{:ok, lv, _html} = live_isolated(conn, SampleView, session: %{})
type_into_combo(lv, "test-component", "Echo me")
doc = type_into_combo(lv, "test-component", "")
for i <- 1..7, do: assert(element_exists?(doc, suggestion_li(i)))
end
end
describe "creatable integration" do

View File

@ -56,9 +56,6 @@ defmodule PlausibleWeb.Live.FunnelSettings.FormTest do
doc = type_into_combo(lv, 2, "another")
refute text_of_element(doc, "ul#dropdown-step-1 li") =~ "Another World"
assert text_of_element(doc, "ul#dropdown-step-2 li") =~ "Hello World"
assert text_of_element(doc, "ul#dropdown-step-2 li") =~ "Plausible"
refute text_of_element(doc, "ul#dropdown-step-2 li") =~ "Another World"
end