diff --git a/.changeset/config.json b/.changeset/config.json index c88c9515..095a73a3 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -13,6 +13,8 @@ "@meilisearch/angular-playground", "@meilisearch/vue3-ts-playground", "@meilisearch/react-playground", - "@meilisearch/local-react-playground" + "@meilisearch/local-react-playground", + "@meilisearch/node-playground", + "@meilisearch/autocomplete-playground" ] } diff --git a/.changeset/curly-elephants-juggle.md b/.changeset/curly-elephants-juggle.md new file mode 100644 index 00000000..ee93f5c1 --- /dev/null +++ b/.changeset/curly-elephants-juggle.md @@ -0,0 +1,5 @@ +--- +"@meilisearch/instant-meilisearch": patch +--- + +Add compatibility with the `searchable` parameter of the [`RefinementList`](https://www.algolia.com/doc/api-reference/widgets/refinement-list/js/) widget diff --git a/packages/instant-meilisearch/README.md b/packages/instant-meilisearch/README.md index 4ed17554..9e51c502 100644 --- a/packages/instant-meilisearch/README.md +++ b/packages/instant-meilisearch/README.md @@ -707,11 +707,11 @@ The `refinementList` widget is one of the most common widgets you can find in a - ✅ limit: How many facet values to retrieve. - ✅ showMore: Whether to display a button that expands the number of items. - ✅ showMoreLimit: The maximum number of displayed items. Does not work when showMoreLimit > limit. -- ❌ searchable: Whether to add a search input to let the user search for more facet values. Not supported by Meilisearch. If you'd like to see it implemented [please vote](https://roadmap.meilisearch.com/c/64-search-for-facet-values?utm_medium=social&utm_source=portal_share). -- ❌ searchablePlaceholder: The value of the search input’s placeholder. Not supported, see `searchable`. -- ❌ searchableIsAlwaysActive: When false, disables the facet search input. Not supported, see `searchable`. -- ❌ searchableEscapeFacetValues: When true, escapes the facet values. Not supported, see `searchable`. -- ❌ sortBy: Not supported natively but can be implemented manually using `transformItems` options. +- ✅ searchable: Whether to add a search input to let the user search for more facet values. Not supported by Meilisearch. If you'd like to see it implemented [please vote](https://roadmap.meilisearch.com/c/64-search-for-facet-values?utm_medium=social&utm_source=portal_share). +- ✅ searchablePlaceholder: The value of the search input’s placeholder. Not supported, see `searchable`. +- ✅ searchableIsAlwaysActive: When false, disables the facet search input. Not supported, see `searchable`. +- ❌ searchableEscapeFacetValues: When true, escapes the facet values. +- ❌ sortBy: Not supported but can be implemented manually using `transformItems` options. - ✅ transformItems: A function to transform the items passed to the templates. - ✅ templates: The templates to use for the widget. - ✅ cssClasses: The CSS classes to override. diff --git a/packages/instant-meilisearch/package.json b/packages/instant-meilisearch/package.json index 51955c4a..88c54722 100644 --- a/packages/instant-meilisearch/package.json +++ b/packages/instant-meilisearch/package.json @@ -50,7 +50,7 @@ "templates" ], "dependencies": { - "meilisearch": "^0.33.0" + "meilisearch": "0.35.0-v1.3.0-pre-release.1" }, "devDependencies": { "@babel/cli": "^7.21.0", diff --git a/packages/instant-meilisearch/src/client/instant-meilisearch-client.ts b/packages/instant-meilisearch/src/client/instant-meilisearch-client.ts index c877242e..5b54a5c8 100644 --- a/packages/instant-meilisearch/src/client/instant-meilisearch-client.ts +++ b/packages/instant-meilisearch/src/client/instant-meilisearch-client.ts @@ -8,6 +8,8 @@ import { FacetDistribution, PaginationState, MeilisearchConfig, + AlgoliaSearchForFacetValuesRequests, + AlgoliaSearchForFacetValuesResponse, } from '../types' import { getApiKey, @@ -19,7 +21,7 @@ import { adaptSearchParams, SearchResolver, } from '../adapter' -import { createSearchContext } from '../contexts' +import { createSearchContext, createFacetSearchContext } from '../contexts' import { SearchCache, initFacetDistribution, @@ -132,13 +134,48 @@ export function instantMeiliSearch( throw new Error(e) } }, - searchForFacetValues: async function (_: any) { - return await new Promise((resolve, reject) => { - reject( - new Error('SearchForFacetValues is not compatible with Meilisearch') + searchForFacetValues: async function ( + requests: AlgoliaSearchForFacetValuesRequests + ): Promise { + const results = [] + for (const request of requests) { + const searchContext: SearchContext = createFacetSearchContext( + request, + instantMeiliSearchOptions ) - resolve([]) // added here to avoid compilation error - }) + + const meilisearchSearchQuery = adaptSearchParams(searchContext) + + const index = request.indexName + + const meilisearchRequest: any = { + ...meilisearchSearchQuery, + facetQuery: request.params.facetQuery, + facetName: request.params.facetName, + } + + delete meilisearchRequest.indexUid + + const meilisearchResponse = await meilisearchClient + .index(index) + .searchForFacetValues(meilisearchRequest) + + const facetHits = meilisearchResponse.facetHits.map((facetHit) => ({ + ...facetHit, + // not currently supported + highlighted: facetHit.value, + })) + + const result = { + facetHits, + exhaustiveFacetsCount: false, + processingTimeMS: meilisearchResponse.processingTimeMs, + } + + results.push(result) + } + + return results }, } } diff --git a/packages/instant-meilisearch/src/contexts/index.ts b/packages/instant-meilisearch/src/contexts/index.ts index 02006fa7..49a74346 100644 --- a/packages/instant-meilisearch/src/contexts/index.ts +++ b/packages/instant-meilisearch/src/contexts/index.ts @@ -1 +1 @@ -export { createSearchContext } from './search-context' +export { createSearchContext, createFacetSearchContext } from './search-context' diff --git a/packages/instant-meilisearch/src/contexts/search-context.ts b/packages/instant-meilisearch/src/contexts/search-context.ts index 2e426754..44962b27 100644 --- a/packages/instant-meilisearch/src/contexts/search-context.ts +++ b/packages/instant-meilisearch/src/contexts/search-context.ts @@ -2,6 +2,7 @@ import { InstantMeiliSearchOptions, AlgoliaMultipleQueriesQuery, SearchContext, + AlgoliaSearchForFacetValuesRequest, } from '../types' import { splitSortString } from './sort-context' import { createPaginationState } from './pagination-context' @@ -54,3 +55,36 @@ export function createSearchContext( } return searchContext } + +/** + * @param {AlgoliaMultipleQueriesQuery} searchRequest + * @param {Context} options + * @returns {SearchContext} + */ +export function createFacetSearchContext( + searchRequest: AlgoliaSearchForFacetValuesRequest, + options: InstantMeiliSearchOptions +): SearchContext { + // Split index name and possible sorting rules + const [indexUid, ...sortByArray] = searchRequest.indexName.split(':') + const { params: instantSearchParams } = searchRequest + + const paginationState = createPaginationState( + options.finitePagination, + instantSearchParams?.hitsPerPage, + instantSearchParams?.page + ) + + const sortState = splitSortString(sortByArray.join(':')) + + const searchContext: SearchContext = { + ...options, + ...instantSearchParams, + sort: sortState, + indexUid, + pagination: paginationState, + placeholderSearch: options.placeholderSearch !== false, // true by default + keepZeroFacets: !!options.keepZeroFacets, // false by default + } + return searchContext +} diff --git a/packages/instant-meilisearch/src/types/types.ts b/packages/instant-meilisearch/src/types/types.ts index 94c94719..a8e44d73 100644 --- a/packages/instant-meilisearch/src/types/types.ts +++ b/packages/instant-meilisearch/src/types/types.ts @@ -1,5 +1,8 @@ import type { SearchClient } from 'instantsearch.js' -import type { MultipleQueriesQuery as AlgoliaMultipleQueriesQuery } from '@algolia/client-search' +import type { + MultipleQueriesQuery as AlgoliaMultipleQueriesQuery, + multipleSearchForFacetValues, +} from '@algolia/client-search' import type { MultiSearchQuery as MeiliSearchMultiSearchParams, MultiSearchResult, @@ -12,6 +15,13 @@ export type { SearchForFacetValuesResponse as AlgoliaSearchForFacetValuesResponse, } from '@algolia/client-search' +export type AlgoliaSearchForFacetValuesRequests = Parameters< + ReturnType +>[0] + +export type AlgoliaSearchForFacetValuesRequest = + AlgoliaSearchForFacetValuesRequests[0] + export type { Filter, FacetDistribution, diff --git a/playgrounds/local-react/cypress/integration/search-ui.spec.js b/playgrounds/local-react/cypress/integration/search-ui.spec.js index b1e6118f..65fd84c2 100644 --- a/playgrounds/local-react/cypress/integration/search-ui.spec.js +++ b/playgrounds/local-react/cypress/integration/search-ui.spec.js @@ -38,7 +38,9 @@ describe(`${playground} playground test`, () => { it('Sort by recommendationCound ascending', () => { const select = `.ais-SortBy-select` - cy.get(select).select('games:recommendationCount:asc') + cy.get(select) + .select('games:recommendationCount:asc') + .should('have.value', 'games:recommendationCount:asc') cy.wait(1000) cy.get(HIT_ITEM_CLASS).eq(0).contains('Deathmatch Classic') }) @@ -61,7 +63,10 @@ describe(`${playground} playground test`, () => { }) it('Search', () => { - cy.get('.ais-SearchBox-input').type('Half-Life') + cy.get('.right-panel') + .find('.ais-SearchBox-input') + .type('Half-Life') + .should('have.value', 'Half-Life') cy.wait(1000) cy.get(HIT_ITEM_CLASS).eq(0).contains('Half-Life') }) diff --git a/playgrounds/local-react/src/components/SingleIndex.jsx b/playgrounds/local-react/src/components/SingleIndex.jsx index 4e70d38d..69ca9a49 100644 --- a/playgrounds/local-react/src/components/SingleIndex.jsx +++ b/playgrounds/local-react/src/components/SingleIndex.jsx @@ -50,9 +50,9 @@ const SingleIndex = () => ( ]} />

Genres

- +

Players

- +

Platforms

Misc

diff --git a/yarn.lock b/yarn.lock index 722cf0ee..b66582c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10269,10 +10269,10 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -meilisearch@^0.33.0: - version "0.33.0" - resolved "https://registry.yarnpkg.com/meilisearch/-/meilisearch-0.33.0.tgz#25982b193cdd22e9ec534a022dbde89c42951dc4" - integrity sha512-bYPb9WyITnJfzf92e7QFK8Rc50DmshFWxypXCs3ILlpNh8pT15A7KSu9Xgnnk/K3G/4vb3wkxxtFS4sxNkWB8w== +meilisearch@0.35.0-v1.3.0-pre-release.1: + version "0.35.0-v1.3.0-pre-release.1" + resolved "https://registry.yarnpkg.com/meilisearch/-/meilisearch-0.35.0-v1.3.0-pre-release.1.tgz#24fa735a25539a9de11b0e84a5e4455de003316b" + integrity sha512-rzWDGkuBByGnFjBsnzVNaHS+sXtshwumAYHq8zbkVmwpEwZLuM0bcguKJWcuXvTIkfRqS3u/BhQBtcJ/HWg7dw== dependencies: cross-fetch "^3.1.6"