-
Notifications
You must be signed in to change notification settings - Fork 49
[CT-3469] - Autocomplete for home search bar #119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e70f64d
to
f392311
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments for optimizations you can do! Functionality seems to work well when I try 👍
It's already a big improvement! 🔥
There is just one thing I noticed is that if I type 2 or 3 characters for example, it can show me 1 package suggestion, but if I add a new character, it starts to show me 5 suggestions. Shouldn't it already show 5 before?
Example: plot package, if I write pl
or plo
, I only get this one package
pages/index.tsx
Outdated
async function autoComplete(query) { | ||
try { | ||
// fetch the data | ||
const resPackages = await fetch( | ||
`${API_URL}/search_packages?q=${query}&page=1&latest=1`, | ||
{ | ||
headers: { | ||
Accept: 'application/json', | ||
}, | ||
}, | ||
); | ||
|
||
const { packages } = await resPackages.json(); | ||
const relevantPackages = packages.filter((p)=>(p.score>2.5)); | ||
if (relevantPackages.length<5) { | ||
setPackageSuggestions(packages.slice(0, relevantPackages.length)); | ||
} | ||
setPackageSuggestions(relevantPackages.slice(0,5)); | ||
|
||
const resFunctions = await fetch( | ||
`${API_URL}/search_functions?q=${query}&page=1&latest=1`, | ||
{ | ||
headers: { | ||
Accept: 'application/json', | ||
}, | ||
}, | ||
); | ||
const { functions } = await resFunctions.json(); | ||
const relevantFunctions = functions.filter((f)=>(f.score>10)); | ||
if (relevantFunctions.length<5) { | ||
setFunctionSuggestions(functions.slice(0, relevantFunctions.length)); | ||
} | ||
setFunctionSuggestions(functions.slice(0,5)); | ||
|
||
} catch (err) { | ||
console.error(err); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this live in Autocomplete.tsx
?
So that the component handles all the logic itself
pages/index.tsx
Outdated
const resFunctions = await fetch( | ||
`${API_URL}/search_functions?q=${query}&page=1&latest=1`, | ||
{ | ||
headers: { | ||
Accept: 'application/json', | ||
}, | ||
}, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you do a Promises.all so that both queries are sent at the same time and you don't have to wait for one to be finished?
You can do something like
const resFunctions = await fetch( | |
`${API_URL}/search_functions?q=${query}&page=1&latest=1`, | |
{ | |
headers: { | |
Accept: 'application/json', | |
}, | |
}, | |
); | |
const [resPackages, resFunctions] = await Promises.all([ | |
fetch(...), | |
fetch(...) | |
]); |
You can read about the difference between using multilple await and Promise.all here: https://stackoverflow.com/questions/45285129/any-difference-between-await-promise-all-and-multiple-await
pages/index.tsx
Outdated
const { functions } = await resFunctions.json(); | ||
const relevantFunctions = functions.filter((f)=>(f.score>10)); | ||
if (relevantFunctions.length<5) { | ||
setFunctionSuggestions(functions.slice(0, relevantFunctions.length)); | ||
} | ||
setFunctionSuggestions(functions.slice(0,5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw I think it's more clear to call it topics
and not functions
since that's what we already use it everywhere in the codebase (UI, API, db)
pages/index.tsx
Outdated
if (relevantFunctions.length<5) { | ||
setFunctionSuggestions(functions.slice(0, relevantFunctions.length)); | ||
} | ||
setFunctionSuggestions(functions.slice(0,5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (relevantFunctions.length<5) { | |
setFunctionSuggestions(functions.slice(0, relevantFunctions.length)); | |
} | |
setFunctionSuggestions(functions.slice(0,5)); | |
setTopicSuggestions(relevantTopics.slice(0, Math.min(relevantPackages.length, 5)); |
pages/index.tsx
Outdated
); | ||
|
||
const { packages } = await resPackages.json(); | ||
const relevantPackages = packages.filter((p)=>(p.score>2.5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is typescript, so you can use optional chaining in places where you are not sure if the variable you are accessing is defined or not.
const relevantPackages = packages.filter((p)=>(p.score>2.5)); | |
const relevantPackages = packages?.filter((p)=>(p?.score>2.5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments for optimizations you can do! Functionality seems to work well when I try 👍 It's already a big improvement! 🔥
There is just one thing I noticed is that if I type 2 or 3 characters for example, it can show me 1 package suggestion, but if I add a new character, it starts to show me 5 suggestions. Shouldn't it already show 5 before?
Example: plot package, if I write
pl
orplo
, I only get this one package
I think this is because I set the limits on the elasticsearch for packages the score defaults to 1.82... if the results are a low match. In order for the score to go above this number, the query has to be quite similar. (see picture below).
I can either:
-
Set the filter for the scores so that irrelevant results don't come up. This will mean that there are sometimes no suggestions
-
Don't filter the results so that there are always suggestions but they might be irrelevant
components/Autocomplete.tsx
Outdated
</div> | ||
<div> | ||
{ | ||
functionSuggestions.length>0 | ||
&& | ||
searchInput | ||
&& | ||
<ul> | ||
<li className="my-2 ml-2 pl-4 text-dc-grey200 flex justify-between"> | ||
<Heading as="h3" size={300}>FUNCTIONS</Heading> | ||
</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some space between the the sections?
It will look better 👍
components/Autocomplete.tsx
Outdated
function autoCompleteSearch(query) { | ||
router.push(`/search?q=${encodeURIComponent(searchInput)}`); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can rename it so it's more clear, it can even be called onClick
tbh
components/Autocomplete.tsx
Outdated
packageSuggestions: Array<any>, | ||
functionSuggestions: Array<any> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion you shouldn't need these props, the component should handle them itself.
There are actually two approaches:
- Move all the logic to Autocomplete.tsx so that everything is handled in one place. Everyone who imports Autocomplete will get a search bar that just works.
- Make Autocomplete a wrapper component that handles all the logic. Then inside it, you have a child component that is basically how you wrote the current Autocomplete component: it takes props and just renders them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I decided to move all of the logic into Autocomplete
311e7ec
to
beef2f3
Compare
pages/index.tsx
Outdated
useEffect(() => { | ||
}, [searchInput]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this
pages/index.tsx
Outdated
@@ -1,13 +1,15 @@ | |||
import { GetServerSideProps } from 'next'; | |||
import { useRouter } from 'next/router'; | |||
import { useState } from 'react'; | |||
import { useEffect, useState } from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the useEffect in that case
components/Autocomplete.tsx
Outdated
key={p.fields.package_name} | ||
onClick={()=>onClick(p.fields.package_name)} | ||
className="flex items-center px-4 py-2 cursor-pointer hover:bg-dc-beige200 hover:opacity-0.5" | ||
> | ||
<Paragraph className="pl-2 text-lg">{p.fields.package_name}</Paragraph> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add optional chaining here just in case
components/Autocomplete.tsx
Outdated
key={t.fields.package_name+t.fields.name} | ||
onClick={()=>onClick(t.fields.name)} | ||
className="flex items-center px-4 py-2 cursor-pointer hover:bg-dc-beige200 hover:opacity-0.5" | ||
> | ||
<div> | ||
<Paragraph className="px-2 text-lg">{`${t.fields.name}`}</Paragraph> | ||
</div> | ||
<div> | ||
<Paragraph className="text-lg text-dc-red">{`(${t.fields.package_name})`}</Paragraph> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here too, optional chaining
TICKET
Added autocomplete search to the home page using elastic search and filtered the results based on relevance score. On click, the links search for the content.
Before:


After: