-
Notifications
You must be signed in to change notification settings - Fork 331
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(core): introduce Reshape API #647
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit b6db429:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consistent with the other ones, but why does it have a readme if it's empty?
overall, clean implementation!
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions'; | ||
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches'; | ||
import { h, Fragment } from 'preact'; | ||
import { pipe } from 'ramda'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that it's not needed to have pipe builtin
debug: true, | ||
openOnFocus: true, | ||
plugins: [recentSearchesPlugin, querySuggestionsPlugin, productsPlugin], | ||
reshape({ sourcesBySourceId }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reasonable name!
placeholder: 'Search', | ||
debug: true, | ||
openOnFocus: true, | ||
plugins: [recentSearchesPlugin, querySuggestionsPlugin, productsPlugin], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is products a plugin and not a regular source? could indicate more "regular" usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this gives me the idea if longer term plugins and sources maybe could be merged into a single argument? plugins could have no source, and it would allow you to order before using reshape already
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is products a plugin and not a regular source? could indicate more "regular" usage?
I wanted to focus the example on the reshape API, and not pollute the file with a huge source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this gives me the idea if longer term plugins and sources maybe could be merged into a single argument? plugins could have no source, and it would allow you to order before using reshape already
You mean something like this?
autocomplete({
// ...
getSources() {
return [
recentSearchesPlugin,
querySuggestionsPlugin,
{
// custom source
}
]
}
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was more thinking of plugins: [somePlugin, { getSources() { customStuff }}
, maybe that way you don't really need the callback form (although that limits some use cases for conditional requests, in which case your suggestion fits better)
I was just wondering if we really need to distinguish between the two
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks amazing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it! Small suggestions but nothing blocking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job!
Nothing blocking, only a few remarks.
item: TItem; | ||
}) => TItem; | ||
|
||
export const uniqBy: AutocompleteReshapeFunction<UniqByPredicate<any>> = < |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we've pulled Ramda already in this example, I'd use it there instead of rolling our own uniqBy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of using ramda in the examples, I don't think it's so common, and might cause people to include it just because our example does so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides, it will not make it possible for them to copy/paste.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@francoischalifour You recommended that I go with Ramda's groupBy
in the Tags plugin example though :) Also, we do use Ramda in the example for pipe
. Why do you think this is okay for this specific function?
Anyway it's no biggie and not blocking. We can discuss that later.
getSource(params: { name: string; items: TItem[] }): Partial<TSource>; | ||
}; | ||
|
||
export const groupBy: AutocompleteReshapeFunction = < |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we've pulled Ramda already in this example, I'd use it there instead of rolling our own groupBy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #647 (comment).
This PR introduces the Reshape API to Autocomplete. (The reshape preset package will come later.)
Live playground
Summary
A web UI is not a one-to-one mapping with your database, and a search UI doesn't have to be a one-to-one mapping with your search engine. The Reshape API unlocks this new search representation in your UI.
The Reshape API allows to apply transformations to a group of sources:
limit
operation)uniqBy
operation)groupBy
operation)sort
operation)This API is a transformation that happens after the sources are resolved, as a last step before rendering them. It is an enabler to apply operations like Lodash/Ramda for Autocomplete experiences.
Preview
Example of reshape with a
groupBy
operation on the category:Usage
Detailed design
The Reshape is a post-process step that happens after sources have been resolved in
getSources()
. During thegetSources
step, not all sources are resolved yet because some can be static (like a static list of items), and some can be async (like a search to Algolia).During the Reshape phase, sources are static because they've been resolved. This allows simple items' manipulation.
(Combine is the old name of Reshape.)
Rolling out
reshape
option, which we can introduce in the next minor version.@algolia/autocomplete-preset-reshape
package that we'll expose yet. I'd like to try them user-land in a wide varieties of app before exposing them as APIs.reshape
param to the documentation, as well as write a guide to create custom reshape functions.Related