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

feat(index): compute local uiState #3997

Merged
merged 9 commits into from
Jul 31, 2019
Merged

feat(index): compute local uiState #3997

merged 9 commits into from
Jul 31, 2019

Conversation

samouss
Copy link
Contributor

@samouss samouss commented Jul 30, 2019

This PR introduces the concept of uiState into the index widget. Previously the uiState was only present inside the RoutingManager. Now it's a first class citizen of InstantSearch. One of its main usage will be the computation of the SearchParameters.

To keep the uiState up-to-date at the index level each instance subscribe to the change event on its Helper. Each time a widget (e.g. refine) or an index (e.g. add/remove setState) alter the state it triggers an update of the uiState.

The index now implements the function getWidgetState. This function will walk down the tree on each index to collect the complete uiState for the instance. The function will be useful to get the full uiState from the top level InstantSearch instance.

The format of the uiState changed. Each indices is now scoped under its identifier which is by default the name of the index (it will change to be able to target multiple times the same index). We've made this change because it's way simpler to work with a structure like this one. We don't have to branch to detect whether or not we are at the root (versus the one inside React InstantSearch). Any other ideas/alternatives are welcome!

Edit: With this new shape of uiState that would be nice to detect whether or not we are in a single/multi index context. That would allow us to preserve the current shape of URL with a single index. We can investigate when we adapt the routing mechanism.

Old format:

{
  "refinementList": {
    "brand": ["Apple"]
  }
}

New format: non back-ward compatible

{
  "instant_search": {
    "refinementList": {
      "brand": ["Apple"]
    }
  },
  "instant_search_price_asc": {
    "query": "iPhone",
    "menu": {
      "categories": "Phone"
    }
  }
}

Alternative format: back-ward compatible (React InstantSearch)

{
  "refinementList": {
    "brand": ["Apple"]
  },
  "indices": {
    "instant_search_price_asc": {
      "query": "iPhone",
      "menu": {
        "categories": "Phone"
      }
    }
  }
}

@samouss samouss requested a review from a team July 30, 2019 10:43
@ghost ghost requested review from francoischalifour and Haroenv and removed request for a team July 30, 2019 10:43
@Haroenv
Copy link
Contributor

Haroenv commented Jul 30, 2019

I like the change in the shape of uiState, because it avoids us to branch all over the place. However, I wonder if we could make the default stateMapping remove a nesting level if there's only one index.

Copy link
Member

@francoischalifour francoischalifour left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have keys for all indices (which is the way to go IMO), how are we going to handle URL routing?

My guess would be that when we detect there's a single index used, we keep the same structure as right now. Once there are multiple indices, we change the structure of the URL. This won't bring breaking changes, which is delicate when it comes to routing because we break all existing URLs.

src/widgets/index/index.ts Show resolved Hide resolved
src/widgets/index/__tests__/index-test.ts Outdated Show resolved Hide resolved
src/widgets/index/__tests__/index-test.ts Outdated Show resolved Hide resolved
src/widgets/index/index.ts Show resolved Hide resolved
Co-Authored-By: François Chalifour <francoischalifour@users.noreply.github.com>
@samouss
Copy link
Contributor Author

samouss commented Jul 31, 2019

Since we have keys for all indices (which is the way to go IMO), how are we going to handle URL routing?

My guess would be that when we detect there's a single index used, we keep the same structure as right now. Once there are multiple indices, we change the structure of the URL. This won't bring breaking changes, which is delicate when it comes to routing because we break all existing URLs.

Yes forgot to mention it inside the description (I've added it), but the idea is to be able to detect somewhere (state mapping? before the call to state mapping? This can be decided when we adapt the URLSync) that we are inside a single/multi index context. For a single index, we should keep the same shape of URL that we have today. For a multi-index then we use the default serializer. Note that if users wrote their state mapping they might have to update themselves to match the new structure (depends on the solution we choose).

@samouss samouss merged commit 6df3d40 into next Jul 31, 2019
@samouss samouss deleted the feat/local-ui-state branch July 31, 2019 13:52
samouss added a commit that referenced this pull request Sep 17, 2019
* feat(types): create types for getWidgetState/getWidgetSearchParameters arguments

* feat(index): compute local uiState on state changes

* feat(index): expose getWidgetState

* test(index): indexes -> indices

* feat(index): remove listeners on Helper

* test(index): omit -> omitted

Co-Authored-By: François Chalifour <francoischalifour@users.noreply.github.com>

* feat(index): push empty indices in uiState
samouss added a commit that referenced this pull request Sep 17, 2019
* feat(types): create types for getWidgetState/getWidgetSearchParameters arguments

* feat(index): compute local uiState on state changes

* feat(index): expose getWidgetState

* test(index): indexes -> indices

* feat(index): remove listeners on Helper

* test(index): omit -> omitted

Co-Authored-By: François Chalifour <francoischalifour@users.noreply.github.com>

* feat(index): push empty indices in uiState
samouss added a commit that referenced this pull request Sep 17, 2019
* feat(types): create types for getWidgetState/getWidgetSearchParameters arguments

* feat(index): compute local uiState on state changes

* feat(index): expose getWidgetState

* test(index): indexes -> indices

* feat(index): remove listeners on Helper

* test(index): omit -> omitted

Co-Authored-By: François Chalifour <francoischalifour@users.noreply.github.com>

* feat(index): push empty indices in uiState
Haroenv pushed a commit that referenced this pull request Oct 23, 2019
* feat(types): create types for getWidgetState/getWidgetSearchParameters arguments

* feat(index): compute local uiState on state changes

* feat(index): expose getWidgetState

* test(index): indexes -> indices

* feat(index): remove listeners on Helper

* test(index): omit -> omitted

Co-Authored-By: François Chalifour <francoischalifour@users.noreply.github.com>

* feat(index): push empty indices in uiState
Haroenv added a commit that referenced this pull request Oct 23, 2019
* **configure:** merge with the previous parameters ([#4085](#4085)) ([a215d0c](a215d0c))
* **configure:** update lifecycle state ([#3994](#3994)) ([3d8d967](3d8d967))
* **connectInfiniteHits:** fix page state when adding or removing widgets ([#4104](#4104)) ([1077340](1077340))
* **connectInfiniteHits:** fix state when navigating or adding/removing widgets ([#4123](#4123)) ([9cbd24a](9cbd24a))
* **createURL:** support multi-index ([#4082](#4082)) ([179a6e5](179a6e5))
* **defer:** recover from error ([#3933](#3933)) ([f22b9e2](f22b9e2))
* **helper:** expose .lastResults to .helper ([#4170](#4170)) ([236eb7b](236eb7b))
* **history:** avoid empty query string ([#4130](#4130)) ([18fee7c](18fee7c))
* **hits:** update lifecycle state ([#3977](#3977)) ([6e55ba6](6e55ba6))
* **hitsPerPage:** avoid sync default value ([#4086](#4086)) ([3f8b958](3f8b958))
* **hitsPerPage:** update lifecycle state ([#3978](#3978)) ([d21d620](d21d620))
* **index:** ensure that we always use the index set by widgets ([#4125](#4125)) ([952dc70](952dc70)), closes [/github.com/algolia/algoliasearch-helper-js/blob/5a0352aa233c5ea932df6b054a16989c8d302404/src/algoliasearch.helper.js#L124](https://github.com//github.com/algolia/algoliasearch-helper-js/blob/5a0352aa233c5ea932df6b054a16989c8d302404/src/algoliasearch.helper.js/issues/L124)
* **index:** prevent render without results ([#3932](#3932)) ([1b9b5f4](1b9b5f4))
* **index:** subscribe to state change only after init for uiState ([#4003](#4003)) ([9490ca9](9490ca9))
* **index:** support custom UI params in UI state warning ([#4165](#4165)) ([80d32fc](80d32fc))
* **index:** warn for inconsistent UI state in development mode ([#4140](#4140)) ([7e277dc](7e277dc))
* **infiniteHits:** update lifecycle state ([#3983](#3983)) ([4b8bee5](4b8bee5))
* **instantsearch:** return instance in widgets methods ([#4143](#4143)) ([77ffb93](77ffb93))
* **InstantSearch:** cancel scheduled operations ([#3930](#3930)) ([3aafbad](3aafbad))
* **InstantSearch:** fix initialUIState when refinements are already present in the route ([#4103](#4103)) ([079db57](079db57))
* **InstantSearch:** remove useless walk/duplicate request ([#4127](#4127)) ([70163a8](70163a8))
* **menu:** apply & remove refinement ([#4027](#4027)) ([85de2cf](85de2cf))
* **menu:** prevent error on stale search ([#3934](#3934)) ([5f9e138](5f9e138))
* **numericMenu:** take array into account for empty state ([#4084](#4084)) ([2c05a01](2c05a01))
* **pagination:** update lifecycle state ([#3979](#3979)) ([2b08344](2b08344))
* **pagination:** update no refinement behavior ([#4124](#4124)) ([8d222ad](8d222ad))
* **range:** clear widget state on empty refinements ([#4157](#4157)) ([23cd112](23cd112))
* **ratingMenu:** update lifecycle state ([#3987](#3987)) ([ffadf64](ffadf64))
* **RefinementList:** remove root css class on sublists ([#4117](#4117)) ([ceddd42](ceddd42)), closes [/github.com/algolia/instantsearch.js/blob/v2/src/decorators/headerFooter.js#L22](https://github.com//github.com/algolia/instantsearch.js/blob/v2/src/decorators/headerFooter.js/issues/L22)
* **searchBox:** update lifecycle state ([#3981](#3981)) ([0ea4950](0ea4950))
* **sortBy:** ensure a return value for getWidgetSearchParameters ([#4126](#4126)) ([569d573](569d573))
* **sortBy:** read initial index name from parent index ([#4079](#4079)) ([fe23c55](fe23c55))
* display warnings only in development ([#4150](#4150)) ([44f69a0](44f69a0))
* remove useless types  ([#3958](#3958)) ([ddebf53](ddebf53))
* **stories:** hide Places ([#4152](#4152)) ([7ff843f](7ff843f))
* **toggleRefinement:** update lifecycle state ([#3993](#3993)) ([f1beff6](f1beff6))
* **voiceSearch:** update lifecycle state ([#3982](#3982)) ([798e3c1](798e3c1))
* **warnings:** remove v3 warnings ([#4134](#4134)) ([7eb6810](7eb6810))

* **autocomplete:** leverage scoped results ([#3975](#3975)) ([8f05968](8f05968))
* **autocomplete:** participate in routing ([#4029](#4029)) ([a9ca0c5](a9ca0c5))
* **autocomplete:** provide indexId ([#4142](#4142)) ([b641e23](b641e23))
* **clearRefinements:** support multiple indices ([#4036](#4036)) ([3611b11](3611b11))
* **connectAutocomplete:** add default value on getConfiguration ([#3836](#3836)) ([724b83f](724b83f))
* **connectAutocomplete:** clear the state on dispose ([#3815](#3815)) ([8ae87d8](8ae87d8))
* **connectHierarchicalMenu:** update getWidgetSearchParameters ([#4053](#4053)) ([c99f822](c99f822))
* **connectHits:** clear the state on dispose ([#3816](#3816)) ([c4de730](c4de730))
* **connectHits:** implement getWidgetSearchParameters ([#4001](#4001)) ([c77cf66](c77cf66))
* **connectHitsPerPage:** clear the state on dispose ([#3818](#3818)) ([d7a5c89](d7a5c89))
* **connectInfiniteHits:** add default value on getConfiguration ([#3837](#3837)) ([8c65249](8c65249))
* **connectInfiniteHits:** clear the state on dispose ([#3819](#3819)) ([60ce151](60ce151))
* **connectMenu:** update getWidgetSearchParameters ([#4054](#4054)) ([7d001e7](7d001e7))
* **connectNumericMenu:** update state lifecycle  ([#4013](#4013)) ([2620c90](2620c90))
* **connectPagination:** add default value on getConfiguration ([#3838](#3838)) ([aa4602c](aa4602c))
* **connectPagination:** clear the state on dispose ([#3821](#3821)) ([5b8ef49](5b8ef49))
* **connectPagination:** update getWidgetSearchParameters ([#4004](#4004)) ([eed7e77](eed7e77))
* **connectRange:** default `precision` to 0 ([#3953](#3953)) ([632e06b](632e06b))
* **connectRatingMenu:** update getWidgetSearchParameters  ([#4008](#4008)) ([d3c96bf](d3c96bf))
* **connectRefinementList:** update getWidgetSearchParameters  ([#4010](#4010)) ([ddc8fc4](ddc8fc4))
* **connectSearchBox:** clear the state on dispose ([#3822](#3822)) ([940522c](940522c))
* **connectSearchBox:** mount with a default query ([#3840](#3840)) ([c3a7d69](c3a7d69))
* **connectSearchBox:** update getWidgetSearchParameters ([#4002](#4002)) ([5c6fcd8](5c6fcd8))
* **connectVoiceSearch:** add default value on getConfiguration ([#3841](#3841)) ([fb70363](fb70363))
* **connectVoiceSearch:** clear the state on dispose ([#3823](#3823)) ([705b3e6](705b3e6))
* **connectVoiceSearch:** update getWidgetSearchParameters ([#4055](#4055)) ([b8c669f](b8c669f))
* **core:** deprecate addWidget & removeWidget ([#4131](#4131)) ([e5dafef](e5dafef))
* **currentRefinements:** support multiple indices ([#4012](#4012)) ([e997728](e997728))
* **defer:** implement cancellable callback ([#3916](#3916)) ([43a0bf8](43a0bf8))
* **federated:** keep a consistent state in the RefinementList life cycle ([#3976](#3976)) ([31d0fd6](31d0fd6))
* **hitsPerPage:** support new routing system ([#4038](#4038)) ([02502cb](02502cb)), closes [#4069](#4069)
* **index:** accept indexId ([#4070](#4070)) ([b74f8e3](b74f8e3))
* **index:** add mergeSearchParameters function ([#3917](#3917)) ([c0fe7bb](c0fe7bb))
* **index:** add widget ([dbbda0f](dbbda0f)), closes [#3892](#3892) [#3893](#3893) [#3914](#3914)
* **index:** compute local uiState ([#3997](#3997)) ([997c0f4](997c0f4))
* **index:** merge `ruleContexts` search parameter ([#3944](#3944)) ([e94752d](e94752d))
* **index:** provide scoped results to render hook ([#3964](#3964)) ([37c6aad](37c6aad))
* **index:** replicate searchFunction hack ([#4078](#4078)) ([1d2a816](1d2a816)), closes [/github.com/algolia/instantsearch.js/blob/509513c0feafaad522f6f18d87a441559f4aa050/src/lib/RoutingManager.ts#L113-L130](https://github.com//github.com/algolia/instantsearch.js/blob/509513c0feafaad522f6f18d87a441559f4aa050/src/lib/RoutingManager.ts/issues/L113-L130)
* **index:** reset page of child indexes ([#3962](#3962)) ([131b1ce](131b1ce))
* **index:** resolve parent SearchParameters ([#3937](#3937)) ([2611da5](2611da5))
* **index:** use uiState driven SearchParameters ([#4059](#4059)) ([b12bb9f](b12bb9f))
* **infiniteHits:** support new routing system ([#4040](#4040)) ([49315cf](49315cf))
* **instantsearch:** add onStateChange method ([#4080](#4080)) ([9f68da5](9f68da5))
* **InstantSearch:** switch to DerivedHelper only ([#3885](#3885)) ([d6fc317](d6fc317))
* **places:** add Places widget ([#4167](#4167)) ([1d754d1](1d754d1))
* drop support of searchParameters for initialUiState ([#4081](#4081)) ([571efeb](571efeb))
* **range:** support new routing system ([#4039](#4039)) ([8cba05a](8cba05a))
* **routing:** add a "single index" compatibility mode ([#4087](#4087)) ([842eb0f](842eb0f))
* **RoutingManager:** update state on route update ([#4100](#4100)) ([88f2615](88f2615))
* **toggleRefinement:** support new routing system ([#4037](#4037)) ([6a9d99f](6a9d99f))
* **types:** DerivedHelper ([#3887](#3887)) ([0f38b4a](0f38b4a))
* **types:** rename RenderOptions -> RendererOptions ([#3867](#3867)) ([05c6f72](05c6f72))
* **utils:** implement defer ([#3882](#3882)) ([8af470e](8af470e))
* **voice:** add additional query parameters ([#3738](#3738)) ([c555255](c555255))
* drop suppot for onHistoryChange ([#3941](#3941)) ([697f609](697f609))
* introduce initialUiState option ([#4074](#4074)) ([de00707](de00707))
* update UiState definition ([#4075](#4075)) ([9e7d3d8](9e7d3d8))
* **widgets:** add `$$type` to widgets definition ([#3960](#3960)) ([344d1b7](344d1b7))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants