From cb4c87f1d55241b163dce16f1e8c075641ca35f5 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Mon, 14 Jun 2021 18:10:29 +0200 Subject: [PATCH 1/6] feat(facets): apply sort from facetOrdering --- package.json | 2 +- .../__tests__/connectHierarchicalMenu-test.ts | 213 ++++++++++++++++++ .../connectHierarchicalMenu.ts | 10 +- .../menu/__tests__/connectMenu-test.ts | 198 +++++++++++++++- src/connectors/menu/connectMenu.ts | 5 +- .../__tests__/connectRefinementList-test.ts | 147 ++++++++++++ .../refinement-list/connectRefinementList.ts | 5 +- yarn.lock | 8 +- 8 files changed, 574 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index f053163364..ea5d1e8b7c 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "dependencies": { "@types/googlemaps": "^3.39.6", "@types/hogan.js": "^3.0.0", - "algoliasearch-helper": "^3.4.5", + "algoliasearch-helper": "^3.5.3", "classnames": "^2.2.5", "events": "^1.1.0", "hogan.js": "^3.0.2", diff --git a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts index c24981ace5..b3d7bb6b5f 100644 --- a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts +++ b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts @@ -691,6 +691,219 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica canToggleShowMore: false, }); }); + + test('uses facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createHierarchicalMenu = connectHierarchicalMenu( + renderFn, + unmountFn + ); + const hierarchicalMenu = createHierarchicalMenu({ + attributes: ['category', 'subCategory'], + }); + const helper = algoliasearchHelper( + createSearchClient(), + 'indexName', + hierarchicalMenu.getWidgetSearchParameters!(new SearchParameters(), { + uiState: { + hierarchicalMenu: { + category: ['Decoration'], + }, + }, + }) + ); + + hierarchicalMenu.init!(createInitOptions({ helper })); + + const results = new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + category: { + order: ['Outdoor'], + sortRemainingBy: 'alpha', + }, + subCategory: { + order: ['Decoration > Frames & pictures'], + sortRemainingBy: 'count', + }, + }, + }, + }, + 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).toMatchInlineSnapshot(` + Array [ + Object { + "count": 47, + "data": null, + "exhaustive": true, + "isRefined": false, + "label": "Outdoor", + "value": "Outdoor", + }, + Object { + "count": 880, + "data": Array [ + Object { + "count": 173, + "data": null, + "exhaustive": true, + "isRefined": false, + "label": "Frames & pictures", + "value": "Decoration > Frames & pictures", + }, + Object { + "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", + }, + ] + `); + }); + + test('sortBy overrides facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createHierarchicalMenu = connectHierarchicalMenu( + renderFn, + unmountFn + ); + const hierarchicalMenu = createHierarchicalMenu({ + attributes: ['category', 'subCategory'], + sortBy: ['name:asc'], + }); + const helper = algoliasearchHelper( + createSearchClient(), + 'indexName', + hierarchicalMenu.getWidgetSearchParameters!(new SearchParameters(), { + uiState: { + hierarchicalMenu: { + category: ['Decoration'], + }, + }, + }) + ); + + hierarchicalMenu.init!(createInitOptions({ helper })); + + const results = new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + category: { + order: ['Outdoor'], + sortRemainingBy: 'alpha', + }, + subCategory: { + order: ['Decoration > Frames & pictures'], + sortRemainingBy: 'count', + }, + }, + }, + }, + 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).toMatchInlineSnapshot(` + Array [ + Object { + "count": 880, + "data": Array [ + Object { + "count": 193, + "data": null, + "exhaustive": true, + "isRefined": false, + "label": "Candle holders & candles", + "value": "Decoration > Candle holders & candles", + }, + Object { + "count": 173, + "data": null, + "exhaustive": true, + "isRefined": false, + "label": "Frames & pictures", + "value": "Decoration > Frames & pictures", + }, + ], + "exhaustive": true, + "isRefined": true, + "label": "Decoration", + "value": "Decoration", + }, + Object { + "count": 47, + "data": null, + "exhaustive": true, + "isRefined": false, + "label": "Outdoor", + "value": "Outdoor", + }, + ] + `); + }); }); describe('getWidgetUiState', () => { diff --git a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts index d71d7ebf1c..e7ed47a609 100644 --- a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts +++ b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts @@ -23,6 +23,8 @@ const withUsage = createDocumentationMessageGenerator({ connector: true, }); +const DEFAULT_SORT = ['name:asc']; + export type HierarchicalMenuItem = { /** * Value of the menu item. @@ -174,7 +176,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera limit = 10, showMore = false, showMoreLimit = 20, - sortBy = ['name:asc'], + sortBy = DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -273,11 +275,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(); @@ -336,6 +333,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 diff --git a/src/connectors/menu/__tests__/connectMenu-test.ts b/src/connectors/menu/__tests__/connectMenu-test.ts index 45bc496ca0..a81e8ec568 100644 --- a/src/connectors/menu/__tests__/connectMenu-test.ts +++ b/src/connectors/menu/__tests__/connectMenu-test.ts @@ -560,7 +560,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co }); describe('getWidgetRenderState', () => { - test('returns the widget render state', () => { + test('returns the widget render state (init)', () => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createMenu = connectMenu(renderFn, unmountFn); @@ -589,6 +589,202 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co widgetParams: { attribute: 'brand' }, }); }); + + test('returns the widget render state (render)', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createMenu = connectMenu(renderFn, unmountFn); + const menu = createMenu({ + attribute: 'brand', + }); + const helper = jsHelper( + createSearchClient(), + 'indexName', + menu.getWidgetSearchParameters!(new SearchParameters(), { uiState: {} }) + ); + + const renderState1 = menu.getWidgetRenderState( + createRenderOptions({ + helper, + results: new SearchResults(helper.state, [ + createSingleSearchResponse({ + facets: { + brand: { + Apple: 100, + Samsung: 1, + }, + }, + }), + ]), + }) + ); + + expect(renderState1).toEqual({ + items: [ + { + count: 100, + data: null, + exhaustive: true, + isRefined: false, + label: 'Apple', + value: 'Apple', + }, + { + count: 1, + data: null, + exhaustive: true, + isRefined: false, + label: 'Samsung', + value: 'Samsung', + }, + ], + createURL: expect.any(Function), + refine: expect.any(Function), + sendEvent: expect.any(Function), + canRefine: true, + isShowingMore: false, + toggleShowMore: expect.any(Function), + canToggleShowMore: false, + widgetParams: { attribute: 'brand' }, + }); + }); + + test('uses facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createMenu = connectMenu(renderFn, unmountFn); + const menu = createMenu({ + attribute: 'brand', + }); + const helper = jsHelper( + createSearchClient(), + 'indexName', + menu.getWidgetSearchParameters!(new SearchParameters(), { uiState: {} }) + ); + + const renderState1 = menu.getWidgetRenderState( + createRenderOptions({ + helper, + results: new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'count', + }, + }, + }, + }, + facets: { + brand: { + Apple: 100, + Algolia: 3, + Samsung: 1, + }, + }, + }), + ]), + }) + ); + + expect(renderState1.items).toEqual([ + { + count: 1, + data: null, + exhaustive: true, + isRefined: false, + label: 'Samsung', + value: 'Samsung', + }, + { + count: 100, + data: null, + exhaustive: true, + isRefined: false, + label: 'Apple', + value: 'Apple', + }, + { + count: 3, + data: null, + exhaustive: true, + isRefined: false, + label: 'Algolia', + value: 'Algolia', + }, + ]); + }); + + test('uses sortBy instead of facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createMenu = connectMenu(renderFn, unmountFn); + const menu = createMenu({ + attribute: 'brand', + sortBy: ['name:asc'], + }); + const helper = jsHelper( + createSearchClient(), + 'indexName', + menu.getWidgetSearchParameters!(new SearchParameters(), { uiState: {} }) + ); + + const renderState1 = menu.getWidgetRenderState( + createRenderOptions({ + helper, + results: new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'count', + }, + }, + }, + }, + facets: { + brand: { + Apple: 100, + Algolia: 3, + Samsung: 1, + }, + }, + }), + ]), + }) + ); + + expect(renderState1.items).toEqual([ + { + count: 3, + data: null, + exhaustive: true, + isRefined: false, + label: 'Algolia', + value: 'Algolia', + }, + { + count: 100, + data: null, + exhaustive: true, + isRefined: false, + label: 'Apple', + value: 'Apple', + }, + { + count: 1, + data: null, + exhaustive: true, + isRefined: false, + label: 'Samsung', + value: 'Samsung', + }, + ]); + }); }); describe('showMore', () => { diff --git a/src/connectors/menu/connectMenu.ts b/src/connectors/menu/connectMenu.ts index 1fe4bf610e..d4edf499eb 100644 --- a/src/connectors/menu/connectMenu.ts +++ b/src/connectors/menu/connectMenu.ts @@ -19,6 +19,8 @@ const withUsage = createDocumentationMessageGenerator({ connector: true, }); +const DEFAULT_SORT = ['isRefined', 'name:asc']; + export type MenuItem = { /** * The value of the menu item. @@ -147,7 +149,7 @@ const connectMenu: MenuConnector = function connectMenu( limit = 10, showMore = false, showMoreLimit = 20, - sortBy = ['isRefined', 'name:asc'], + sortBy = DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -286,6 +288,7 @@ const connectMenu: MenuConnector = function connectMenu( if (results) { const facetValues = results.getFacetValues(attribute, { sortBy, + facetOrdering: sortBy === DEFAULT_SORT, }); const facetItems = facetValues && !Array.isArray(facetValues) && facetValues.data diff --git a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts index 6c03aec07c..43cb0754d3 100644 --- a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts +++ b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts @@ -2589,6 +2589,153 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }) ); }); + + it('uses facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createRefinementList = connectRefinementList(renderFn, unmountFn); + const refinementListWidget = createRefinementList({ attribute: 'brand' }); + const helper = jsHelper(createSearchClient(), 'indexName', { + disjunctiveFacets: ['brand'], + disjunctiveFacetsRefinements: { + brand: ['Apple', 'Samsung'], + }, + }); + + const results = new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Microsoft'], + sortRemainingBy: 'alpha', + }, + }, + }, + }, + hits: [], + facets: { + brand: { + Apple: 88, + Microsoft: 66, + Samsung: 44, + }, + }, + }), + ]); + + const renderOptions = createRenderOptions({ + helper, + state: helper.state, + results, + }); + + const renderState = refinementListWidget.getWidgetRenderState( + renderOptions + ); + + expect(renderState.items).toMatchInlineSnapshot(` + Array [ + Object { + "count": 66, + "highlighted": "Microsoft", + "isRefined": false, + "label": "Microsoft", + "value": "Microsoft", + }, + Object { + "count": 88, + "highlighted": "Apple", + "isRefined": true, + "label": "Apple", + "value": "Apple", + }, + Object { + "count": 44, + "highlighted": "Samsung", + "isRefined": true, + "label": "Samsung", + "value": "Samsung", + }, + ] + `); + }); + + it('uses sortBy instead of facetOrdering if available for items', () => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createRefinementList = connectRefinementList(renderFn, unmountFn); + const refinementListWidget = createRefinementList({ + attribute: 'brand', + sortBy: ['isRefined'], + }); + const helper = jsHelper(createSearchClient(), 'indexName', { + disjunctiveFacets: ['brand'], + disjunctiveFacetsRefinements: { + brand: ['Apple', 'Samsung'], + }, + }); + + const results = new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Microsoft'], + sortRemainingBy: 'alpha', + }, + }, + }, + }, + hits: [], + facets: { + brand: { + Apple: 88, + Microsoft: 66, + Samsung: 44, + }, + }, + }), + ]); + + const renderOptions = createRenderOptions({ + helper, + state: helper.state, + results, + }); + + const renderState = refinementListWidget.getWidgetRenderState( + renderOptions + ); + + expect(renderState.items).toMatchInlineSnapshot(` + Array [ + Object { + "count": 88, + "highlighted": "Apple", + "isRefined": true, + "label": "Apple", + "value": "Apple", + }, + Object { + "count": 44, + "highlighted": "Samsung", + "isRefined": true, + "label": "Samsung", + "value": "Samsung", + }, + Object { + "count": 66, + "highlighted": "Microsoft", + "isRefined": false, + "label": "Microsoft", + "value": "Microsoft", + }, + ] + `); + }); }); describe('getWidgetSearchParameters', () => { diff --git a/src/connectors/refinement-list/connectRefinementList.ts b/src/connectors/refinement-list/connectRefinementList.ts index 22c5e44c31..deeab4f6c2 100644 --- a/src/connectors/refinement-list/connectRefinementList.ts +++ b/src/connectors/refinement-list/connectRefinementList.ts @@ -26,6 +26,8 @@ const withUsage = createDocumentationMessageGenerator({ connector: true, }); +const DEFAULT_SORT = ['isRefined', 'count:desc', 'name:asc']; + export type RefinementListItem = { /** * The value of the refinement list item. @@ -182,7 +184,7 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen limit = 10, showMore = false, showMoreLimit = 20, - sortBy = ['isRefined', 'count:desc', 'name:asc'], + sortBy = DEFAULT_SORT, escapeFacetValues = true, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -386,6 +388,7 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen if (results) { const values = results.getFacetValues(attribute, { sortBy, + facetOrdering: sortBy === DEFAULT_SORT, }); facetValues = values && Array.isArray(values) ? values : []; items = transformItems( diff --git a/yarn.lock b/yarn.lock index 1538973603..8b955725ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3545,10 +3545,10 @@ ajv@^6.12.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -algoliasearch-helper@^3.4.5: - version "3.4.5" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.4.5.tgz#f907494cf7057f9fc4f91e7dee9a40fee789ac5c" - integrity sha512-CrVoQE1i7jL1vmTx7Eus+ZS+f4gYUzGbswi2GR26xUtS9kVjjiZZVBaIXmCQJIV/NJIH1GJoJ3GoM6CKDabcRg== +algoliasearch-helper@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.5.3.tgz#fbf8b328bc103efdefde59a7d25eaffe85b2490f" + integrity sha512-DtSlOKAJ6TGkQD6u58g6/ABdMmHf3pAj6xVL5hJF+D4z9ldDRf/f5v6puNIxGOlJRwGVvFGyz34beYNqhLDUbQ== dependencies: events "^1.1.1" From 51acbfb42795489ece8dfd10efca1ded965140a8 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 16 Jun 2021 11:42:39 +0200 Subject: [PATCH 2/6] 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) --- .../__tests__/connectHierarchicalMenu-test.ts | 354 ++++++++---------- .../connectHierarchicalMenu.ts | 8 +- .../menu/__tests__/connectMenu-test.ts | 160 ++++---- src/connectors/menu/connectMenu.ts | 8 +- .../__tests__/connectRefinementList-test.ts | 257 ++++++------- .../refinement-list/connectRefinementList.ts | 8 +- .../__tests__/hierarchical-menu-test.ts | 17 +- 7 files changed, 381 insertions(+), 431 deletions(-) diff --git a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts index b3d7bb6b5f..3686bdd90e 100644 --- a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts +++ b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts @@ -692,217 +692,173 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica }); }); - test('uses facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createHierarchicalMenu = connectHierarchicalMenu( - renderFn, - unmountFn - ); - const hierarchicalMenu = createHierarchicalMenu({ - attributes: ['category', 'subCategory'], - }); - const helper = algoliasearchHelper( - createSearchClient(), - 'indexName', - hierarchicalMenu.getWidgetSearchParameters!(new SearchParameters(), { - uiState: { - hierarchicalMenu: { - category: ['Decoration'], - }, - }, - }) - ); - - hierarchicalMenu.init!(createInitOptions({ helper })); - - const results = new SearchResults(helper.state, [ - createSingleSearchResponse({ - renderingContent: { - facetOrdering: { - values: { - category: { - order: ['Outdoor'], - sortRemainingBy: 'alpha', - }, - subCategory: { - order: ['Decoration > Frames & pictures'], - sortRemainingBy: 'count', - }, - }, - }, - }, - facets: { - category: { - Decoration: 880, + 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', }, - subCategory: { - 'Decoration > Candle holders & candles': 193, - 'Decoration > Frames & pictures': 173, + { + count: 193, + data: null, + exhaustive: true, + isRefined: false, + label: 'Candle holders & candles', + value: 'Decoration > Candle holders & candles', }, - }, - }), - createSingleSearchResponse({ - facets: { - category: { - Decoration: 880, - Outdoor: 47, + ], + 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', }, - }, - }), - ]); - - const renderState = hierarchicalMenu.getWidgetRenderState( - createRenderOptions({ - helper, - results, - }) - ); - - expect(renderState.items).toMatchInlineSnapshot(` - Array [ - Object { - "count": 47, - "data": null, - "exhaustive": true, - "isRefined": false, - "label": "Outdoor", - "value": "Outdoor", - }, - Object { - "count": 880, - "data": Array [ - Object { - "count": 173, - "data": null, - "exhaustive": true, - "isRefined": false, - "label": "Frames & pictures", - "value": "Decoration > Frames & pictures", - }, - Object { - "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", - }, - ] - `); - }); - - test('sortBy overrides facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createHierarchicalMenu = connectHierarchicalMenu( - renderFn, - unmountFn - ); - const hierarchicalMenu = createHierarchicalMenu({ - attributes: ['category', 'subCategory'], - sortBy: ['name:asc'], - }); - const helper = algoliasearchHelper( - createSearchClient(), - 'indexName', - hierarchicalMenu.getWidgetSearchParameters!(new SearchParameters(), { - uiState: { - hierarchicalMenu: { - category: ['Decoration'], + { + count: 173, + data: null, + exhaustive: true, + isRefined: false, + label: 'Frames & pictures', + value: 'Decoration > Frames & pictures', }, - }, - }) - ); - - hierarchicalMenu.init!(createInitOptions({ helper })); + ], + exhaustive: true, + isRefined: true, + label: 'Decoration', + value: 'Decoration', + }, + { + count: 47, + data: null, + exhaustive: true, + isRefined: false, + label: 'Outdoor', + value: 'Outdoor', + }, + ]; + + test.each` + ordered | facetOrdering | sortBy | expected + ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${undefined} | ${resultsViaSortBy} + ${true} | ${true} | ${['name:asc']} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} + ${true} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} + ${true} | ${false} | ${undefined} | ${resultsViaSortBy} + ${false} | ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + `( + 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', + ({ ordered, facetOrdering, sortBy, expected }) => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createHierarchicalMenu = connectHierarchicalMenu( + renderFn, + unmountFn + ); + const hierarchicalMenu = createHierarchicalMenu({ + attributes: ['category', 'subCategory'], + facetOrdering, + sortBy, + }); + const helper = algoliasearchHelper( + createSearchClient(), + 'indexName', + hierarchicalMenu.getWidgetSearchParameters!( + new SearchParameters(), + { + uiState: { + hierarchicalMenu: { + category: ['Decoration'], + }, + }, + } + ) + ); + + hierarchicalMenu.init!(createInitOptions({ helper })); + + const renderingContent = ordered + ? { + 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: { - facetOrdering: { - values: { + const results = new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent, + facets: { category: { - order: ['Outdoor'], - sortRemainingBy: 'alpha', + Decoration: 880, }, subCategory: { - order: ['Decoration > Frames & pictures'], - sortRemainingBy: 'count', + 'Decoration > Candle holders & candles': 193, + 'Decoration > Frames & pictures': 173, }, }, - }, - }, - facets: { - category: { - Decoration: 880, - }, - subCategory: { - 'Decoration > Candle holders & candles': 193, - 'Decoration > Frames & pictures': 173, - }, - }, - }), - createSingleSearchResponse({ - facets: { - category: { - Decoration: 880, - Outdoor: 47, - }, - }, - }), - ]); + }), + createSingleSearchResponse({ + facets: { + category: { + Decoration: 880, + Outdoor: 47, + }, + }, + }), + ]); - const renderState = hierarchicalMenu.getWidgetRenderState( - createRenderOptions({ - helper, - results, - }) - ); + const renderState = hierarchicalMenu.getWidgetRenderState( + createRenderOptions({ + helper, + results, + }) + ); - expect(renderState.items).toMatchInlineSnapshot(` - Array [ - Object { - "count": 880, - "data": Array [ - Object { - "count": 193, - "data": null, - "exhaustive": true, - "isRefined": false, - "label": "Candle holders & candles", - "value": "Decoration > Candle holders & candles", - }, - Object { - "count": 173, - "data": null, - "exhaustive": true, - "isRefined": false, - "label": "Frames & pictures", - "value": "Decoration > Frames & pictures", - }, - ], - "exhaustive": true, - "isRefined": true, - "label": "Decoration", - "value": "Decoration", - }, - Object { - "count": 47, - "data": null, - "exhaustive": true, - "isRefined": false, - "label": "Outdoor", - "value": "Outdoor", - }, - ] - `); + expect(renderState.items).toEqual(expected); + } + ); }); }); diff --git a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts index e7ed47a609..fcbb78b136 100644 --- a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts +++ b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts @@ -83,6 +83,11 @@ export type HierarchicalMenuConnectorParams = { * 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). */ sortBy?: SortBy; + /** + * Apply the sorting of facet values defined in settings + * Defaults to `true` if sortBy is not given + */ + facetOrdering?: boolean; /** * Function to transform the items passed to the templates. */ @@ -177,6 +182,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, + facetOrdering = sortBy === DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -333,7 +339,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera if (results) { const facetValues = results.getFacetValues(hierarchicalFacetName, { sortBy, - facetOrdering: sortBy === DEFAULT_SORT, + facetOrdering, }); const facetItems = facetValues && !Array.isArray(facetValues) && facetValues.data diff --git a/src/connectors/menu/__tests__/connectMenu-test.ts b/src/connectors/menu/__tests__/connectMenu-test.ts index a81e8ec568..2c0882d04e 100644 --- a/src/connectors/menu/__tests__/connectMenu-test.ts +++ b/src/connectors/menu/__tests__/connectMenu-test.ts @@ -649,47 +649,8 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co }); }); - test('uses facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createMenu = connectMenu(renderFn, unmountFn); - const menu = createMenu({ - attribute: 'brand', - }); - const helper = jsHelper( - createSearchClient(), - 'indexName', - menu.getWidgetSearchParameters!(new SearchParameters(), { uiState: {} }) - ); - - const renderState1 = menu.getWidgetRenderState( - createRenderOptions({ - helper, - results: new SearchResults(helper.state, [ - createSingleSearchResponse({ - renderingContent: { - facetOrdering: { - values: { - brand: { - order: ['Samsung'], - sortRemainingBy: 'count', - }, - }, - }, - }, - facets: { - brand: { - Apple: 100, - Algolia: 3, - Samsung: 1, - }, - }, - }), - ]), - }) - ); - - expect(renderState1.items).toEqual([ + describe('facetOrdering', () => { + const resultsViaFacetOrdering = [ { count: 1, data: null, @@ -714,51 +675,8 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co label: 'Algolia', value: 'Algolia', }, - ]); - }); - - test('uses sortBy instead of facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createMenu = connectMenu(renderFn, unmountFn); - const menu = createMenu({ - attribute: 'brand', - sortBy: ['name:asc'], - }); - const helper = jsHelper( - createSearchClient(), - 'indexName', - menu.getWidgetSearchParameters!(new SearchParameters(), { uiState: {} }) - ); - - const renderState1 = menu.getWidgetRenderState( - createRenderOptions({ - helper, - results: new SearchResults(helper.state, [ - createSingleSearchResponse({ - renderingContent: { - facetOrdering: { - values: { - brand: { - order: ['Samsung'], - sortRemainingBy: 'count', - }, - }, - }, - }, - facets: { - brand: { - Apple: 100, - Algolia: 3, - Samsung: 1, - }, - }, - }), - ]), - }) - ); - - expect(renderState1.items).toEqual([ + ]; + const resultsViaSortBy = [ { count: 3, data: null, @@ -783,7 +701,75 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co label: 'Samsung', value: 'Samsung', }, - ]); + ]; + + test.each` + ordered | facetOrdering | sortBy | expected + ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${undefined} | ${resultsViaSortBy} + ${true} | ${true} | ${['name:asc']} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} + ${true} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} + ${true} | ${false} | ${undefined} | ${resultsViaSortBy} + ${false} | ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + `( + 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', + ({ ordered, facetOrdering, sortBy, expected }) => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createMenu = connectMenu(renderFn, unmountFn); + const menu = createMenu({ + attribute: 'brand', + sortBy, + facetOrdering, + }); + const helper = jsHelper( + createSearchClient(), + 'indexName', + menu.getWidgetSearchParameters!(new SearchParameters(), { + uiState: {}, + }) + ); + + const renderingContent = ordered + ? { + facetOrdering: { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'count' as const, + }, + }, + }, + } + : undefined; + + const renderState1 = menu.getWidgetRenderState( + createRenderOptions({ + helper, + results: new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent, + facets: { + brand: { + Apple: 100, + Algolia: 3, + Samsung: 1, + }, + }, + }), + ]), + }) + ); + + expect(renderState1.items).toEqual(expected); + } + ); }); }); diff --git a/src/connectors/menu/connectMenu.ts b/src/connectors/menu/connectMenu.ts index d4edf499eb..84cd433031 100644 --- a/src/connectors/menu/connectMenu.ts +++ b/src/connectors/menu/connectMenu.ts @@ -63,6 +63,11 @@ export type MenuConnectorParams = { * 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). */ sortBy?: SortBy; + /** + * Apply the sorting of facet values defined in settings + * Defaults to `true` if sortBy is not given + */ + facetOrdering?: boolean; /** * Function to transform the items passed to the templates. */ @@ -150,6 +155,7 @@ const connectMenu: MenuConnector = function connectMenu( showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, + facetOrdering = sortBy === DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -288,7 +294,7 @@ const connectMenu: MenuConnector = function connectMenu( if (results) { const facetValues = results.getFacetValues(attribute, { sortBy, - facetOrdering: sortBy === DEFAULT_SORT, + facetOrdering, }); const facetItems = facetValues && !Array.isArray(facetValues) && facetValues.data diff --git a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts index 43cb0754d3..d8a148295f 100644 --- a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts +++ b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts @@ -2590,151 +2590,126 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- ); }); - it('uses facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createRefinementList = connectRefinementList(renderFn, unmountFn); - const refinementListWidget = createRefinementList({ attribute: 'brand' }); - const helper = jsHelper(createSearchClient(), 'indexName', { - disjunctiveFacets: ['brand'], - disjunctiveFacetsRefinements: { - brand: ['Apple', 'Samsung'], + describe('facetOrdering', () => { + const resultsViaFacetOrdering = [ + { + count: 66, + highlighted: 'Microsoft', + isRefined: false, + label: 'Microsoft', + value: 'Microsoft', }, - }); - - const results = new SearchResults(helper.state, [ - createSingleSearchResponse({ - renderingContent: { - facetOrdering: { - values: { - brand: { - order: ['Microsoft'], - sortRemainingBy: 'alpha', - }, - }, - }, - }, - hits: [], - facets: { - brand: { - Apple: 88, - Microsoft: 66, - Samsung: 44, - }, - }, - }), - ]); - - const renderOptions = createRenderOptions({ - helper, - state: helper.state, - results, - }); - - const renderState = refinementListWidget.getWidgetRenderState( - renderOptions - ); - - expect(renderState.items).toMatchInlineSnapshot(` - Array [ - Object { - "count": 66, - "highlighted": "Microsoft", - "isRefined": false, - "label": "Microsoft", - "value": "Microsoft", - }, - Object { - "count": 88, - "highlighted": "Apple", - "isRefined": true, - "label": "Apple", - "value": "Apple", - }, - Object { - "count": 44, - "highlighted": "Samsung", - "isRefined": true, - "label": "Samsung", - "value": "Samsung", - }, - ] - `); - }); - - it('uses sortBy instead of facetOrdering if available for items', () => { - const renderFn = jest.fn(); - const unmountFn = jest.fn(); - const createRefinementList = connectRefinementList(renderFn, unmountFn); - const refinementListWidget = createRefinementList({ - attribute: 'brand', - sortBy: ['isRefined'], - }); - const helper = jsHelper(createSearchClient(), 'indexName', { - disjunctiveFacets: ['brand'], - disjunctiveFacetsRefinements: { - brand: ['Apple', 'Samsung'], + { + count: 88, + highlighted: 'Apple', + isRefined: true, + label: 'Apple', + value: 'Apple', }, - }); - - const results = new SearchResults(helper.state, [ - createSingleSearchResponse({ - renderingContent: { - facetOrdering: { - values: { - brand: { - order: ['Microsoft'], - sortRemainingBy: 'alpha', - }, + { + count: 44, + highlighted: 'Samsung', + isRefined: true, + label: 'Samsung', + value: 'Samsung', + }, + ]; + const resultsViaSortBy = [ + { + count: 88, + highlighted: 'Apple', + isRefined: true, + label: 'Apple', + value: 'Apple', + }, + { + count: 44, + highlighted: 'Samsung', + isRefined: true, + label: 'Samsung', + value: 'Samsung', + }, + { + count: 66, + highlighted: 'Microsoft', + isRefined: false, + label: 'Microsoft', + value: 'Microsoft', + }, + ]; + + test.each` + ordered | facetOrdering | sortBy | expected + ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${undefined} | ${resultsViaSortBy} + ${true} | ${true} | ${['isRefined']} | ${resultsViaFacetOrdering} + ${false} | ${true} | ${['isRefined']} | ${resultsViaSortBy} + ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} + ${true} | ${undefined} | ${['isRefined']} | ${resultsViaSortBy} + ${false} | ${undefined} | ${['isRefined']} | ${resultsViaSortBy} + ${true} | ${false} | ${undefined} | ${resultsViaSortBy} + ${false} | ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${false} | ${['isRefined']} | ${resultsViaSortBy} + ${false} | ${false} | ${['isRefined']} | ${resultsViaSortBy} + `( + 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', + ({ ordered, facetOrdering, sortBy, expected }) => { + const renderFn = jest.fn(); + const unmountFn = jest.fn(); + const createRefinementList = connectRefinementList( + renderFn, + unmountFn + ); + const refinementList = createRefinementList({ + attribute: 'brand', + sortBy, + facetOrdering, + }); + const helper = jsHelper( + createSearchClient(), + 'indexName', + refinementList.getWidgetSearchParameters!(new SearchParameters(), { + uiState: { + refinementList: { brand: ['Apple', 'Samsung'] }, }, - }, - }, - hits: [], - facets: { - brand: { - Apple: 88, - Microsoft: 66, - Samsung: 44, - }, - }, - }), - ]); - - const renderOptions = createRenderOptions({ - helper, - state: helper.state, - results, - }); - - const renderState = refinementListWidget.getWidgetRenderState( - renderOptions + }) + ); + + const renderingContent = ordered + ? { + facetOrdering: { + values: { + brand: { + order: ['Microsoft'], + sortRemainingBy: 'alpha' as const, + }, + }, + }, + } + : undefined; + + const renderState1 = refinementList.getWidgetRenderState( + createRenderOptions({ + helper, + results: new SearchResults(helper.state, [ + createSingleSearchResponse({ + renderingContent, + facets: { + brand: { + Apple: 88, + Microsoft: 66, + Samsung: 44, + }, + }, + }), + ]), + }) + ); + + expect(renderState1.items).toEqual(expected); + } ); - - expect(renderState.items).toMatchInlineSnapshot(` - Array [ - Object { - "count": 88, - "highlighted": "Apple", - "isRefined": true, - "label": "Apple", - "value": "Apple", - }, - Object { - "count": 44, - "highlighted": "Samsung", - "isRefined": true, - "label": "Samsung", - "value": "Samsung", - }, - Object { - "count": 66, - "highlighted": "Microsoft", - "isRefined": false, - "label": "Microsoft", - "value": "Microsoft", - }, - ] - `); }); }); diff --git a/src/connectors/refinement-list/connectRefinementList.ts b/src/connectors/refinement-list/connectRefinementList.ts index deeab4f6c2..93a3b63bf9 100644 --- a/src/connectors/refinement-list/connectRefinementList.ts +++ b/src/connectors/refinement-list/connectRefinementList.ts @@ -78,6 +78,11 @@ export type RefinementListConnectorParams = { * How to sort refinements. Possible values: `count|isRefined|name:asc|name:desc`. */ sortBy?: SortBy; + /** + * Apply the sorting of facet values defined in settings. + * Defaults to `true` if sortBy is not given + */ + facetOrdering?: boolean; /** * Escapes the content of the facet values. */ @@ -185,6 +190,7 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, + facetOrdering = sortBy === DEFAULT_SORT, escapeFacetValues = true, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -388,7 +394,7 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen if (results) { const values = results.getFacetValues(attribute, { sortBy, - facetOrdering: sortBy === DEFAULT_SORT, + facetOrdering, }); facetValues = values && Array.isArray(values) ? values : []; items = transformItems( diff --git a/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts b/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts index ea91fbe8c4..b3b3009ac3 100644 --- a/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts +++ b/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts @@ -133,18 +133,33 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica expect(results.getFacetValues).toHaveBeenCalledTimes(1); expect(results.getFacetValues).toHaveBeenCalledWith('hello', { + facetOrdering: true, sortBy: ['name:asc'], }); }); it('has a sortBy option', () => { - widget = hierarchicalMenu({ ...options, sortBy: ['name:asc'] }); + widget = hierarchicalMenu({ ...options, sortBy: ['name:desc'] }); widget.init!(createInitOptions({ helper })); widget.render!(createRenderOptions({ results, state })); expect(results.getFacetValues).toHaveBeenCalledTimes(1); expect(results.getFacetValues).toHaveBeenCalledWith('hello', { + facetOrdering: false, + sortBy: ['name:desc'], + }); + }); + + it('has a facetOrdering option', () => { + widget = hierarchicalMenu({ ...options, facetOrdering: false }); + + widget.init!(createInitOptions({ helper })); + widget.render!(createRenderOptions({ results, state })); + + expect(results.getFacetValues).toHaveBeenCalledTimes(1); + expect(results.getFacetValues).toHaveBeenCalledWith('hello', { + facetOrdering: false, sortBy: ['name:asc'], }); }); From 84110e5047d1b9188a14ef8522175ea0ebea601a Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 16 Jun 2021 11:51:45 +0200 Subject: [PATCH 3/6] forward facetOrdering option from widget --- src/widgets/hierarchical-menu/hierarchical-menu.tsx | 2 ++ src/widgets/menu/menu.tsx | 2 ++ src/widgets/refinement-list/refinement-list.tsx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/widgets/hierarchical-menu/hierarchical-menu.tsx b/src/widgets/hierarchical-menu/hierarchical-menu.tsx index a3bd0d5081..9b365ac5bb 100644 --- a/src/widgets/hierarchical-menu/hierarchical-menu.tsx +++ b/src/widgets/hierarchical-menu/hierarchical-menu.tsx @@ -295,6 +295,7 @@ const hierarchicalMenu: HierarchicalMenuWidget = function hierarchicalMenu( showMore = false, showMoreLimit, sortBy, + facetOrdering, transformItems, templates = defaultTemplates, cssClasses: userCssClasses = {}, @@ -358,6 +359,7 @@ const hierarchicalMenu: HierarchicalMenuWidget = function hierarchicalMenu( showMore, showMoreLimit, sortBy, + facetOrdering, transformItems, }), $$widgetType: 'ais.hierarchicalMenu', diff --git a/src/widgets/menu/menu.tsx b/src/widgets/menu/menu.tsx index 6fcae72c8a..c69863e9eb 100644 --- a/src/widgets/menu/menu.tsx +++ b/src/widgets/menu/menu.tsx @@ -171,6 +171,7 @@ const menu: MenuWidget = function menu(widgetParams) { container, attribute, sortBy, + facetOrdering, limit, showMore, showMoreLimit, @@ -226,6 +227,7 @@ const menu: MenuWidget = function menu(widgetParams) { showMore, showMoreLimit, sortBy, + facetOrdering, transformItems, }), $$widgetType: 'ais.menu', diff --git a/src/widgets/refinement-list/refinement-list.tsx b/src/widgets/refinement-list/refinement-list.tsx index 206a5cb019..80e058fc47 100644 --- a/src/widgets/refinement-list/refinement-list.tsx +++ b/src/widgets/refinement-list/refinement-list.tsx @@ -324,6 +324,7 @@ const refinementList: RefinementListWidget = function refinementList( attribute, operator, sortBy, + facetOrdering, limit, showMore, showMoreLimit, @@ -442,6 +443,7 @@ const refinementList: RefinementListWidget = function refinementList( showMore, showMoreLimit, sortBy, + facetOrdering, escapeFacetValues, transformItems, }), From c36108b336810f18d537d374625373c82812df84 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 16 Jun 2021 11:53:01 +0200 Subject: [PATCH 4/6] suppress v3 ts errors --- tsconfig.v3.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tsconfig.v3.json b/tsconfig.v3.json index f7f443fd37..356a202897 100644 --- a/tsconfig.v3.json +++ b/tsconfig.v3.json @@ -13,6 +13,9 @@ // v3 has a wrong definition for optionalWords (only accepts string[]) "src/connectors/voice-search/__tests__/connectVoiceSearch-test.ts", // v3 does not have renderingContent (only errors in the test) - "src/connectors/dynamic-widgets/__tests__/connectDynamicWidgets-test.ts" + "src/connectors/dynamic-widgets/__tests__/connectDynamicWidgets-test.ts", + "src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts", + "src/connectors/menu/__tests__/connectMenu-test.ts", + "src/connectors/refinement-list/__tests__/connectRefinementList-test.ts" ] } From 4ca56a90e15d037af5c9f50c1173e526cfb57c8a Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Mon, 5 Jul 2021 13:28:32 +0200 Subject: [PATCH 5/6] remove option --- .../__tests__/connectHierarchicalMenu-test.ts | 23 ++++++------------- .../connectHierarchicalMenu.ts | 10 +++----- .../menu/__tests__/connectMenu-test.ts | 23 ++++++------------- src/connectors/menu/connectMenu.ts | 10 +++----- .../__tests__/connectRefinementList-test.ts | 23 ++++++------------- .../refinement-list/connectRefinementList.ts | 12 ++++------ .../__tests__/hierarchical-menu-test.ts | 13 ----------- .../hierarchical-menu/hierarchical-menu.tsx | 2 -- src/widgets/menu/menu.tsx | 2 -- .../refinement-list/refinement-list.tsx | 2 -- 10 files changed, 32 insertions(+), 88 deletions(-) diff --git a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts index 3686bdd90e..6b0a1cc72d 100644 --- a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts +++ b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts @@ -765,22 +765,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica ]; test.each` - ordered | facetOrdering | sortBy | expected - ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${undefined} | ${resultsViaSortBy} - ${true} | ${true} | ${['name:asc']} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${['name:asc']} | ${resultsViaSortBy} - ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} - ${true} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} - ${true} | ${false} | ${undefined} | ${resultsViaSortBy} - ${false} | ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${false} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + ordered | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${['name:asc']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', - ({ ordered, facetOrdering, sortBy, expected }) => { + 'renderingContent present: $ordered, sortBy: $sortBy', + ({ ordered, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createHierarchicalMenu = connectHierarchicalMenu( @@ -789,7 +781,6 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica ); const hierarchicalMenu = createHierarchicalMenu({ attributes: ['category', 'subCategory'], - facetOrdering, sortBy, }); const helper = algoliasearchHelper( diff --git a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts index fcbb78b136..eb99992882 100644 --- a/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts +++ b/src/connectors/hierarchical-menu/connectHierarchicalMenu.ts @@ -81,13 +81,10 @@ 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; - /** - * Apply the sorting of facet values defined in settings - * Defaults to `true` if sortBy is not given - */ - facetOrdering?: boolean; /** * Function to transform the items passed to the templates. */ @@ -182,7 +179,6 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, - facetOrdering = sortBy === DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -339,7 +335,7 @@ const connectHierarchicalMenu: HierarchicalMenuConnector = function connectHiera if (results) { const facetValues = results.getFacetValues(hierarchicalFacetName, { sortBy, - facetOrdering, + facetOrdering: sortBy === DEFAULT_SORT, }); const facetItems = facetValues && !Array.isArray(facetValues) && facetValues.data diff --git a/src/connectors/menu/__tests__/connectMenu-test.ts b/src/connectors/menu/__tests__/connectMenu-test.ts index 2c0882d04e..c37faa8c3d 100644 --- a/src/connectors/menu/__tests__/connectMenu-test.ts +++ b/src/connectors/menu/__tests__/connectMenu-test.ts @@ -704,29 +704,20 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co ]; test.each` - ordered | facetOrdering | sortBy | expected - ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${undefined} | ${resultsViaSortBy} - ${true} | ${true} | ${['name:asc']} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${['name:asc']} | ${resultsViaSortBy} - ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} - ${true} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${undefined} | ${['name:asc']} | ${resultsViaSortBy} - ${true} | ${false} | ${undefined} | ${resultsViaSortBy} - ${false} | ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${false} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${false} | ${['name:asc']} | ${resultsViaSortBy} + ordered | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${['name:asc']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', - ({ ordered, facetOrdering, sortBy, expected }) => { + 'renderingContent present: $ordered, sortBy: $sortBy', + ({ ordered, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createMenu = connectMenu(renderFn, unmountFn); const menu = createMenu({ attribute: 'brand', sortBy, - facetOrdering, }); const helper = jsHelper( createSearchClient(), diff --git a/src/connectors/menu/connectMenu.ts b/src/connectors/menu/connectMenu.ts index 84cd433031..4ad7148a02 100644 --- a/src/connectors/menu/connectMenu.ts +++ b/src/connectors/menu/connectMenu.ts @@ -61,13 +61,10 @@ export type MenuConnectorParams = { * 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; - /** - * Apply the sorting of facet values defined in settings - * Defaults to `true` if sortBy is not given - */ - facetOrdering?: boolean; /** * Function to transform the items passed to the templates. */ @@ -155,7 +152,6 @@ const connectMenu: MenuConnector = function connectMenu( showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, - facetOrdering = sortBy === DEFAULT_SORT, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -294,7 +290,7 @@ const connectMenu: MenuConnector = function connectMenu( if (results) { const facetValues = results.getFacetValues(attribute, { sortBy, - facetOrdering, + facetOrdering: sortBy === DEFAULT_SORT, }); const facetItems = facetValues && !Array.isArray(facetValues) && facetValues.data diff --git a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts index d8a148295f..76474fe80e 100644 --- a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts +++ b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts @@ -2639,22 +2639,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- ]; test.each` - ordered | facetOrdering | sortBy | expected - ${true} | ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${undefined} | ${resultsViaSortBy} - ${true} | ${true} | ${['isRefined']} | ${resultsViaFacetOrdering} - ${false} | ${true} | ${['isRefined']} | ${resultsViaSortBy} - ${true} | ${undefined} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${undefined} | ${resultsViaSortBy} - ${true} | ${undefined} | ${['isRefined']} | ${resultsViaSortBy} - ${false} | ${undefined} | ${['isRefined']} | ${resultsViaSortBy} - ${true} | ${false} | ${undefined} | ${resultsViaSortBy} - ${false} | ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${false} | ${['isRefined']} | ${resultsViaSortBy} - ${false} | ${false} | ${['isRefined']} | ${resultsViaSortBy} + ordered | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['isRefined']} | ${resultsViaSortBy} + ${false} | ${['isRefined']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, facetOrdering: $facetOrdering, sortBy: $sortBy', - ({ ordered, facetOrdering, sortBy, expected }) => { + 'renderingContent present: $ordered, sortBy: $sortBy', + ({ ordered, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createRefinementList = connectRefinementList( @@ -2664,7 +2656,6 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const refinementList = createRefinementList({ attribute: 'brand', sortBy, - facetOrdering, }); const helper = jsHelper( createSearchClient(), diff --git a/src/connectors/refinement-list/connectRefinementList.ts b/src/connectors/refinement-list/connectRefinementList.ts index 93a3b63bf9..5951d9b956 100644 --- a/src/connectors/refinement-list/connectRefinementList.ts +++ b/src/connectors/refinement-list/connectRefinementList.ts @@ -76,13 +76,12 @@ export type RefinementListConnectorParams = { showMoreLimit?: number; /** * 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; - /** - * Apply the sorting of facet values defined in settings. - * Defaults to `true` if sortBy is not given - */ - facetOrdering?: boolean; /** * Escapes the content of the facet values. */ @@ -190,7 +189,6 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen showMore = false, showMoreLimit = 20, sortBy = DEFAULT_SORT, - facetOrdering = sortBy === DEFAULT_SORT, escapeFacetValues = true, transformItems = (items => items) as TransformItems, } = widgetParams || {}; @@ -394,7 +392,7 @@ const connectRefinementList: RefinementListConnector = function connectRefinemen if (results) { const values = results.getFacetValues(attribute, { sortBy, - facetOrdering, + facetOrdering: sortBy === DEFAULT_SORT, }); facetValues = values && Array.isArray(values) ? values : []; items = transformItems( diff --git a/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts b/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts index b3b3009ac3..0da2df13e4 100644 --- a/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts +++ b/src/widgets/hierarchical-menu/__tests__/hierarchical-menu-test.ts @@ -151,19 +151,6 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica }); }); - it('has a facetOrdering option', () => { - widget = hierarchicalMenu({ ...options, facetOrdering: false }); - - widget.init!(createInitOptions({ helper })); - widget.render!(createRenderOptions({ results, state })); - - expect(results.getFacetValues).toHaveBeenCalledTimes(1); - expect(results.getFacetValues).toHaveBeenCalledWith('hello', { - facetOrdering: false, - sortBy: ['name:asc'], - }); - }); - it('has a templates option', () => { widget = hierarchicalMenu({ ...options, diff --git a/src/widgets/hierarchical-menu/hierarchical-menu.tsx b/src/widgets/hierarchical-menu/hierarchical-menu.tsx index 9b365ac5bb..a3bd0d5081 100644 --- a/src/widgets/hierarchical-menu/hierarchical-menu.tsx +++ b/src/widgets/hierarchical-menu/hierarchical-menu.tsx @@ -295,7 +295,6 @@ const hierarchicalMenu: HierarchicalMenuWidget = function hierarchicalMenu( showMore = false, showMoreLimit, sortBy, - facetOrdering, transformItems, templates = defaultTemplates, cssClasses: userCssClasses = {}, @@ -359,7 +358,6 @@ const hierarchicalMenu: HierarchicalMenuWidget = function hierarchicalMenu( showMore, showMoreLimit, sortBy, - facetOrdering, transformItems, }), $$widgetType: 'ais.hierarchicalMenu', diff --git a/src/widgets/menu/menu.tsx b/src/widgets/menu/menu.tsx index c69863e9eb..6fcae72c8a 100644 --- a/src/widgets/menu/menu.tsx +++ b/src/widgets/menu/menu.tsx @@ -171,7 +171,6 @@ const menu: MenuWidget = function menu(widgetParams) { container, attribute, sortBy, - facetOrdering, limit, showMore, showMoreLimit, @@ -227,7 +226,6 @@ const menu: MenuWidget = function menu(widgetParams) { showMore, showMoreLimit, sortBy, - facetOrdering, transformItems, }), $$widgetType: 'ais.menu', diff --git a/src/widgets/refinement-list/refinement-list.tsx b/src/widgets/refinement-list/refinement-list.tsx index 80e058fc47..206a5cb019 100644 --- a/src/widgets/refinement-list/refinement-list.tsx +++ b/src/widgets/refinement-list/refinement-list.tsx @@ -324,7 +324,6 @@ const refinementList: RefinementListWidget = function refinementList( attribute, operator, sortBy, - facetOrdering, limit, showMore, showMoreLimit, @@ -443,7 +442,6 @@ const refinementList: RefinementListWidget = function refinementList( showMore, showMoreLimit, sortBy, - facetOrdering, escapeFacetValues, transformItems, }), From 53b3745987686d8b84c4742ead607a0b821bd32d Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Mon, 5 Jul 2021 13:52:10 +0200 Subject: [PATCH 6/6] test: rename --- .../__tests__/connectHierarchicalMenu-test.ts | 16 ++++++++-------- .../menu/__tests__/connectMenu-test.ts | 16 ++++++++-------- .../__tests__/connectRefinementList-test.ts | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts index 6b0a1cc72d..59cc466947 100644 --- a/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts +++ b/src/connectors/hierarchical-menu/__tests__/connectHierarchicalMenu-test.ts @@ -765,14 +765,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica ]; test.each` - ordered | sortBy | expected - ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${['name:asc']} | ${resultsViaSortBy} + facetOrderingInResult | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${['name:asc']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, sortBy: $sortBy', - ({ ordered, sortBy, expected }) => { + 'renderingContent present: $facetOrderingInResult, sortBy: $sortBy', + ({ facetOrderingInResult, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createHierarchicalMenu = connectHierarchicalMenu( @@ -800,7 +800,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hierarchica hierarchicalMenu.init!(createInitOptions({ helper })); - const renderingContent = ordered + const renderingContent = facetOrderingInResult ? { facetOrdering: { values: { diff --git a/src/connectors/menu/__tests__/connectMenu-test.ts b/src/connectors/menu/__tests__/connectMenu-test.ts index c37faa8c3d..e4a2535c03 100644 --- a/src/connectors/menu/__tests__/connectMenu-test.ts +++ b/src/connectors/menu/__tests__/connectMenu-test.ts @@ -704,14 +704,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co ]; test.each` - ordered | sortBy | expected - ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${['name:asc']} | ${resultsViaSortBy} - ${false} | ${['name:asc']} | ${resultsViaSortBy} + facetOrderingInResult | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['name:asc']} | ${resultsViaSortBy} + ${false} | ${['name:asc']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, sortBy: $sortBy', - ({ ordered, sortBy, expected }) => { + 'renderingContent present: $facetOrderingInResult, sortBy: $sortBy', + ({ facetOrderingInResult, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createMenu = connectMenu(renderFn, unmountFn); @@ -727,7 +727,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co }) ); - const renderingContent = ordered + const renderingContent = facetOrderingInResult ? { facetOrdering: { values: { diff --git a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts index 76474fe80e..e14c8ab88b 100644 --- a/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts +++ b/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts @@ -2639,14 +2639,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- ]; test.each` - ordered | sortBy | expected - ${true} | ${undefined} | ${resultsViaFacetOrdering} - ${false} | ${undefined} | ${resultsViaSortBy} - ${true} | ${['isRefined']} | ${resultsViaSortBy} - ${false} | ${['isRefined']} | ${resultsViaSortBy} + facetOrderingInResult | sortBy | expected + ${true} | ${undefined} | ${resultsViaFacetOrdering} + ${false} | ${undefined} | ${resultsViaSortBy} + ${true} | ${['isRefined']} | ${resultsViaSortBy} + ${false} | ${['isRefined']} | ${resultsViaSortBy} `( - 'renderingContent present: $ordered, sortBy: $sortBy', - ({ ordered, sortBy, expected }) => { + 'renderingContent present: $facetOrderingInResult, sortBy: $sortBy', + ({ facetOrderingInResult, sortBy, expected }) => { const renderFn = jest.fn(); const unmountFn = jest.fn(); const createRefinementList = connectRefinementList( @@ -2667,7 +2667,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }) ); - const renderingContent = ordered + const renderingContent = facetOrderingInResult ? { facetOrdering: { values: {