Skip to content
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

docs: improve search to show results for all filters #9208

Merged
merged 2 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion www/apps/book/providers/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
mainIndexName:
process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME || "temp",
indices: [
process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || "temp",
process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME || "temp",
process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || "temp",
],
}}
searchProps={{
Expand Down
2 changes: 1 addition & 1 deletion www/apps/resources/providers/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
mainIndexName:
process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME || "temp",
indices: [
process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || "temp",
process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME || "temp",
process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || "temp",
],
}}
searchProps={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const SearchHits = ({
setNoResults,
checkInternalPattern,
}: SearchHitsProps) => {
const { hits } = useHits<HitType>()
const { items: hits } = useHits<HitType>()
const { status } = useInstantSearch()
const { setIsOpen } = useSearch()

Expand Down
103 changes: 99 additions & 4 deletions www/packages/docs-ui/src/providers/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { checkArraySameElms } from "../../utils"
import {
liteClient as algoliasearch,
LiteClient as SearchClient,
type SearchResponses,
type SearchHits,
SearchResponse,
} from "algoliasearch/lite"
import clsx from "clsx"
import { CSSTransition, SwitchTransition } from "react-transition-group"
Expand Down Expand Up @@ -78,11 +81,37 @@ export const SearchProvider = ({
async search(searchParams) {
const requests =
"requests" in searchParams ? searchParams.requests : searchParams
const noQueries = requests.every(
// always send this request, which is the main request with no filters
const mainRequest = requests[0]

// retrieve only requests that have filters
// this is to ensure that we show no result if no filter is selected
const requestsWithFilters = requests.filter((item) => {
if (
!item.params ||
typeof item.params !== "object" ||
!("tagFilters" in item.params)
) {
return false
}

const tagFilters = item.params.tagFilters as string[]

// if no tag filters are specified, there's still one item,
// which is an empty array
return tagFilters.length >= 1 && tagFilters[0].length > 0
})

// check whether a query is entered in the search box
const noQueries = requestsWithFilters.every(
(item) =>
("facetQuery" in item && !item.facetQuery) ||
("query" in item && !item.query)
!item.facetQuery &&
(!item.params ||
typeof item.params !== "object" ||
!("query" in item.params) ||
!item.params.query)
)

if (noQueries) {
return Promise.resolve({
results: requests.map(() => ({
Expand All @@ -99,7 +128,73 @@ export const SearchProvider = ({
})
}

return algoliaClient.search(searchParams)
// split requests per tags
const newRequests: typeof requestsWithFilters = [mainRequest]
for (const request of requestsWithFilters) {
const params = request.params as Record<string, unknown>
const tagFilters = (params.tagFilters as string[][])[0]

// if only one tag is selected, keep the request as-is
if (tagFilters.length === 1) {
newRequests.push(request)

continue
}

// if multiple tags are selected, split the tags
// to retrieve a small subset of results per each tag.
newRequests.push(
...tagFilters.map((tag) => ({
...request,
params: {
...params,
tagFilters: [tag],
},
hitsPerPage: 4,
}))
)
}

return algoliaClient
.search<SearchHits>(newRequests)
.then((response) => {
// combine results of the same index and return the results
const resultsByIndex: {
[indexName: string]: SearchResponse<SearchHits>
} = {}
// extract the response of the main request
const mainResult = response.results[0]

response.results.forEach((result, indexNum) => {
if (indexNum === 0) {
// ignore the main request's result
return
}
const resultIndex = "index" in result ? result.index : undefined
const resultHits = "hits" in result ? result.hits : []

if (!resultIndex) {
return
}

resultsByIndex[resultIndex] = {
...result,
...(resultsByIndex[resultIndex] || {}),
hits: [
...(resultsByIndex[resultIndex]?.hits || []),
...resultHits,
],
nbHits:
(resultsByIndex[resultIndex]?.nbHits || 0) +
resultHits.length,
}
})

return {
// append the results with the main request's results
results: [mainResult, ...Object.values(resultsByIndex)],
} as SearchResponses<any>
})
},
}
}, [algolia.appId, algolia.apiKey])
Expand Down
Loading