Skip to content
This repository was archived by the owner on Dec 30, 2022. It is now read-only.

Commit 731d9ba

Browse files
authored
feat(facets): add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu (#3067)
* feat(facetOrdering): add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu If `facetOrdering` is enabled (the default behaviour), before the default sortBy is used, the result from renderingContent.facetOrdering.values is first checked. If that's present, it will be used to sort the items. You can still change that ordering afterwards with the existing transformItems, so if you are sorting in transformItems, you actually override the sorting done by facet ordering, and won't see the effect. To use facetOrdering, you thus need to remove any sorting done in transformItems. If there is a facetOrdering present in the index, but you don't want to use it for a certain widget, you need to explicitly pass `facetOrdering: false` to the widget or connector References: - [RFC 45](https://github.com/algolia/instantsearch-rfcs/blob/master/accepted/flexible-facet-values.md) - algolia/instantsearch#4784 - algolia/algoliasearch-helper-js#822 * clarify
1 parent a3b3f28 commit 731d9ba

File tree

7 files changed

+400
-10
lines changed

7 files changed

+400
-10
lines changed

packages/react-instantsearch-core/src/connectors/__tests__/connectHierarchicalMenu.js

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SearchParameters } from 'algoliasearch-helper';
1+
import { SearchResults, SearchParameters } from 'algoliasearch-helper';
22
import connect from '../connectHierarchicalMenu';
33

44
jest.mock('../../core/createConnector', () => x => x);
@@ -174,6 +174,159 @@ describe('connectHierarchicalMenu', () => {
174174
expect(props.items).toEqual(['items']);
175175
});
176176

177+
it('facetValues results uses facetOrdering by default', () => {
178+
const props = {
179+
...connect.defaultProps,
180+
attributes: ['lvl0', 'lvl1'],
181+
contextValue,
182+
};
183+
const searchState = { hierarchicalMenu: { lvl0: 'wat' } };
184+
const state = connect.getSearchParameters(
185+
new SearchParameters(),
186+
props,
187+
searchState
188+
);
189+
const results = new SearchResults(state, [
190+
{
191+
hits: [],
192+
renderingContent: {
193+
facetOrdering: {
194+
values: {
195+
lvl0: {
196+
order: ['wat'],
197+
},
198+
lvl1: {
199+
order: ['wat > wut'],
200+
},
201+
},
202+
},
203+
},
204+
facets: {
205+
lvl0: {
206+
wat: 20,
207+
oy: 10,
208+
},
209+
lvl1: {
210+
'wat > wot': 15,
211+
'wat > wut': 5,
212+
},
213+
},
214+
},
215+
]);
216+
217+
const providedProps = connect.getProvidedProps(props, searchState, {
218+
results,
219+
});
220+
expect(providedProps.items).toEqual([
221+
{
222+
label: 'wat',
223+
value: undefined,
224+
count: 20,
225+
isRefined: true,
226+
items: [
227+
{
228+
label: 'wut',
229+
value: 'wat > wut',
230+
count: 5,
231+
isRefined: false,
232+
items: null,
233+
},
234+
{
235+
label: 'wot',
236+
value: 'wat > wot',
237+
count: 15,
238+
isRefined: false,
239+
items: null,
240+
},
241+
],
242+
},
243+
{
244+
label: 'oy',
245+
value: 'oy',
246+
count: 10,
247+
isRefined: false,
248+
items: null,
249+
},
250+
]);
251+
});
252+
253+
it('facetValues results does not use facetOrdering if disabled', () => {
254+
const props = {
255+
attributes: ['lvl0', 'lvl1'],
256+
facetOrdering: false,
257+
contextValue,
258+
};
259+
const searchState = { hierarchicalMenu: { lvl0: 'wat' } };
260+
const state = connect.getSearchParameters(
261+
new SearchParameters(),
262+
props,
263+
searchState
264+
);
265+
const results = new SearchResults(state, [
266+
{
267+
hits: [],
268+
renderingContent: {
269+
facetOrdering: {
270+
values: {
271+
lvl0: {
272+
order: ['wat'],
273+
},
274+
lvl1: {
275+
order: ['wat > wut'],
276+
},
277+
},
278+
},
279+
},
280+
facets: {
281+
lvl0: {
282+
wat: 20,
283+
oy: 10,
284+
},
285+
lvl1: {
286+
'wat > wot': 15,
287+
'wat > wut': 5,
288+
},
289+
},
290+
},
291+
]);
292+
293+
const providedProps = connect.getProvidedProps(props, searchState, {
294+
results,
295+
});
296+
expect(providedProps.items).toEqual([
297+
{
298+
label: 'oy',
299+
value: 'oy',
300+
count: 10,
301+
isRefined: false,
302+
items: null,
303+
},
304+
{
305+
label: 'wat',
306+
value: undefined,
307+
count: 20,
308+
isRefined: true,
309+
items: [
310+
// default ordering: alphabetical
311+
{
312+
label: 'wot',
313+
value: 'wat > wot',
314+
count: 15,
315+
isRefined: false,
316+
items: null,
317+
},
318+
{
319+
label: 'wut',
320+
value: 'wat > wut',
321+
count: 5,
322+
isRefined: false,
323+
items: null,
324+
},
325+
],
326+
},
327+
]);
328+
});
329+
177330
it('shows the effect of showMoreLimit when there is no transformItems', () => {
178331
const results = {
179332
getFacetValues: jest.fn(),

packages/react-instantsearch-core/src/connectors/__tests__/connectMenu.js

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SearchParameters } from 'algoliasearch-helper';
1+
import { SearchParameters, SearchResults } from 'algoliasearch-helper';
22
import connect from '../connectMenu';
33

44
jest.mock('../../core/createConnector', () => x => x);
@@ -245,6 +245,116 @@ describe('connectMenu', () => {
245245
]);
246246
});
247247

248+
it('facetValues have facetOrdering by default', () => {
249+
const userProps = {
250+
...connect.defaultProps,
251+
attribute: 'ok',
252+
contextValue,
253+
};
254+
const searchState = {
255+
menu: { ok: 'wat' },
256+
};
257+
const parameters = connect.getSearchParameters(
258+
new SearchParameters(),
259+
userProps,
260+
searchState
261+
);
262+
263+
const searchResults = new SearchResults(parameters, [
264+
{
265+
hits: [],
266+
renderingContent: {
267+
facetOrdering: {
268+
values: {
269+
ok: {
270+
order: ['wat'],
271+
},
272+
},
273+
},
274+
},
275+
facets: {
276+
ok: {
277+
wat: 20,
278+
lol: 2000,
279+
},
280+
},
281+
},
282+
]);
283+
284+
const providedProps = connect.getProvidedProps(userProps, searchState, {
285+
results: searchResults,
286+
});
287+
288+
expect(providedProps.items).toEqual([
289+
{
290+
count: 20,
291+
isRefined: true,
292+
label: 'wat',
293+
value: '',
294+
},
295+
{
296+
count: 2000,
297+
isRefined: false,
298+
label: 'lol',
299+
value: 'lol',
300+
},
301+
]);
302+
expect(providedProps.isFromSearch).toBe(false);
303+
});
304+
305+
it('facetValues results does not use facetOrdering if disabled', () => {
306+
const userProps = { attribute: 'ok', facetOrdering: false, contextValue };
307+
const searchState = {
308+
menu: { ok: 'wat' },
309+
};
310+
const parameters = connect.getSearchParameters(
311+
new SearchParameters(),
312+
userProps,
313+
searchState
314+
);
315+
316+
const searchResults = new SearchResults(parameters, [
317+
{
318+
hits: [],
319+
renderingContent: {
320+
facetOrdering: {
321+
values: {
322+
ok: {
323+
order: ['wat'],
324+
},
325+
},
326+
},
327+
},
328+
facets: {
329+
ok: {
330+
wat: 20,
331+
lol: 2000,
332+
},
333+
},
334+
},
335+
]);
336+
337+
const providedProps = connect.getProvidedProps(userProps, searchState, {
338+
results: searchResults,
339+
});
340+
341+
expect(providedProps.items).toEqual([
342+
{
343+
count: 2000,
344+
isRefined: false,
345+
label: 'lol',
346+
value: 'lol',
347+
},
348+
{
349+
count: 20,
350+
isRefined: true,
351+
label: 'wat',
352+
value: '',
353+
},
354+
]);
355+
expect(providedProps.isFromSearch).toBe(false);
356+
});
357+
248358
it("calling refine updates the widget's search state", () => {
249359
const nextState = connect.refine(
250360
{ attribute: 'ok', contextValue },
@@ -435,13 +545,14 @@ describe('connectMenu', () => {
435545
};
436546

437547
props = connect.getProvidedProps(
438-
{ attribute: 'ok', contextValue },
548+
{ ...connect.defaultProps, attribute: 'ok', contextValue },
439549
{},
440550
{ results }
441551
);
442552

443553
expect(results.getFacetValues).toHaveBeenCalledWith('ok', {
444554
sortBy: ['count:desc', 'name:asc'],
555+
facetOrdering: true,
445556
});
446557

447558
expect(props.items).toEqual([
@@ -479,13 +590,19 @@ describe('connectMenu', () => {
479590
};
480591

481592
props = connect.getProvidedProps(
482-
{ attribute: 'ok', searchable: true, contextValue },
593+
{
594+
...connect.defaultProps,
595+
attribute: 'ok',
596+
searchable: true,
597+
contextValue,
598+
},
483599
{},
484600
{ results }
485601
);
486602

487603
expect(results.getFacetValues).toHaveBeenCalledWith('ok', {
488604
sortBy: undefined,
605+
facetOrdering: true,
489606
});
490607

491608
expect(props.items).toEqual([

0 commit comments

Comments
 (0)