Skip to content

Commit

Permalink
feat(facets): apply result from facet ordering (algolia#4784)
Browse files Browse the repository at this point in the history
* feat(facets): apply sort from facetOrdering

* feat(facets): apply result from facet ordering

This adds a new option "facetOrdering" (boolean) to refinementList, menu, hierarchicalMenu which will read facet ordering from the results if available, but fall back to sortBy if no facetOrdering is available.

The option facetOrdering defaults to `true` if no sortBy is given, to make it apply out of the box.

references:
- NLP-110
- [RFC 45](https://github.com/algolia/instantsearch-rfcs/blob/master/accepted/flexible-facet-values.md)

* forward facetOrdering option from widget

* suppress v3 ts errors

* remove option

* test: rename
  • Loading branch information
Haroenv authored Jul 5, 2021
1 parent dc2fd95 commit 9e9d839
Show file tree
Hide file tree
Showing 8 changed files with 475 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,166 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica
canToggleShowMore: false,
});
});

describe('facetOrdering', () => {
const resultsViaFacetOrdering = [
{
count: 47,
data: null,
exhaustive: true,
isRefined: false,
label: 'Outdoor',
value: 'Outdoor',
},
{
count: 880,
data: [
{
count: 173,
data: null,
exhaustive: true,
isRefined: false,
label: 'Frames & pictures',
value: 'Decoration > Frames & pictures',
},
{
count: 193,
data: null,
exhaustive: true,
isRefined: false,
label: 'Candle holders & candles',
value: 'Decoration > Candle holders & candles',
},
],
exhaustive: true,
isRefined: true,
label: 'Decoration',
value: 'Decoration',
},
];
const resultsViaSortBy = [
{
count: 880,
data: [
{
count: 193,
data: null,
exhaustive: true,
isRefined: false,
label: 'Candle holders & candles',
value: 'Decoration > Candle holders & candles',
},
{
count: 173,
data: null,
exhaustive: true,
isRefined: false,
label: 'Frames & pictures',
value: 'Decoration > Frames & pictures',
},
],
exhaustive: true,
isRefined: true,
label: 'Decoration',
value: 'Decoration',
},
{
count: 47,
data: null,
exhaustive: true,
isRefined: false,
label: 'Outdoor',
value: 'Outdoor',
},
];

test.each`
facetOrderingInResult | sortBy | expected
${true} | ${undefined} | ${resultsViaFacetOrdering}
${false} | ${undefined} | ${resultsViaSortBy}
${true} | ${['name:asc']} | ${resultsViaSortBy}
${false} | ${['name:asc']} | ${resultsViaSortBy}
`(
'renderingContent present: $facetOrderingInResult, sortBy: $sortBy',
({ facetOrderingInResult, sortBy, expected }) => {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const createHierarchicalMenu = connectHierarchicalMenu(
renderFn,
unmountFn
);
const hierarchicalMenu = createHierarchicalMenu({
attributes: ['category', 'subCategory'],
sortBy,
});
const helper = algoliasearchHelper(
createSearchClient(),
'indexName',
hierarchicalMenu.getWidgetSearchParameters!(
new SearchParameters(),
{
uiState: {
hierarchicalMenu: {
category: ['Decoration'],
},
},
}
)
);

hierarchicalMenu.init!(createInitOptions({ helper }));

const renderingContent = facetOrderingInResult
? {
facetOrdering: {
values: {
category: {
order: ['Outdoor'],
sortRemainingBy: 'alpha' as const,
},
subCategory: {
order: ['Decoration > Frames & pictures'],
sortRemainingBy: 'count' as const,
},
},
},
}
: undefined;

const results = new SearchResults(helper.state, [
createSingleSearchResponse({
renderingContent,
facets: {
category: {
Decoration: 880,
},
subCategory: {
'Decoration > Candle holders & candles': 193,
'Decoration > Frames & pictures': 173,
},
},
}),
createSingleSearchResponse({
facets: {
category: {
Decoration: 880,
Outdoor: 47,
},
},
}),
]);

const renderState = hierarchicalMenu.getWidgetRenderState(
createRenderOptions({
helper,
results,
})
);

expect(renderState.items).toEqual(expected);
}
);
});
});

describe('getWidgetUiState', () => {
Expand Down
12 changes: 6 additions & 6 deletions src/connectors/hierarchical-menu/connectHierarchicalMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const withUsage = createDocumentationMessageGenerator({
connector: true,
});

const DEFAULT_SORT = ['name:asc'];

export type HierarchicalMenuItem = {
/**
* Value of the menu item.
Expand Down Expand Up @@ -79,6 +81,8 @@ export type HierarchicalMenuConnectorParams = {
/**
* How to sort refinements. Possible values: `count|isRefined|name:asc|name:desc`.
* You can also use a sort function that behaves like the standard Javascript [compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Syntax).
*
* If a facetOrdering is set in the index settings, it is used when sortBy isn't passed
*/
sortBy?: SortBy<HierarchicalMenuItem>;
/**
Expand Down Expand Up @@ -174,7 +178,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera
limit = 10,
showMore = false,
showMoreLimit = 20,
sortBy = ['name:asc'],
sortBy = DEFAULT_SORT,
transformItems = (items => items) as TransformItems<HierarchicalMenuItem>,
} = widgetParams || {};

Expand Down Expand Up @@ -273,11 +277,6 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera
);
},

/**
* @param {Object} param0 cleanup arguments
* @param {any} param0.state current search parameters
* @returns {any} next search parameters
*/
dispose({ state }) {
unmountFn();

Expand Down Expand Up @@ -336,6 +335,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera
if (results) {
const facetValues = results.getFacetValues(hierarchicalFacetName, {
sortBy,
facetOrdering: sortBy === DEFAULT_SORT,
});
const facetItems =
facetValues && !Array.isArray(facetValues) && facetValues.data
Expand Down
Loading

0 comments on commit 9e9d839

Please sign in to comment.