diff --git a/docs/api-architecture.mdx b/docs/api-architecture.mdx deleted file mode 100644 index 4578ae1c..00000000 --- a/docs/api-architecture.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -slug: /search-ui/api/architecture -title: Architecture -date: 2022-02-27 -tags: ["architecture"] ---- - -``` - | - @elastic/react-search-ui | @elastic/search-ui - | - | - SearchProvider <--------------- SearchDriver - | | | | - State / | | | | State / - Actions | | | | Actions - | | | | - Components | | | - | | | | - v v | v -------------------------------------+---------------------------- - | | | - v v v - Using Headless Usage Headless Usage outside - Components in React of React -``` - -The core is a separate, vanilla JS library which can be used for any JavaScript based implementation. - -The Headless Core implements the functionality behind a search experience, but without its own view. It provides the underlying "state" and "actions" associated with that view. For instance, the core provides a `setSearchTerm` action, which can be used to save a `searchTerm` property in the state. Calling `setSearchTerm` using the value of an `` will save the `searchTerm` to be used to build a query. - -All of the Components in this library use the Headless Core under the hood. For instance, Search UI provides a `SearchBox` Component for collecting input from a user. But you are not restricted to using just that Component. Since Search UI lets you work directly with "state" and "actions", you could use any type of input you want! As long as your input or Component calls the Headless Core's `setSearchTerm` action, it will "just work". This gives you maximum flexibility over your experience if you need more than the Components in Search UI have to offer. - -The `SearchProvider` is a React wrapper around the Headless Core, and makes state and actions available to Search UI -and in a React [Context](https://reactjs.org/docs/context.html), and also via a -[Render Prop](https://reactjs.org/docs/render-props.html). diff --git a/docs/api-connectors-app-search.mdx b/docs/api-connectors-app-search.mdx deleted file mode 100644 index 5175c641..00000000 --- a/docs/api-connectors-app-search.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -slug: /search-ui/api/connectors/app-search -title: App Search Connector -date: 2022-02-27 -tags: ["app search connector"] ---- - - - App Search connector for Search UI is deprecated and will no longer be - supported. Please migrate to{" "} - {" "} - for continued support. - - -This Connector is used to connect Search UI to Elastic's [App Search](https://www.elastic.co/cloud/app-search-service) API. - -## Usage - -```shell -npm install --save @elastic/search-ui-app-search-connector -``` - -```js -import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector"; - -const connector = new AppSearchAPIConnector({ - searchKey: "search-371auk61r2bwqtdzocdgutmg", - engineName: "search-ui-examples", - endpointBase: "http://127.0.0.1:3002" -}); -``` - -### Additional options - -Additional options will be passed through to the underlying -[APIclient](https://github.com/elastic/app-search-javascript). Any valid parameter of the client can be used. - -```js -const connector = new AppSearchAPIConnector({ - searchKey: "search-371auk61r2bwqtdzocdgutmg", - engineName: "search-ui-examples", - endpointBase: "http://127.0.0.1:3002", - cacheResponses: false -}); -``` - -## Options - -| Param | Description | -| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| searchKey | Required. String. Credential found in your App Search Dashboard | -| engineName | Required. String. Engine to query, found in your App Search Dashboard | -| endpointBase | Required. String. Endpoint path, found in your App Search Dashboard | -| cacheResponses | Optional. Boolean. Default is true. By default, connector will keep an in browser memory result cache of previous requests. | -| hostIdentifier | Optional. Useful when proxying the Swiftype API or developing against a local API server. | -| beforeSearchCall | Optional. A hook to amend query options before the request is sent to the API in a query on an "onSearch" event. | -| beforeAutocompleteResultsCall | Optional. A hook to amend query options before the request is sent to the API in a "results" query on an "onAutocomplete" event. | -| beforeAutocompleteSuggestionsCall | Optional. A hook to amend query options before the request is sent to the API in a "suggestions" query on an "onAutocomplete" event. | diff --git a/docs/api-connectors-elasticsearch.mdx b/docs/api-connectors-elasticsearch.mdx deleted file mode 100644 index 26862972..00000000 --- a/docs/api-connectors-elasticsearch.mdx +++ /dev/null @@ -1,311 +0,0 @@ ---- -slug: /search-ui/api/connectors/elasticsearch -title: Elasticsearch Connector -date: 2022-04-13 -tags: ["demo"] ---- - - - Elasticsearch connector for Search UI is currently in technical preview - status. It is not ready for production use. - - -Search UI provides a way to connect to Elasticsearch directly without needing Enterprise Search. This is useful for when you dont need the features of Enterprise Search, such as relevance tuning. - -The connector uses the same Search UI configuration that other connectors use. - -You must specify either the cloud id or on-premise host url for the Elasticsearch connector. - -```js -import ElasticsearchAPIConnector from "@elastic/search-ui-elasticsearch-connector"; - -const connector = new ElasticsearchAPIConnector({ - // Either specify the cloud id or host to connect to elasticsearch - cloud: { - id: "" // cloud id found under your cloud deployment overview page - }, - host: "http://localhost:9200", // host url for the Elasticsearch instance - index: "", // index name where the search documents are contained - apiKey: "", // Optional. apiKey used to authorize a connection to Elasticsearch instance. - // This key will be visible to everyone so ensure its setup with restricted privileges. - // See Authentication section for more details. - connectionOptions: { - // Optional connection options. - headers: { - "x-custom-header": "value" // Optional. Specify custom headers to send with the request - } - } -}); -``` - -| Param | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| cloud | Required if `host` not provided. Object type. The cloud id for the deployment within elastic cloud. | -| host | Required if `cloud` not provided. String type. The host url to the Elasticsearch instance | -| index | Required. String type. The search index name | -| apiKey | Optional. a credential used to access the Elasticsearch instance. See [Connection & Authentication](#connection-&-authentication) | -| connectionOptions | Optional. Object containing `headers` dictionary of header name to header value. | - -## Differences between App Search and Elasticsearch connector - -### Applying Filters to Range Facets - -Elasticsearch connector differs in the way filters can be applied to facets. Currently its not possible to apply an explicit range filter to range facets. Elasticsearch connector uses the name thats been given to the option to apply the filter. It uses this name to match the option and creates a the range filter query for the option. - -#### Example Facet Configuration - -``` -{ - visitors: { - type: "range", - ranges: [ - { from: 0, to: 10000, name: "0 - 10000" }, - { from: 10001, to: 100000, name: "10001 - 100000" }, - { from: 100001, to: 500000, name: "100001 - 500000" }, - { from: 500001, to: 1000000, name: "500001 - 1000000" }, - { from: 1000001, to: 5000000, name: "1000001 - 5000000" }, - { from: 5000001, to: 10000000, name: "5000001 - 10000000" }, - { from: 10000001, name: "10000001+" } - ] - } -} -``` - -#### How to apply the filter - -``` - setFilter("visitors", { - name: "10001 - 100000", // name of the option - from: 10001, // both from and to will be ignored - to: 100000 - }); -``` - -#### Applying a range to a field that isn't a facet - -If the field isn't a facet, you will be able to apply filters to the search using `value`, `numeric range` and `date range`, depending on the field type. - -``` - setFilter("precio", { - name: "precio", - from: rangePrices[0], - to: rangePrices[1], - }); -``` - -### 'None' Filter Type - -Currently the None filter type is not supported. If this is a feature thats needed, please mention it in this [issue](https://github.com/elastic/search-ui/issues/783). - -## Connection & Authentication - - - This connector will talk to the Elasticsearch instance directly from the - browser. We **strongly** suggest you take additional steps to keep your - Elasticsearch instance as secure as possible. - - -You have the following options available to you for securely exposing your Elasticsearch instance to the internet: - -### Proxy the \_search API call through your API - -This envolves building an API route that will proxy the Elasticsearch call through your API. During the proxy, you are able to: - -- Ability to add any additional authentication headers / keys as you proxy the request through the API and to Elasticsearch. -- Update the Elasticsearch query request to add any filters to filter restricted documents -- Application performance monitoring of functionality -- Your own user based authentication for your API -- Add a caching layer between the API and Elasticsearch - -The connector will perform a `_search` query and will derive the endpoint path with the host and index. With `http://localhost:9200` host and `search-ui-example` index, the endpoint path will be `http://localhost:9200/search-ui-example/_search`. The connector will make a POST call with the elasticsearch query in the body of the request. To proxy the request through your API, you need to implement a route and update the connector's settings to use the proxy route. - -### Use an Elasticsearch api-key - -You can restrict access to indices by using an API key. We recommend you create an apiKey that is restricted to the particular index and has read-only authorization. See [Kibana API keys guide](https://www.elastic.co/guide/en/kibana/main/api-keys.html). To use the API key, place it within the Elasticsearch connection configuration. - -## Autocomplete - -Search UI supports autocomplete functionality to suggest search terms that provide results. The autocomplete functionality is built on top of the Elasticsearch `suggest` and `bool prefix query` API. - -To take advantage of the feature, first update the configuration. - -Below is an example of what the `autocompleteQuery` may look like. - -```js -autocompleteQuery: { - // performs a prefix search on the query - results: { - resultsPerPage: 5, // number of results to display. Default is 5. - search_fields: { - // the fields to prefix search on - title_suggest: {} - }, - result_fields: { - // Add snippet highlighting within autocomplete suggestions - title: { snippet: { size: 100, fallback: true }}, - nps_link: { raw: {} } - } - }, - // performs a query to suggest for values that partially match the incomplete query - suggestions: { - types: { - // Limit query to only suggest based on "title" field - documents: { fields: ["title_completion"] } - }, - // Limit the number of suggestions returned from the server - size: 4 - } -} - -``` - -Above we are configuring both the `results` and `suggestions` sections of the autocomplete query. - -`results` will need a search field to perform a prefix search on the query. We advise using a `search_as_you_type` field to be used. -`suggestions` require a `completion` type field to perform a query to suggest for values that partially match the incomplete query. - -Below is an example of the mappings for the above example. `title_suggest` is a `search_as_you_type` field and `title_completion` is a `completion` type field. - -```json -{ - "mappings": { - "properties": { - "title_suggest": { - "type": "search_as_you_type" - }, - "title_completion": { - "type": "completion" - } - } - } -} -``` - -With a combination of this configuration + the component with autocomplete configuration, your users will be able to see suggestions as they type within the search box. - -## Node.js Integration - -The Elasticsearch API Connector builds the Elasticsearch query and performs the request directly to Elasticsearch from the browser. Depending on what you're building, you may want this logic to be done on the server and provide your clients a simplified API. - -First step is to implement two routes to handle `search` and `autocomplete` requests. In example below, we are using express.js framework to implement these http routes within node.js. - -```js -// index.js - -var express = require("express"); -var APIConnector = - require("@elastic/search-ui-elasticsearch-connector").default; -require("cross-fetch/polyfill"); - -var app = express(); - -app.use(express.json()); -app.use(express.urlencoded({ extended: false })); - -const connector = new APIConnector({ - host: "http://localhost:9200", // host url for the Elasticsearch instance - index: "search-ui-examples", // index name where the search documents are contained - apiKey: "apiKeyExample" // Optional. apiKey used to authorize a connection to Elasticsearch instance. -}); - -app.post("/search", async (req, res) => { - const { query, options } = req.body; - const response = await connector.onSearch(query, options); - res.json(response); -}); - -app.post("/autocomplete", async (req, res) => { - const { query, options } = req.body; - const response = await connector.onAutocomplete(query, options); - res.json(response); -}); - -var listener = app.listen(8080, function () { - console.log("Listening on port " + listener.address().port); -}); -``` - -Next, you can add a simple connector which passes the configuration and query from the client to the server. - -```js -class CustomConnector { - constructor(host) { - this.host = host; - } - - async onSearch(query, options) { - const response = await fetch(this.host + "/search", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - query, - options - }) - }); - return response.json(); - } - - async onAutocomplete(query, options) { - const response = await fetch(this.host + "/autocomplete", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - query, - options - }) - }); - return response.json(); - } -} - -const connector = new CustomConnector("https://my-api-host/"); - -const config = { - alwaysSearchOnInitialLoad: true, - apiConnector: connector - // ... typical search-ui configuration -}; -``` - -Thats it!. You should see the `CustomConnector` executing requests to the server, providing the search state and configuration in the body. The node.js server will use the Elasticsearch connector to perform a search to Elasticsearch and return the results back to the client. - -## Customise the Elasticsearch Request Body - -Elasticsearch connector allows you to customise the Elasticsearch request body before its performed on Elasticsearch. This is useful if you want to customise the query or options before the request is sent to Elasticsearch. - -This is an advanced option, the underlying query may change between versions and reading from / mutating the query is brittle, so please be aware to use this sparingly and let us know what you want to achieve through github issues. - -Example below is overriding the `query` section of the Elasticsearch request body. - -```js -const connector = new ElasticsearchAPIConnector( - { - host: "https://example-host.es.us-central1.gcp.cloud.es.io:9243", - index: "national-parks", - apiKey: "exampleApiKey" - }, - (requestBody, requestState, queryConfig) => { - console.log("postProcess requestBody Call", requestBody); // logging out the requestBody before sending to Elasticsearch - if (!requestState.searchTerm) return requestBody; - - // transforming the query before sending to Elasticsearch using the requestState and queryConfig - const searchFields = queryConfig.search_fields; - - requestBody.query = { - multi_match: { - query: requestState.searchTerm, - fields: Object.keys(searchFields).map((fieldName) => { - const weight = searchFields[fieldName].weight || 1; - return `${fieldName}^${weight}`; - }) - } - }; - - return requestBody; - } -); -``` diff --git a/docs/api-connectors-site-search.mdx b/docs/api-connectors-site-search.mdx deleted file mode 100644 index 20fbdf49..00000000 --- a/docs/api-connectors-site-search.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -slug: /search-ui/api/connectors/site-search -title: Site Search Connector -date: 2022-02-27 -tags: ["demo"] ---- - -This Connector is used to connect Search UI to Elastic's [Site Search](https://www.elastic.co/cloud/site-search-service) API. - -While Site Search supports multiple document types, Search UI will only -support a single document type, and it must be provided up front when -creating the connector. - -Note that Site Search does not support certain features of Search UI: - -- `disjunctiveFacets` or `disjunctiveFacetsAnalyticsTags` configuration options -- Only `value` facets are allowed, no `range` facet support. -- `sort` option is not supported on facets. -- `size` option is not supported on facets. -- Does not support multiple filters applied to a single field. -- Cannot apply more than 1 range filter on a single field. -- Analytics tags are not supported in `click`. -- `suggestions` are not supported in autocomplete, only `results` -- The `none` filter type is not supported. - -## Usage - -```shell -npm install --save @elastic/search-ui-site-search-connector -``` - -```js -import SiteSearchAPIConnector from "@elastic/search-ui-site-search-connector"; - -const connector = new SiteSearchAPIConnector({ - documentType: "national-parks", - engineKey: "Z41R5U3Hi4s5gp1aw7kA" -}); -``` - -| Param | Description | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| documentType | Required. String type. Document Type found in your Site Search Dashboard | -| engineKey | Required. String type. Credential found in your Site Search Dashboard | -| beforeSearchCall | Optional. A hook to amend query options before the request is sent to the API in a query on an "onSearch" event. | -| beforeAutocompleteResultsCall | Optional. A hook to amend query options before the request is sent to the API in a "results" query on an "onAutocomplete" event. | diff --git a/docs/api-connectors-workplace-search.mdx b/docs/api-connectors-workplace-search.mdx deleted file mode 100644 index 0c2fcca8..00000000 --- a/docs/api-connectors-workplace-search.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -slug: /search-ui/api/connectors/workplace-search -title: Workplace Search Connector -date: 2022-04-18 -tags: ["demo"] ---- - - - Workplace Search connector for Search UI is deprecated and will no longer be - supported. Please migrate to{" "} - {" "} - for continued support. - - -This Connector is used to connect Search UI to Elastic's [Workplace Search](https://www.elastic.co/workplace-search/) API. - -## Usage - -```shell -npm install --save @elastic/search-ui-workplace-search-connector -``` - -```js -import WorkplaceSearchAPIConnector from "@elastic/search-ui-workplace-search-connector"; - -const connector = new WorkplaceSearchAPIConnector({ - kibanaBase: "https://search-ui-sandbox.kb.us-central1.gcp.cloud.es.io:9243", - enterpriseSearchBase: - "https://search-ui-sandbox.ent.us-central1.gcp.cloud.es.io", - redirectUri: "http://localhost:3000", - clientId: "8e495e40fc4e6acf515e557e634de39d4f727f7f60a3afed24a99ce316607c1e" -}); -``` - -See the [usage example](https://github.com/elastic/search-ui/blob/main/examples/sandbox/src/pages/workplace-search/index.js) in our sandbox app. The example uses a private Elastic Cloud deployment. Make sure to update the configuration values to use with your own [Elastic Cloud](https://www.elastic.co/cloud/) deployment. - -## Authentication - -The Workplace Search API requires authentication. This connector uses OAuth authentication. You can read more about that [here](https://www.elastic.co/guide/en/workplace-search/current/building-custom-search-workplace-search.html) and [here](https://www.elastic.co/guide/en/workplace-search/current/workplace-search-search-oauth.html). - -Using this connector will populate two additional pieces of Application State: - -`isLoggedIn` (boolean) - This can be used to determine whether or not a user is authenticated. Requests using this connector will only work if a user is authenticatied. If this is false, consider showing a "Login" link using the `authorizeUrl` state. - -`authorizeUrl` (string) - This can be used to create a "Login" link for users to initiate OAuth authentication. - -`logout` - (function) - This action can be used to log out user out of the search experience. Under the hood it 1) deletes the saved token from LocalStorage and 2) logs user out of Enterprise Search and Kibana to prevent the ability to get a new access token. - -## Options - -| Param | Description | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| enterpriseSearchBase | Required. String. The publicly accessible url of the Enterprise Search. | -| kibanaBase | Required. String. The publicly accessible url for the Kibana deployment associated with the Enterprise Search deployment. Used for OAuth authentication. | -| redirectUri | Required. String. The publicly accessible url of this Search UI deployment, which Kibana will redirect back to after successful OAuth authentication. Must match a URI as configured in the OAuth Application. | -| clientId | Required. String. Client ID as generated when setting up the OAuth Application. | -| beforeSearchCall | Optional. A hook to amend query options before the request is sent to the API in a query on an "onSearch" event. | -| beforeAutocompleteResultsCall | Optional. A hook to amend query options before the request is sent to the API in a "results" query on an "onAutocomplete" event. | diff --git a/docs/api-core-actions.mdx b/docs/api-core-actions.mdx deleted file mode 100644 index 611723fd..00000000 --- a/docs/api-core-actions.mdx +++ /dev/null @@ -1,392 +0,0 @@ ---- -slug: /search-ui/api/core/actions -title: Actions -date: 2022-02-27 -tags: [""] ---- - -To update the state, you can use actions below. Actions are functions that update the Request State and performs an API request. - -```js -setSearchTerm("search term"); -``` - -To get access to the actions within your component, you must wrap your component with our context HOCs. - -```jsx -// Selects `searchTerm` and `setSearchTerm` for use in Component -withSearch(({ searchTerm, setSearchTerm }) => ({ - searchTerm, - setSearchTerm -}))(Component); -``` - -See for more information. - -There are certain cases where you may need to apply one or more actions at a time. Search UI intelligently -batches actions into a single API call. - -For example, if you need to apply two filters at once, it is perfectly acceptable to write the following code: - -```js -addFilter("states", "Alaska", "any"); -addFilter("world_heritage_site", "true"); -``` - -This will only result in a single API call. - -### addFilter - -```ts -addFilter( - name: string, - value: FilterValue, - type: FilterType = "all" -) -``` - -Add a filter in addition to current filters values. - -#### Examples - -``` -addFilter("states", "Alaska"); -addFilter("isPublished", true); -addFilter("rating", 1); - -addFilter("states", ["Alaska", "California"], "all"); -addFilter("states", ["Alaska", "California"], "any"); - -addFilter("published",{ - name: "published", - from: "2020-01-01", - to: "2020-12-31" -}); - -addFilter("rating",{ - name: "badRating", - from: 1, - to: 6 -}); - -``` - -#### Parameters - -| Parameters | description | -| ---------- | ------------------------------------------------------------------------------------------ | -| `name` | Required. Name of the field | -| `value` | Required. Filter Value. See `FilterValue` type. | -| `type` | Optional. Defaults to `all`. How the filter is applied. Can be one of `any`, `all`, `none` | - -### setFilter - -```js -setFilter( - name: string, - value: FilterValue, - type: FilterType = "all" -) -``` - -Set a filter value, replacing current filter values. - -#### Examples - -``` -setFilter("states", "Alaska"); -setFilter("isPublished", true); -setFilter("rating", 1); - -setFilter("states", ["Alaska", "California"], "all"); -setFilter("states", ["Alaska", "California"], "any"); - -setFilter("published",{ - name: "published", - from: "2020-01-01", - to: "2020-12-31" -}); - -setFilter("rating",{ - name: "badRating", - from: 1, - to: 6 -}); - -``` - -#### Parameters - -| Parameters | description | -| ---------- | ------------------------------------------------------------------------------------------ | -| `name` | Required. Name of the field | -| `value` | Required. Filter Value. See `FilterValue` type. | -| `type` | Optional. Defaults to `all`. How the filter is applied. Can be one of `any`, `all`, `none` | - -### removeFilter - -Removes filters or filter values. - -```js -removeFilter( - name: string, - value?: FilterValue, - type?: FilterType -) -``` - -#### Examples - -```js -removeFilter("states"); -removeFilter("states", ["Alaska", "California"]); - -removeFilter("published", { - name: "published", - from: "2020-01-01", - to: "2020-12-31" -}); - -removeFilter("rating", { - name: "badRating", - from: 1, - to: 6 -}); -``` - -#### Parameters - -| Parameters | description | -| ---------- | ----------------------------------------------------------------------------------------------------------- | -| `name` | Required. Name of the field | -| `value` | Optional. Filter Value. Will remove all filters under field if value not specified. See `FilterValue` type. | -| `type` | Optional. Defaults to `all`. How the filter is applied. Can be one of `any`, `all`, `none` | - -### reset - -Reset state to initial search state. - -```js -reset(); -``` - -### clearFilters - -Clear all filters. - -```js -clearFilters((except: string[] = [])); -``` - -#### Examples - -```js -clearFilters(); -clearFilters(["states"]); // field name -``` - -#### Parameters - -| Parameters | description | -| ---------- | --------------------------------------------------------------------------- | -| `except` | Optional. String array. Field names which you want to ignore being cleared. | - -### setCurrent - -Update the current page number. Used for paging. - -```js -setCurrent(current: number) -``` - -#### Examples - -```js -setCurrent(2); -``` - -#### Parameters - -| Parameters | description | -| ---------- | --------------------------------------- | -| `current` | Required. Number type. The page number. | - -### setResultsPerPage - -Update the number of results per page. Used for paging. - -```js -setResultsPerPage(resultsPerPage: number) -``` - -#### Examples - -```js -setResultsPerPage(20); -``` - -#### Parameters - -| Parameters | description | -| ---------------- | ------------------------------------------------------- | -| `resultsPerPage` | Required. Number type. Sets number of results per page. | - -### setSearchTerm - -```js -setSearchTerm( - searchTerm: string, - { - autocompleteMinimumCharacters = 0, - autocompleteResults = false, - autocompleteSuggestions = false, - shouldClearFilters = true, - refresh = true, - debounce = 0 - }: SetSearchTermOptions = {} -) -``` - -Update the search term. Also gives you the ability to control autocomplete options. - -#### Examples - -```js -setSearchTerm("train"); -``` - -#### Parameters - -| Parameters | description | -| ------------ | ------------------------------------------------------- | -| `searchTerm` | Required. String type. the new search term to query by | -| `options` | Optional. Object type. See `SetSearchTermOptions` type. | - -#### SetSearchTermOptions Parameters - -| Parameters | description | -| ------------------------------- | --------------------------------------------------------------------- | -| `autocompleteMinimumCharacters` | Optional. miniumum terms to start performing autocomplete suggestions | -| `autocompleteResults` | Optional. To perform autocomplete Results | -| `autocompleteSuggestions` | Optional. To perform autocomplete Suggestions | -| `shouldClearFilters` | Optional. To clear filters | -| `refresh` | Optional. To refresh results | -| `debounce` | Optional. | - -### setSort - -```js -setSort( - sort: SortOption[] | string, - sortDirection: SortDirection -) -``` - -Update the sort option. - -#### Parameters - -| Parameters | description | -| --------------- | ----------------------------------------- | -| `sort` | `SortOption` or String - field to sort on | -| `sortDirection` | String - "asc" or "desc" | - -### trackClickThrough - -```js -trackClickThrough( - documentId: string, - tags: string[] = [] -) -``` - -Report a clickthrough event, which is when a user clicks on a result link. - -#### Parameters - -| Parameters | description | -| ------------ | -------------------------------------------------------------------------------------- | -| `documentId` | String - The document ID associated with the result that was clicked | -| `tags` | Optional. Array[String] Optional tags which can be used to categorize this click event | - -### trackAutocompleteClickThrough - -```js -trackAutocompleteClickThrough( - documentId: string, - tags: string[] = [] -) -``` - -Report a clickthrough event, which is when a user clicks on an autocomplete suggestion. - -#### Parameters - -| Parameters | description | -| ------------ | -------------------------------------------------------------------------------------- | -| `documentId` | String - The document ID associated with the result that was clicked | -| `tags` | Optional. Array[String] Optional tags which can be used to categorize this click event | - -### trackAutocompleteSuggestionClickThrough - - - -```js -trackAutocompleteSuggestionClickThrough( - suggestion: string, - postion: number - tags: string[] = [] -) -``` - -Report a suggestion clickthrough event, which is when a user clicks on an autocomplete suggestion. - -#### Parameters - -| Parameters | description | -| ------------ | -------------------------------------------------------------------------------------- | -| `suggestion` | String - The suggestion that was clicked | -| `position` | Number - The position of the suggestion that was clicked | -| `tags` | Optional. Array[String] Optional tags which can be used to categorize this click event | - -### a11yNotify - -```js -a11yNotify( - messageFunc: string, - messageArgs?: unknown -) -``` - -Reads out a screen reader accessible notification. See `a11yNotificationMessages` under TODO LINK - -#### Parameters - -| Parameters | description | -| ------------- | -------------------------------------------------------------------- | -| `messageFunc` | String - object key to run as function | -| `messageArgs` | Object - Arguments to pass to form your screen reader message string | - -## Types - -### FilterValue & FilterType Types - -`FilterValue` can be either a value type or a range type. - -#### Types - -```ts -type FilterValue = FilterValueValue | FilterValueRange; - -type FieldValue = string | number | boolean | Array; - -type FilterValueValue = FieldValue; - -type FilterValueRange = { - from?: FieldValue; - name: string; - to?: FieldValue; -}; - -type FilterType = "any" | "all" | "none"; -``` diff --git a/docs/api-core-configuration.mdx b/docs/api-core-configuration.mdx deleted file mode 100644 index 0cbd988f..00000000 --- a/docs/api-core-configuration.mdx +++ /dev/null @@ -1,452 +0,0 @@ ---- -slug: /search-ui/api/core/configuration -title: Configuration -description: Search UI Configuration API -date: 2022-03-31 -tags: ["configuration"] ---- - -Search UI uses a configuration object to tailor search to your needs. It consists of three parts: - -- Search query -- Autocomplete query -- Event hooks - -See below for details on each part. - -See page for more information on how to use the configuration with the SearchProvider. - -## Search Query (QueryConfig) - -This is the configuration for the main search query. Some of these configuration options are not supported by some connectors. Each connector will document the options that are not supported. - -```js - -searchQuery: { - filters: [{ field: "world_heritage_site", values: ["true"] }], - facets: { - states: { type: "value", size: 30 }, - } - disjunctiveFacets: ["states"], // Array of field names to use for disjunctive searches - disjunctiveFacetsAnalyticsTags: ["Ignore"], - conditionalFacets: {}, - search_fields: { - title: {}, - description: {} - }, - result_fields: { - title: { - snippet: { - size: 100, - fallback: true - } - }, - nps_link: { - raw: {} - } - } -} - -``` - -### Filters (Global Filters) - -Using Query Config, it is possible to create "Global" filters. "Global filters" are filters that are added to every query. The user has no control over whether or not this filter is added or removed, it doesn't show up in the query string, and is completely transparent to the user. It is applied IN ADDITION to filters which the user applies. - -```json -filters: [ - // value filter example - { field: "world_heritage_site", values: ["true"] }, - // Range filter example - { - field: "acres", - values: [{ - from: 0, to: 1000, name: "Small" - }] - } -] -``` - -### Facets - -Tells Search UI to fetch facet data that can be used with Facet Components. - -```js - facets: { - // example of a value facet - states: { type: "value", size: 30 }, - - // example of a numeric range facet - acres: { - type: "range", - ranges: [ - { from: -1, name: "Any" }, - { from: 0, to: 1000, name: "Small" }, - { from: 1001, to: 100000, name: "Medium" }, - { from: 100001, name: "Large" }, - ], - }, - - // example of a date range facet - date_established: { - type: "range", - ranges: [ - { - from: "1950-10-05T14:48:00.000Z", - name: "Within the last 50 years", - }, - { - from: "1900-10-05T14:48:00.000Z", - to: "1950-10-05T14:48:00.000Z", - name: "50 - 100 years ago", - }, - { - to: "1920-10-05T14:48:00.000Z", - name: "More than 100 years ago", - }, - ], - - // example of a geo location range facet - location: { - // center location to base ranges off of - center: "37.7749, -122.4194", - type: "range", - unit: "mi", - ranges: [ - { from: 0, to: 100, name: "Nearby" }, - { from: 100, to: 500, name: "A longer drive" }, - { from: 500, name: "Perhaps fly?" }, - ], - }, - } - } -``` - -#### Disjunctive Faceting - -"Disjunctive" facets are facets that do not change when a selection is made. Meaning, all available options will remain as selectable options even after a selection is made. - -Configured in the searchQuery.disjunctiveFacets array. An array of field names. Every field listed here must have been configured in the facets field first. It denotes that a facet should be considered disjunctive. When returning counts for disjunctive facets, the counts will be returned as if no filter is applied on this field, even if one is applied. - -##### disjunctiveFacetsAnalyticsTags - -Used in conjunction with the disjunctiveFacets parameter. Adding disjunctiveFacets can cause additional API requests to be made to your API, which can create deceiving analytics. These queries will be tagged with "Facet-Only" by default. This field lets you specify a different tag for these. - -Example, use ignore as a tag on all disjunctive API calls: - -```js -disjunctiveFacetsAnalyticsTags: ["ignore"]; -``` - -#### Conditional Faceting - -See for more information. - -### search_fields - -Fields which should be searched with search term. - -```js -search_fields: { - title: { - weight: 10, - }, - description: {}, - tags: { - weight: 5, - } -} -``` - -Apply Weights to each search field. - -Engine level Weight settings will be applied is none are provided. - -Query time Weights take precedence over Engine level values. - -All fields specified within the search relevance section will be used for searching if not specified. - -### result_fields - -Select from two ways to render text field values: - -- **Raw**: An exact representation of the value within a field. And it is exact! It is not HTML escaped. -- **Snippet**: A snippet is an HTML escaped representation of the value within a field, where query matches are captured in `` tags. - -A raw field defaults to the full field with no character limit outside of max document size. A custom range must be at least 20 characters. - -A snippet field defaults to 100 characters. A custom range must be between 20-1000 characters. - -Only text fields provide these two options, as they are functions of the deep full-text search capabilities of App Search. - -#### Raw - -```js -result_fields: { - title: { - raw: {} - }, - description: { - raw: { - size: 50 - } - } -} -``` - -| field | description | -| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `size` | Number - Optional. Length of the return value. Only can be used on text fields. Must be at least 20; defaults to the entire text field. If given for a different field type other than text, it will be silently ignored. | - -#### Snippet (Highlighting) - -Requests a snippet of a text field. - -The query match will be wrapped in tags, for highlighting, if a match exists. - -Use escaped quotations to highlight only on exact, case insensitive matches. - -Matches are HTML escaped prior to inserting tags. Fallbacks are also HTML escaped. - -If requesting a snippet on a non-text field, the snippet field will be null. - -If there is no match for your query, the snippet field will be null. - -Snippets on an array value will return the first match or null. There is no fallback support. - -On synonyms: If a search finds a synonym for a query, the synonym will not be highlighted. - -For example, if "path" and "trail" are synonyms and a query is done for "path", the term "trail" will not be highlighted. - -```js -result_fields: { - title: { - snippet: { - size: 100, - fallback: true - } - }, - description: { - raw: { - size: 50 - } - } -} -``` - -| field | description | -| ---------- | ------------------------------------------------------------------------------- | -| `size` | Character length of the snippet returned. Must be at least 20; defaults to 100. | -| `fallback` | If true, fallback to the raw field if no match is found. | - -## Autocomplete Query - -This is the configuration that provide relevant query suggestions for incomplete queries. Some of these configuration options are not supported by some connectors. Each connector will document the options that are not supported. - -```js -autocompleteQuery: { - // performs a prefix search on the query - results: { - resultsPerPage: 5, // number of results to display. Default is 5. - result_fields: { - // Add snippet highlighting within autocomplete suggestions - title: { snippet: { size: 100, fallback: true }}, - nps_link: { raw: {} } - } - }, - // performs a query to suggest for values that partially match the incomplete query - suggestions: { - types: { - // Limit query to only suggest based on "title" field - documents: { fields: ["title"] } - }, - // Limit the number of suggestions returned from the server - size: 4 - } -} -``` - -### Results - -`results` will perform autocomplete on the query being typed. This will give back results that are relevant to the query before the user has typed any additional characters. - -```json -results: { - resultsPerPage: 5, - result_fields: { - title: { snippet: { size: 100, fallback: true }}, - nps_link: { raw: {} } - } -}, -``` - -| field | description | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `resultPerPage` | Optional. Number type. Number of results suggested | -| `result_fields` | Optional. To specify the fields for each result hit. Use same configuration as | - -### Suggestions - -Suggestions Query configuration for Search UI largely follows the same API as the [App Search Search API](https://www.elastic.co/guide/en/app-search/current/query-suggestion.html). - -```json -{ - "types": { - "documents": { - "fields": ["title", "states"] - } - }, - "size": 4 -} -``` - -| option | type | required? | source | -| ------- | ------- | --------- | -------------------------------------------------------------------------------------------- | -| `types` | Object | required | Object, keyed by "type" of query suggestion, with configuration for that type of suggestion. | -| `size` | Integer | optional | Number of suggestions to return. | - -### Result Suggestions - - - -A different index can be used for the suggestions. Some examples: - -- Popular queries index from analytics -- Brands index from product data -- Categories index from product data - -Below we are using the `popular_queries` index and performing a prefix match search on the `query.suggest` field. One thing to note, make sure the api-key has access to the index. - -See for more information. - -```js -autocompleteQuery: { - suggestions: { - popularQueries: { - search_fields: { - "query.suggest": {} // fields used to query - }, - result_fields: { - query: { // fields used for display - raw: {} - } - }, - index: "popular_queries", - queryType: "results" - } - } -} -``` - -## Event Hooks - -Search UI exposes a number of event hooks which need handlers to be implemented in order for Search UI -to function properly. - -The easiest way to provide handlers for these events is via an out-of-the-box "Connector", which -provides pre-built handlers, which can then be configured for your particular use case. - -While we do provide out-of-the-box Connectors, it is also possible to implement these handlers directly, -override Connector methods, or provide "middleware" to Connectors in order to further customize -how Search UI interacts with your services. - -#### Event Handlers - -| method | params | return | description | -| --------------------------- | ----------------------------------------------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `onResultClick` | `props` - Object | | This method logs a click-through event to your APIs analytics service. This is triggered when a user clicks on a result on a result page. | -| | - `query` - String | | The query used to generate the current results. | -| | - `documentId` - String | | The id of the result that a user clicked. | -| | - `requestId` - String | | A unique id that ties the click to a particular search request. | -| | - `tags` - Array[String] | | Tags used for analytics. | -| `onSearch` | `state` - [Request State](#request-state) | [Response State](#response-state) | | -| | `queryConfig` - [Query Config](#query-config) | | | -| `onAutocompleteResultClick` | `props` - Object | | This method logs a click-through event to your APIs analytics service. This is triggered when a user clicks on a result in an autocomplete dropdown | -| | - `query` - String | | The query used to generate the current results. | -| | - `documentId` - String | | The id of the result that a user clicked. | -| | - `requestId` - String | | A unique id that ties the click to a particular search request. | -| | - `tags` - Array[String] | | Tags used for analytics. | -| `onAutocomplete` | `state` - [Request State](#request-state) | [Response State](#response-state) | | -| | `queryConfig` - Object | | | -| | - `results` - [Query Config](#query-config) | | If this is set, results should be returned for autocomplete. | -| | - `suggestions` - [Suggestions Query Config](#suggestions-query-config) | | If this is set, query suggestions should be returned for autocomplete. | - -Explicitly providing a Handler will override the Handler provided by the Connector. - -```jsx - { - const queryForOtherService = transformSearchUIStateToQuery( - requestState, - queryConfig - ); - const otherServiceResponse = await callSomeOtherService( - queryForOtherService - ); - return transformOtherServiceResponseToSearchUIState(otherServiceResponse); - } - }} -/> -``` - -### Using middleware in Connector Handlers - -Handler implementations can also be used as middleware for Connectors by leveraging -the `next` function. - -```jsx - { - const updatedState = someStateTransformation(requestState); - return next(updatedState, queryConfig); - } - }} -/> -``` - -### Routing Options - -Search UI provides a number of options for how to customise how state is serialised onto the URL. Within the config there is a `routingOptions` object which can be used to override the serialisation and parsing of the url to state. - -Below is an example of how to use the `routingOptions` object to customise the url to be more SEO friendly. - -This will result in the url pattern being like `https://example.com/search/california,alaska?query=shoes` - -```js -const routingOptions = { - readUrl: () => { - return asPath; - }, - writeUrl: (url, { replaceUrl }) => { - const method = router[replaceUrl ? "replace" : "push"]; - method(url); - }, - stateToUrl: (state) => { - const statesFilter = state.filters.find( - (filter) => filter.field === "states" - ); - const states = statesFilter ? statesFilter.values.join(",") : "all"; - return `/search/${states}?query=${state.searchTerm}`; - }, - urlToState: (url) => { - const match = url.match(/\/search\/(\w+)\?query=(\w+)/); - if (!match) return {}; - return { - searchTerm: match[2], - filters: [{ field: "states", values: [match[1].split(",")], type: "any" }] - }; - } -}; - -const config = { - // search UI config - routingOptions: routingOptions -}; -``` diff --git a/docs/api-core-state.mdx b/docs/api-core-state.mdx deleted file mode 100644 index 1b026f9a..00000000 --- a/docs/api-core-state.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -slug: /search-ui/api/core/state -title: State -date: 2022-02-27 -tags: ["state"] ---- - -State can be divided up into a few different types. - -1. [Request State](#request-state) - State that is used - as parameters on Search API calls. -2. [Response State](#response-state) - State that represents a response from a Search API call. -3. [Application State](#application-state) - The general state. - -Request State and Response State will often have similar values. For instance, `searchTerm` and `resultSearchTerm`. -`searchTerm` is the current search term in the UI, and `resultSearchTerm` is the term associated with the current -`results`. This can be relevant in the UI, where you might not want the search term on the page to change until AFTER -a response is received, so you'd use the `resultSearchTerm` state. - -### Request State - -State that is used as parameters on Search API calls. - -Request state can be set by: - -- Using actions, like `setSearchTerm` -- The `initialState` option. -- The URL query string, if `trackUrlState` is enabled. - -| option | Description | -| ---------------- | ---------------------------------------- | -| `current` | Current page number | -| `filters` | Array of filters. See Filters section. | -| `resultsPerPage` | | -| `searchTerm` | Search terms to search for | -| `sort` | List of fields and directions to sort on | - -### Response State - -State that represents a response from a Search API call. - -It is not directly update-able. - -It is updated indirectly by invoking an action which results in a new API request. - -| field | description | -| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `autocompletedResults` | An array of results items fetched for an autocomplete dropdown. | -| `autocompletedResultsRequestId` | A unique ID for the current autocompleted search results. | -| `autocompletedSuggestions` | A keyed object of query suggestions. It's keyed by type since multiple types of query suggestions can be set here. | -| `autocompletedSuggestionsRequestId` | A unique ID for the current autocompleted suggestion results. | -| `facets` | Will be populated if `facets` configured in . | -| `rawResponse` | The response object received from the API | -| `requestId` | A unique ID for the current search results. | -| `results` | An array of result items. | -| `resultSearchTerm` | As opposed the the `searchTerm` state, which is tied to the current search parameter, this is tied to the searchTerm for the current results. There will be a period of time in between when a request is started and finishes where the two pieces of state will differ. | -| `totalResults` | Total number of results found for the current query. | - -### Application State - -Application state is the general application state. - -| field | description | -| ------------- | ------------------------------------------------------------------------------------------------------------------ | -| `error` | Error message, if an error was thrown. | -| `isLoading` | Whether or not a search is currently being performed. | -| `wasSearched` | Has any query been performed since this driver was created? Can be useful for displaying initial states in the UI. | diff --git a/docs/api-plugins-analytics-plugin.mdx b/docs/api-plugins-analytics-plugin.mdx deleted file mode 100644 index 1063c98d..00000000 --- a/docs/api-plugins-analytics-plugin.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -slug: /search-ui/api/core/plugins/analytics-plugin -title: Analytics Plugin -date: 2023-01-05 -tags: [""] ---- - -Use the Analytics Plugin to send analytics events to the Behavioral Analytics Product. Follow the instructions to set up the plugin. - -## Installation - -```bash -yarn add @elastic/search-ui-analytics-plugin -## OR -npm install @elastic/search-ui-analytics-plugin -``` - -## Basic Usage - -Add the Analytics Plugin to your Search UI configuration like so: - -```js -import AnalyticsPlugin from "@elastic/search-ui-analytics-plugin"; - -// search ui configuration -const config = { - apiConnector: connector, - searchQuery: { ... }, - plugins: [ AnalyticsPlugin() ] -} -``` - -By default, the Analytics Plugin will use the Behavioral Analytics client provided when using script tag integration. - -### Passing in a custom analytics client - -If you integrated Behavioral Analytics using the `@elastic/behavioral-analytics-javascript-tracker` NPM package, you can pass in a custom analytics client to the Analytics Plugin. - -```js - -import AnalyticsPlugin from "@elastic/search-ui-analytics-plugin"; -import { createTracker, getTracker } from "@elastic/behavioral-analytics-javascript-tracker"; - -createTracker({ - // the DSN can be found in the Behavioral Analytics Collections view page - dsn: "https://my-analytics-dsn.elastic.co" -}) - -// search ui configuration -const config = { - apiConnector: connector, - searchQuery: { ... }, - plugins: [ - AnalyticsPlugin({ - client: getTracker() - }) - ] -} -``` - -## Options - -The Analytics Plugin accepts the following parameters: - -| Option | Type | Description | Default | -| -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | -| `client` | `AnalyticsTracker` | The Behavioral Analytics client to use. Read more on [Behavioral Analytics Tracker repo](https://github.com/elastic/behavioral-analytics-tracker) | `window.elasticAnalytics` | diff --git a/docs/api-react-components-error-boundary.mdx b/docs/api-react-components-error-boundary.mdx deleted file mode 100644 index 4402a35b..00000000 --- a/docs/api-react-components-error-boundary.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -slug: /search-ui/api/react/components/error-boundary -title: ErrorBoundary -date: 2022-02-27 -tags: ["demo"] ---- - -Handle unexpected errors. - -### Example - -```jsx -import { ErrorBoundary } from "@elastic/react-search-ui"; - -... - - -
Some Content
-
-``` - -### Properties - -| Name | Description | -| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| children | Content to show if no error has occurred, will be replaced with error messaging if there was an error. | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| --------- | ------------------------------------------------------------------------------------------------------ | -| className | Passed through from main component. | -| children | Content to show if no error has occurred, will be replaced with error messaging if there was an error. | -| error | Type: `string`. The error message to show if an error occurred. | - -See [ErrorBoundary.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/ErrorBoundary.tsx) for an example. diff --git a/docs/api-react-components-facet.mdx b/docs/api-react-components-facet.mdx deleted file mode 100644 index 398c4d03..00000000 --- a/docs/api-react-components-facet.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -slug: /search-ui/api/react/components/facet -title: Facet -date: 2022-02-27 -tags: ["facet"] ---- - -Show a Facet filter for a particular field. - -Must configure the corresponding field in the `SearchProvider` object. - -### Example - -```jsx -import { Facet } from "@elastic/react-search-ui"; -import { MultiCheckboxFacet } from "@elastic/react-search-ui-views"; - -... - - - {() => ( - - )} - -``` - -### Example of an OR based Facet filter - -Certain configuration of the `Facet` Component will require a "disjunctive" facet to work -correctly. "Disjunctive" facets are facets that do not change when a selection is made. Meaning, all available options -will remain as selectable options even after a selection is made. - -```jsx -import { Facet } from "@elastic/react-search-ui"; -import { MultiCheckboxFacet } from "@elastic/react-search-ui-views"; - -... - - - {() => ( - - )} - -``` - -### Properties - -| Name | Description | -| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| field | Field name corresponding to this filter. This requires that the corresponding field has been configured in `facets` on the top level Provider. | -| filterType | The type of filter to apply with the selected values. I.e., should "all" of the values match, or just "any" of the values, or "none" of the values. Note: See the example above which describes using "disjunctive" facets in conjunction with filterType. | -| label | A static label to show in the facet filter. | -| show | The number of facet filter options to show before concatenating with a "Show more" link. | -| isFilterable | Whether or not to show Facet quick filter. | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| label | Type: `string`. Passed through from main component. | -| onMoreClick | Type: `() => void`. Used for a "Show more" link. Call this to show more options. | -| onRemove | Type: `(value: FieldValue) => void`. Call this when a user removes a facet filter selection. Pass the `value` from the corresponding selection from `options`. | -| onChange | Type: `(value: FieldValue) => void`. Call this when a user changes a facet filter selection. Pass the `value` from the corresponding selection from `options`. | -| onSelect | Type: `(value: FieldValue) => void`. Call this when a user adds a facet filter selection. Pass the `value` from the corresponding selection from `options`. | -| options | Type: `FacetValue[]`. The options to show available for selection for this facet. `selected` property will be true if this values is selected. | -| showMore | Type: `boolean`. Whether or not to show a "Show more" link. If there are no more options available to show, then this will be `false`. | -| values | Type: `FilterValue[]`. A list of all the selected values. This can also be deduced be inspected the `selected` properties of the `options`. | -| showSearch | Type: `boolean`. Whether or not the compopnent is `isFilterable`. This would indicates that a filter search box should be shown. | -| onSearch | Type: `(value: string) => void`. Call this to filter down the facet options shown. Used if there is a search box shown in relation to `showSearch`. | -| searchPlaceholder | Type: `string`. The placeholder fo show in the filter search box when `showSearch` is true. | - -See [MultiCheckboxFacet.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/MultiCheckboxFacet.tsx) for an example. - -When overriding Facet views, note that there are pre-built options that you can choose from, in addition to providing your own: - -```jsx -import { - BooleanFacet, - SingleSelectFacet, - SingleLinksFacet -} from "@elastic/react-search-ui-views"; - -// Default out-of-the-box view - - -// Choose an alternate out-of-the-box view - -``` diff --git a/docs/api-react-components-paging-info.mdx b/docs/api-react-components-paging-info.mdx deleted file mode 100644 index 3d783bf6..00000000 --- a/docs/api-react-components-paging-info.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -slug: /search-ui/api/react/components/paging-info -title: PagingInfo -date: 2022-02-27 -tags: ["demo"] ---- - -Paging details, like "1 - 20 of 100 results". - -### Example - -```jsx - -import { PagingInfo } from "@elastic/react-search-ui"; - -... - - -``` - -### Properties - -| Name | Description | -| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| ------------ | ------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| end | Type: `number`. The position of the last result shown on this page of reuslts. | -| searchTerm | Type: `string`. The current search term. | -| start | Type: `number`. The position of the first result shown on this page of reuslts. | -| totalResults | Type: `number`. The total number of results. | - -See [PagingInfo.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/PagingInfo.tsx) for an example. diff --git a/docs/api-react-components-paging.mdx b/docs/api-react-components-paging.mdx deleted file mode 100644 index ff761c10..00000000 --- a/docs/api-react-components-paging.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -slug: /search-ui/api/react/components/paging -title: Paging -date: 2022-02-27 -tags: ["Paging"] ---- - -Navigate through pagination. - -### Example - -```jsx - -import { Paging } from "@elastic/react-search-ui"; - -... - - -``` - -### Properties - -| Name | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| -------------- | ----------------------------------------------------------------------- | -| className | Passed through from main component. | -| current | Type: `number`. The current page | -| resultsPerPage | Type: `number`. The number of results that are shown per page. | -| onChange | function(value: number) - call this with the newly selected page number | -| totalPages | Type: `number`. The total number of pages. | - -See [Paging.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/Paging.tsx) for an example. diff --git a/docs/api-react-components-result.mdx b/docs/api-react-components-result.mdx deleted file mode 100644 index 56732861..00000000 --- a/docs/api-react-components-result.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -slug: /search-ui/api/react/components/result -title: Result -date: 2022-02-27 -tags: ["demo"] ---- - -## Result - -Displays a search result. - -### Example - -```jsx - -import { Result } from "@elastic/react-search-ui"; - -... - - - {({ results }) => { - return ( -
- {results.map(result => ( - - ))} -
- ); - }} -
-``` - -### Configuring search queries - -Certain aspects of search results can be configured in `SearchProvider`, using the `searchQuery` configuration, such as -term highlighting and search fields. See the guide -for more information. - -### Properties - -| Name | Description | -| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| titleField | Name of field to use as the title from each result. | -| shouldTrackClickThrough | Whether or not to track a clickthrough event when clicked. | -| clickThroughTags | Tags to send to analytics API when tracking clickthrough. | -| urlField | Name of field to use as the href from each result. | -| result | Type: `SearchResult`. An object representing the search result to render. | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -Example: - -```jsx -const CustomResultView = ({ - result, - onClickLink -}: { - result: SearchResult, - onClickLink: () => void -}) => ( -
  • -
    -

    - {/* Maintain onClickLink to correct track click throughs for analytics*/} - - {result.title.snippet} - -

    -
    -
    - {/* use 'raw' values of fields to access values without snippets */} -
    - -
    - {/* Use the 'snippet' property of fields with dangerouslySetInnerHtml to render snippets */} -
    -
    -
  • -); - -; -``` - -The following properties are available in the view: - -| Name | Description | -| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| result | Type: `SearchResult`. An object representing the search result to render. | -| onClickLink | function() - Call this when a link is clicked to trigger click tracking. Only triggered if `shouldTrackClickThrough` was set to true on the main component. | -| titleField | Passed through from main component. Not usually needed for custom views. | -| urlField | Passed through from main component. Not usually needed for custom views. | -| thumbnailField | Passed through from main component. Not usually needed for custom views. | - -See [Result.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/Result.tsx) for an example. diff --git a/docs/api-react-components-results-per-page.mdx b/docs/api-react-components-results-per-page.mdx deleted file mode 100644 index bbc90ac0..00000000 --- a/docs/api-react-components-results-per-page.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -slug: /search-ui/api/react/components/results-per-page -title: ResultsPerPage -date: 2022-02-27 -tags: ["demo"] ---- - -Shows a dropdown for selecting the number of results to show per page. - -Uses [20, 40, 60] as default options. You can use `options` prop to pass custom options. - -**Note:** When passing custom options make sure one of the option values match -the current `resultsPerPageProp` value, which is 20 by default. -To override `resultsPerPage` default value, use the property. - -### Example - -```jsx - -import { ResultsPerPage } from "@elastic/react-search-ui"; - -... - - -``` - -### Example using custom options - -```jsx - -import { SearchProvider, ResultsPerPage } from "@elastic/react-search-ui"; - - - - -``` - -### Properties - -| Name | Description | -| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| className | | -| options | Type: `number[]`. Dropdown options to select the number of results to show per page. | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View. | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| onChange | function(value: number) - Call this function with the select value from `options` after a user has made a selection. | -| options | Passed through from main component. | -| value | The currently selected option. | - -See [ResultsPerPage.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/ResultsPerPage.tsx) for an example. diff --git a/docs/api-react-components-results.mdx b/docs/api-react-components-results.mdx deleted file mode 100644 index 7037e506..00000000 --- a/docs/api-react-components-results.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -slug: /search-ui/api/react/components/results -title: Results -description: Search UI React Results Component -date: 2022-02-27 -tags: ["demo"] ---- - -Displays all search results. - -### Example - -```jsx - -import { Results } from "@elastic/react-search-ui"; - -... - - -``` - -### Configuring search queries - -Certain aspects of search results can be configured in `SearchProvider`, using the `searchQuery` configuration, such as -term highlighting and search fields. See the guide -for more information. - -### Properties - -| Name | Description | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| titleField | Name of field to use as the title from each result. | -| shouldTrackClickThrough | Whether or not to track a clickthrough event when clicked. | -| clickThroughTags | Tags to send to analytics API when tracking clickthrough. | -| urlField | Name of field to use as the href from each result. | -| thumbnailField | Name of field to use for thumbnail image. Should be a valid URL and at least 220px wide. | -| resultView | See | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -This component accepts two view props: `view` and `resultView`. The `resultView` allows you to customize the individual result items that are displayed. The `view` prop allows you to customize that wrapper around those results, which by default is simply a `ul` element. - -A separate guide specifically for customizing the Result component can be found , which can be used for providing a `resultView` prop. - -The following properties are available in the view: - -| Name | Description | -| --------- | ---------------------------------- | -| className | Passed through from main component | -| children | | - -See [Results.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/Results.tsx) for an example. diff --git a/docs/api-react-components-search-box.mdx b/docs/api-react-components-search-box.mdx deleted file mode 100644 index 9291fd20..00000000 --- a/docs/api-react-components-search-box.mdx +++ /dev/null @@ -1,415 +0,0 @@ ---- -slug: /search-ui/api/react/components/search-box -title: SearchBox -date: 2022-02-27 -tags: ["demo"] ---- - -Input element which accepts search terms and triggers a new search query. - -### Example - -```jsx - -import { SearchBox } from "@elastic/react-search-ui"; - -... - - -``` - -### Configuring search queries - -The input from `SearchBox` will be used to trigger a new search query. That query can be further customized -in the `SearchProvider` configuration, using the `searchQuery` property. See the guide for more information. - -### Example of passing custom props to text input element - -```jsx - -``` - -### Example using autocomplete results - -"Results" are search results. The default behavior for autocomplete -results is to link the user directly to a result when selected, which is why -a "titleField" and "urlField" are required for the default view. - -```jsx - -``` - -### Example using autocomplete suggestions - -"Suggestions" are different than "results". Suggestions are suggested queries. Unlike an autocomplete result, a -suggestion does not go straight to a result page when selected. It acts as a regular search query and -refreshes the result set. - -```jsx - -``` - -### Example using autocomplete suggestions and autocomplete results - -The default view will show both results and suggestions, divided into -sections. Section titles can be added to help distinguish between the two. - -```jsx - -``` - -### Example retrieving suggestions from another index - - - -A different index can be used for the suggestions. Some examples: - -- Popular queries index from analytics -- Brands index from product data -- Categories index from product data - -Below we are using the `popular_queries` index and performing a prefix match search on the `query.suggest` field. One thing to note, make sure the api-key has access to the index. - -````jsx - -#### Autocomplete Configuration - -```js -autocompleteQuery: { - suggestions: { - types: { - popularQueries: { - search_fields: { - "query.suggest": {} // fields used to query - }, - result_fields: { - query: { // fields used for display - raw: {} - } - }, - index: "popular_queries", - queryType: "results" - } - }, - size: 4 - } -} - -```` - -#### Component Configuration - -```jsx - -``` - -You also have the option to customise the `view` of the autocomplete to show more fields. - -### Configuring autocomplete queries - -Autocomplete queries can be customized in the `SearchProvider` configuration, using the `autocompleteQuery` property. -See the for more information. - -```jsx - - - -``` - -### Example using multiple types of autocomplete suggestions - -"Suggestions" can be generated via multiple methods. They can be derived from -common terms and phrases inside of documents, or be "popular" queries -generated from actual search queries made by users. This will differ -depending on the particular Search API you are using. - -**Note**: Elastic App Search currently only supports type "documents", and Elastic Site Search and Workplace Search -do not support suggestions. This is purely illustrative in case a Connector is used that -does support multiple types. - -```jsx - - - -``` - -### Example using autocomplete in a site header - -This is an example from a [Gatsby](https://www.gatsbyjs.org/) site, which overrides "submit" to navigate a user to the search -page for suggestions, and maintaining the default behavior when selecting a result. - -```jsx - { - navigate("/search?q=" + searchTerm); - }} - onSelectAutocomplete={(selection, {}, defaultOnSelectAutocomplete) => { - if (selection.suggestion) { - navigate("/search?q=" + selection.suggestion); - } else { - defaultOnSelectAutocomplete(selection); - } - }} -/> -``` - -### Properties - -| Name | Description | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| className | | -| shouldClearFilters | Should existing filters be cleared when a new search is performed? | -| inputProps | Props for underlying 'input' element. I.e., `{ placeholder: "Enter Text"}`. | -| searchAsYouType | Executes a new search query with every key stroke. You can fine tune the number of queries made by adjusting the `debounceLength` parameter. | -| debounceLength | When using `searchAsYouType`, it can be useful to "debounce" search requests to avoid creating an excessive number of requests. This controls the length to debounce / wait. | -| autocompleteResults | Configure and autocomplete search results. Boolean option is primarily available for implementing custom views. | -| autocompleteSuggestions | Configure and autocomplete query suggestions. Boolean option is primarily available for implementing custom views. Configuration may or may not be keyed by "Suggestion Type", as APIs for suggestions may support may than 1 type of suggestion. If it is not keyed by Suggestion Type, then the configuration will be applied to the first type available. | -| autocompleteMinimumCharacters | Minimum number of characters before autocompleting. | -| onSelectAutocomplete | Allows overriding behavior when selected, to avoid creating an entirely new view. In addition to the current `selection`, various helpers are passed as `options` to the second parameter. This third parameter is the default `onSelectAutocomplete`, which allows you to defer to the original behavior. | -| onSubmit | Allows overriding behavior when submitted. Receives the search term from the search box. | -| autocompleteView | Used to override only the autocomplete dropdown. See below. | -| inputView | Used to override only the input box. See below. | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -#### AutocompleteResultsOptions - -| Name | Description | -| ----------------------- | --------------------------------------------------------- | -| linkTarget | Used to open links in a new tab. | -| sectionTitle | Title to show in section within dropdown. | -| shouldTrackClickThrough | Only applies to Results, not Suggestions. | -| clickThroughTags | Tags to send to analytics API when tracking clickthrough. | -| titleField | Field within a Result to use as the "title". | -| urlField | Field within a Result to use for linking. | - -#### AutocompleteSuggestionsOptions - -| Name | Description | -| ------------ | ---------------------------------------- | -| sectionTitle | Title to show in section within dropdown | - -### View customization - -A complete guide to view customization can be found in the section. - -#### Full view customization - -You can customize the entire view using the `view` prop. This is useful to use an entirely different -autocomplete library (we use [downshift](https://github.com/downshift-js/downshift)). A SearchBox component at its simplest could look like the following: - -```jsx - ( -
    - onChange(e.target.value)} - /> - -
    - )} -/> -``` - -The full list of props available to this view are as follows: - -| Name | Description | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| inputView | Component to use for text input. When rendering, pass all props documented below in the section.
    Note that this can be challenging to do since some of the required props are generated by Downshift. It's generally advised not to try to use this property directly when creating a custom view. | -| isFocused | Type: `boolean`. Whether or not the input currently has focus. Will only work if you have correct spread `inputProps` over your input box. | -| onChange | Type: `(value: string) => void`. When a user changes the input of the search input box, call this with the new value. | -| onSubmit | Type: `(e: FormEvent) => void`. Handle a "submission" of the search box. Typically used directly on a `form` element surrounding your input box. | -| value | Type: `string`. The current user input to show in the input box. | -| inputProps | An object containing props that should be spread over the input box element. You'll need to do this in order to have the `isFocused` prop work. | -| autocompleteView | Component to use for Autocomplete. When rendering, pass all props documented below in the section.
    Note that this can be challenging to do since some of the required props are generated by Downshift. It's generally advised not to try to use this property directly when creating a custom view. | -| completeSuggestion | Type: `(searchQuery: string) => void`. | -| notifyAutocompleteSelected | Type: `(selection: any) => void`. | -| autocompletedSuggestionsCount | Type: `number`. | -| autocompleteSuggestions | Type: `boolean \| AutocompleteSuggestion`. | -| autocompletedSuggestions | Type: `AutocompletedSuggestions`. | -| autocompletedResults | Type: `AutocompletedResult[]`. | -| autocompleteResults | Type: `AutocompleteResult \| boolean`. | -| onSelectAutocomplete | Type: `(selectedItem: any) => void`. Call this with the selected item (whether it is a result or a suggestion) when an autocomplete selection is made in the autocomplete dropdown. | -| allAutocompletedItemsCount | Type: `number`. The number of items that would be shown in an autocomplete. If 0, no need to show the autocomplete. | -| useAutocomplete | Type: `boolean`. Whether or not to show an autocomplete dropdown. | - -See [SearchBox.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/SearchBox.tsx) for an example. - -#### Input view customization - -For making small customizations, like simply hiding the search button, or rearranging DOM structure, full customization is often overkill. - -You can also just customize the input section of the search box using the `inputView` prop. - -```jsx - ( - <> -
    - - {getAutocomplete()} -
    - - - )} -/> -``` - -Note that `getInputProps` and `getButtonProps` are -[prop getters](https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters). -They are meant return a props object to spread over their corresponding UI elements. This lets you arrange -elements however you'd like in the DOM. It also lets you pass additional properties. You should pass properties -through these functions, rather directly on elements, in order to not override base values. For instance, -adding a `className` through these functions will assure that the className is only appended, not overriding the base class values. - -`getAutocomplete` is used to determine where the autocomplete dropdown will be shown. - -The full list of props available to this view are as follows: - -| Name | Description | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| getAutocomplete | Type: `() => JSX.Element`. Call this method wherever you would like your autocomplete to appear. Typically, directly below your input box. | -| getButtonProps | Type: `() => Object`. Spread the return value of this function over your "Search" button, which submit your search. | -| getInputProps | Type: `() => JSX`. Spread the return value of this function over the `input` element you are using for your search box. | - -See [SearchInput.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/SearchInput.tsx) for an example. - -#### Autocomplete view customization - -In addition to the `inputView` customization, you can also make targed customization to the autocomplete view using the `autocompleteView` prop. - -For example: - -```jsx - ( -
    - {autocompletedResults.map((result, i) => ( -
    - Result {i}: {result.title.snippet} -
    - ))} -
    - )} -/> -``` - -The full list of props available to this view are as follows: - -| Name | Description | -| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| allAutocompletedItemsCount | Type: `number`. The number of items that would be shown in an autocomplete. If 0, no need to show the autocomplete. | -| autocompleteResults | Type: `boolean \| AutocompleteResult`. Configuration object passed through from main component. | -| autocompletedResults | Type: `AutocompletedResult[]`. The search results generated by an autocomplete query. | -| autocompletedSuggestions | Type: `AutocompletedSuggestions`. The suggestions generated by an autocomplete suggestions query. | -| autocompletedSuggestionsCount | Type: `number`. The total number of suggestions generated by an autocomplete suggestions query. | -| autocompleteSuggestions | Type: `boolean \| AutocompleteSuggestion`. Configuration object passed through from main component. | -| onSelectAutocomplete | Type: `(selectedItem: any) => void`. Call this with the selected item (whether it is a result or a suggestion) when an autocomplete selection is made in the autocomplete dropdown. | -| getItemProps | Type: `{ key: string, index: number, item: AutocompletedSuggestion }) => any`. A function that will generate props to spread over an individual item in the autocomplete list. | -| getMenuProps | Type: `({ className: string }) => any`. A function that will generate props to spread over the main autocomplete dropdown element. | - -See [Autocomplete.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/Autocomplete.tsx) for an example. diff --git a/docs/api-react-components-sorting.mdx b/docs/api-react-components-sorting.mdx deleted file mode 100644 index 61ff3438..00000000 --- a/docs/api-react-components-sorting.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -slug: /search-ui/api/react/components/sorting -title: Sorting -date: 2022-02-27 -tags: ["demo"] ---- - -Shows a dropdown for selecting the current Sort. - -### Example - -```jsx - -import { Sorting } from "@elastic/react-search-ui"; - -... - - -``` - -### Properties - -| Name | Description | -| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| className | | -| label | A static label to show in the Sorting Component. | -| sortOptions | | -| view | Used to override the default view for this Component. See below. | -| \* | Any other property passed will be passed through and available to use in a Custom View | - -### View customization - -A complete guide to view customization can be found in the section. - -The following properties are available in the view: - -| Name | Description | -| --------- | --------------------------------------------------------------------------------------- | -| className | Passed through from main component. | -| label | The label to display for this component. For example: "Sort by". | -| onChange | function(value: string) - Pass the value to this callback from the selected sort option | -| options | `{ value: string; label: string;}[]` - Options to display | -| value | string - The currently selected value | - -See [Sorting.tsx](https://github.com/elastic/search-ui/blob/main/packages/react-search-ui-views/src/Sorting.tsx) for an example. diff --git a/docs/api-react-search-provider.mdx b/docs/api-react-search-provider.mdx deleted file mode 100644 index 7b2a1f75..00000000 --- a/docs/api-react-search-provider.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -slug: /search-ui/api/react/search-provider -title: SearchProvider -date: 2022-03-31 -tags: ["core"] ---- - -The `SearchProvider` is a React wrapper around the Headless Core, and makes state and actions available to Search UI -and in a React [Context](https://reactjs.org/docs/context.html), and also via a -[Render Prop](https://reactjs.org/docs/render-props.html). - -It looks like this: - -```jsx -import { SearchProvider, SearchBox } from "@elastic/react-search-ui"; -import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector"; - -const connector = new AppSearchAPIConnector({ - searchKey: "search-371auk61r2bwqtdzocdgutmg", - engineName: "search-ui-examples", - endpointBase: "http://my-app-search-host:3002" -}); - -const configurationOptions = { - apiConnector: connector, - searchQuery: { ... }, - autocompleteQuery: { ... }, - hasA11yNotifications: true, - a11yNotificationMessages: { - searchResults: ({ start, end, totalResults, searchTerm }) => - `Searching for "${searchTerm}". Showing ${start} to ${end} results out of ${totalResults}.` - }, - alwaysSearchOnInitialLoad: true -}; - -const App = () => ( - -
    - -
    -
    -); -``` - -| option | type | description | -| --------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `apiConnector` | APIConnector | Instance of a Connector. See Connectors API section. | -| `onSearch` | function | You may provide individual handlers instead of a Connector, override individual Connector handlers, or act as middleware to Connector methods. See [Handlers](#handlers) for more information. | -| `onAutocomplete` | function | You may provide individual handlers instead of a Connector, override individual Connector handlers, or act as middleware to Connector methods. See [Handlers](#handlers) for more information. | -| `onResultClick` | function | You may provide individual handlers instead of a Connector, override individual Connector handlers, or act as middleware to Connector methods. See [Handlers](#handlers) for more information. | -| `onAutocompleteResultClick` | function | You may provide individual handlers instead of a Connector, override individual Connector handlers, or act as middleware to Connector methods. See [Handlers](#handlers) for more information. | -| `autocompleteQuery` | | Configuration options for the autocomplete query. | -| `debug` | Boolean | Trace log actions and state changes. Default is false. | -| `initialState` | Object | Set inital state of Search UI. See [Initial State](#initial-state) for more information. | -| `searchQuery` | | Configuration options for the main search query. | -| `trackUrlState` | Boolean | By default, [Request State](#request-state) will be synced with the browser url. To turn this off, pass `false`. | -| `urlPushDebounceLength` | Integer | The amount of time in milliseconds to debounce/delay updating the browser url after the UI update. This, for example, prevents excessive history entries while a user is still typing in a live search box. Default is 500. | -| `hasA11yNotifications` | Boolean | Search UI will create a visually hidden live region to announce search results & other actions to screen reader users. This accessibility feature will be turned on by default in our 2.0 release. Default is false. | -| `a11yNotificationMessages` | Object | You can override our default screen reader [messages](packages/search-ui/src/A11yNotifications.js#L49) (e.g. for localization), or create your own custom notification, by passing in your own key and message function(s). | -| `alwaysSearchOnInitialLoad` | Boolean | If true, Search UI will always do an initial search, even when no inital Request State is set. | - -### Context - -The "Context" is a flattened object containing, as keys, all and . - -We refer to it as "Context" because it is implemented with a [React Context](https://reactjs.org/docs/context.html). - -ex. - -```js -{ - resultsPerPage: 10, // Request State - setResultsPerPage: () => {}, // Action - current: 1, // Request State - setCurrent: () => {}, // Action - error: '', // Response State - isLoading: false, // Response State - totalResults: 1000, // Response State - ... -} -``` - -### Initial State - -This is useful for defaulting a search term, sort, etc. - -Example - -```js - initialState: { searchTerm: "test", resultsPerPage: 40 } -``` - -See for more properties that can be set in initial state. diff --git a/docs/api-react-with-search.mdx b/docs/api-react-with-search.mdx deleted file mode 100644 index bffea5e6..00000000 --- a/docs/api-react-with-search.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -slug: /search-ui/api/react/with-search -title: WithSearch & withSearch -date: 2022-03-31 -tags: ["component hocs"] ---- - -If you wish to use Search UI and build your own custom component, you will need to use our HOCs to use Search UI's core state and actions. - -There are two HOCs for accessing Search UI's state & actions, `withSearch` and -`WithSearch`. They use the [HOC](https://reactjs.org/docs/higher-order-components.html) and -[Render Props](https://reactjs.org/docs/render-props.html) patterns, respectively. The two methods -are similar, and choosing between the two is mostly personal preference. - -Both methods expose a `mapContextToProps` function which allows you to pick which state and actions -from context you need to work with. - -### mapContextToProps - -`mapContextToProps` allows you to pick which state and actions -from Context you need to work with. `withSearch` and `WithSearch` both use [React.PureComponent](https://reactjs.org/docs/react-api.html#reactpurecomponent), -and will only re-render when the picked state has changed. - -| name | type | description | -| ------- | ------ | ------------------- | -| context | Object | The current Context | -| props | Object | The current props | - -ex.: - -```jsx -import { withSearch } from "@elastic/react-search-ui"; - -const Component = ({ searchTerm, setSearchTerm }) => { - return ( -
    { - - }} - - ) -} - -// Selects `searchTerm` and `setSearchTerm` for use in Component -withSearch(({ searchTerm, setSearchTerm }) => ({ - searchTerm, - setSearchTerm -}))(Component); - -// Uses current `props` to conditionally modify context -withSearch(({ searchTerm }, { someProp }) => ({ - searchTerm: someProp ? "" : searchTerm -}))(Component); -``` - -### withSearch - -This is the [HOC](https://reactjs.org/docs/higher-order-components.html) approach to working with the -core. - -This is typically used for creating your own Components. - -See [Build Your Own Component](#build-your-own-component). - -### WithSearch - -This is the [Render Props](https://reactjs.org/docs/render-props.html) approach to working with the core. - -One use case for that would be to render a "loading" indicator any time the application is fetching data. - -For example: - -```jsx -import { WithSearch } from "@elastic/react-search-ui"; - - - ({ isLoading })}> - {({ isLoading }) => ( -
    - {isLoading &&
    I'm loading now
    } - {!isLoading && ( - } - bodyContent={} - /> - )} -
    - )} -
    -
    ; -``` diff --git a/docs/guides-adding-search-bar-to-header.mdx b/docs/guides-adding-search-bar-to-header.mdx deleted file mode 100644 index ecc6e323..00000000 --- a/docs/guides-adding-search-bar-to-header.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -slug: /search-ui/guides/adding-search-bar-to-header -title: Adding search bar to header -date: 2022-05-11 -tags: ["search-bar-in-header"] ---- - -It's a common pattern to have a search bar in the header of your website. -Submitting a query in this search bar usually redirects user to a separate search results page. - -To implement this with Search UI use the `` component and add `onSubmit` prop that redirects user to the search page: - -```js - { - window.location.href = `${PATH_TO_YOUR_SEARCH_PAGE}?q=${searchTerm}`; - }} -/> -``` - -Once the redirect happens, Search UI will pick up the query from the URL and display the results. - -Check out the example implementation below. - - - -Related documentation: - -- diff --git a/docs/guides-analyzing-performance.mdx b/docs/guides-analyzing-performance.mdx deleted file mode 100644 index 607d216d..00000000 --- a/docs/guides-analyzing-performance.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -slug: /search-ui/guides/analyzing-performance -title: Analyzing performance -date: 2022-06-17 -tags: - [ - "performance", - "APM", - "Application Performance Monitoring", - "RUM", - "Real user monitoring" - ] ---- - -Search UI allows you to analyze the performance and track errors on your search page by using -[Elastic Real User Monitoring](https://www.elastic.co/observability/real-user-monitoring) (RUM). - -![RUM dashboard](images/guides-analyzing-performance/dashboard.png) - -APM RUM captures the following information: - -- Page load metrics -- Load time of Static Assets (JS, CSS, images, fonts, etc.) -- API requests (XMLHttpRequest and Fetch) -- Single page application navigations -- User interactions (click events that trigger network activity) -- User-centric metrics (Long tasks, FCP, LCP, FID, etc.) -- Page information (URLs visited and referrer) -- Network connection information -- JavaScript errors -- Distributed tracing -- Breakdown metrics - -## Setup - - - This guide assumes that you're using Elastic Cloud and want to analyze a React - application. If your setup is different or you get stuck on any step, please - refer to the main [APM RUM - documentation](https://www.elastic.co/guide/en/apm/agent/rum-js/current/index.html). - - -The setup process consists of three steps: - -- Enabling Integrations Server -- Checking server status -- Adding APM RUM to your application - -### Enabling Integrations Server - -1. Open Elastic Cloud https://cloud.elastic.co -1. Find the deployment you want to add APM RUM to. -1. Click Edit deployment (⚙ icon). -1. On the deployment page click Edit in the left menu. -1. Find the Integrations Server section. - - If you already have Integrations server enabled, go to the next step. - - If don't — click "Add capacity" and choose the size of the server. - -![Integrations Server](images/guides-analyzing-performance/integrations-server.png) - -### Checking server status - -1. Go to the main Kibana page of your deployment. -1. Click Observability. -1. On the Observability overview page, find and click the button "Install RUM Agent". -1. In the tab "Elastic APM in Fleet" find "Check APM Server status" button and click it. You should see a confirmation that APM Server is working. - -![Server status](images/guides-analyzing-performance/server-status.png) - -### Adding APM RUM to your application - -1. On the same page scroll down and find "RUM (JS)" tab and click it. -1. Copy the code snippet and paste it into your application. Put it before the react `.render()` call, so APM RUM would already be initialized when React starts rendering the application. -1. Update the `serviceName` to the name of your application. -1. Replace the value of `environment` field to `process.env.NODE_ENV` to separate analytics from development and production environments. -1. Add the APM RUM dependency to your application: `npm install @elastic/apm-rum`. -1. Check that the events are sent by opening your browser dev tools and looking at the network tab. You should see the events request being sent after each search request. - -![Server status](images/guides-analyzing-performance/events-request.png) - -If you're using Search UI in a React application, it's recommended to also use the React integraton of APM RUM for more detailed analysis. Follow this guide for setting it up: https://www.elastic.co/guide/en/apm/agent/rum-js/current/react-integration.html - -If you feel stuck, check out this PR as an example of adding APM RUM to a React application: https://github.com/elastic/search-ui/pull/764/files - ---- - -That's it! Once the above steps are done, open the search page, do a couple searches to generate analytics events and head to Observability -> Dashboard to see your analytics data. diff --git a/docs/guides-building-a-custom-connector.mdx b/docs/guides-building-a-custom-connector.mdx deleted file mode 100644 index 906052bd..00000000 --- a/docs/guides-building-a-custom-connector.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -slug: /search-ui/guides/building-a-custom-connector -title: Building a custom connector -date: 2022-02-27 -tags: ["custom connector"] ---- - -This guide helps you build a custom connector so you can use Search UI with your own API. - -A connector is a class that implements the following methods: - -- `onSearch` -- `onAutocomplete` -- `onResultClick` -- `onAutocompleteResultClick` - -### Connector Example - -Below is an example of a custom connector. Example is given in typescript as the types may be helpful to you. - -See , and for more information. - -````typescript - -```ts -import type { APIConnector } from "@elastic/search-ui"; - -class MyAPIConnector implements APIConnector { - async onSearch( - state: RequestState, - queryConfig: QueryConfig - ): Promise { - const { searchTerm, current, filters, sort } = state; - // perform a request to your API with the request state - const response = await fetch("https://api.my-host/search", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - searchTerm, - current, - filters, - sort - }) - }); - // response will need to be in the shape of ResponseState. - // Alternatively you could transform the response here - return response.json(); - } - - async onAutocomplete( - state: RequestState, - queryConfig: AutocompleteQueryConfig - ): Promise { - const response = await fetch( - "https://api.my-host/autocomplete?query" + state.searchTerm, - { - headers: { - "Content-Type": "application/json" - } - } - ); - // response will need to be in the shape of AutocompleteResponseState. - // Alternatively you could transform the response here - return response.json(); - } - - onResultClick(params): void { - console.log( - "perform a call to the API to highlight a result has been clicked" - ); - } - - onAutocompleteResultClick(params): void { - console.log( - "perform a call to the API to highlight an autocomplete result has been clicked" - ); - } -} -```` - -### Integration - -Once you have built your connector, you can simply use it within Search UI. - -```js - - const connector = new MyAPIConnector(); - - const config = { - apiConnector: connector, - searchQuery: { ... }, - autocompleteQuery: { ... } - }; - - const App = () => ( - -
    - -
    -
    - ); - -``` diff --git a/docs/guides-changing-component-behavior.mdx b/docs/guides-changing-component-behavior.mdx deleted file mode 100644 index c81d012b..00000000 --- a/docs/guides-changing-component-behavior.mdx +++ /dev/null @@ -1,84 +0,0 @@ ---- -slug: /search-ui/guides/changing-component-behavior -title: Changing component behavior -date: 2022-02-27 -tags: ["changing component behavior"] ---- - -We have two primary recommendations for customizing Component behavior: - -1. Override state and action props before they are passed to your Component, using the `mapContextToProps` param. This - will override the default `mapContextToProps` for the component. -2. Override props before they are passed to your Component's view. - -### Override mapContextToProps - -Every Component supports a `mapContextToProps` prop, which allows you to modify state and actions -before they are received by the Component. - -**NOTE** This MUST be an immutable function. If you directly update the props or context, you will have major issues in your application. - -A practical example might be putting a custom sort on your facet data. - -This example orders a list of states by name: - -```jsx - { - if (!context.facets.states) return context; - return { - ...context, - facets: { - ...(context.facets || {}), - states: context.facets.states.map((s) => ({ - ...s, - data: s.data.sort((a, b) => { - if (a.value > b.value) return 1; - if (a.value < b.value) return -1; - return 0; - }) - })) - } - }; - }} - field="states" - label="States" - show={10} -/> -``` - -### Overriding view props - -An example of this is modifying the `onChange` handler of the `Paging` Component -view. Hypothetically, you may need to know every time a user -pages past page 1, indicating that they are not finding what they need on the first page -of search results. - -```jsx -import { Paging } from "@elastic/react-search-ui"; -import { Paging as PagingView } from "@elastic/react-search-ui-views"; - -function reportChange(value) { - // Some logic to report the change -} - - - PagingView({ - ...props, - onChange: (value) => { - reportChange(value); - return props.onChange(value); - } - }) - } -/>; -``` - -In this example, we did the following: - -1. Looked up what the default view is for our Component in the components guide. -2. Imported that view as `PagingView`. -3. Passed an explicit `view` to our `Paging` Component, overriding - the `onChange` prop with our own implementation, and ultimately rendering - `PagingView` with the updated props. diff --git a/docs/guides-conditional-facets.mdx b/docs/guides-conditional-facets.mdx deleted file mode 100644 index c75c1d19..00000000 --- a/docs/guides-conditional-facets.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -slug: /search-ui/guides/conditional-facets -title: Conditional Facets -date: 2022-05-16 -tags: ["conditional facets"] ---- - -Search UI has the ability to conditionally show facets based on the filters selected. This is useful for showing facets that are only relevant to certain filters. - -To use, add a `conditionalFacets` property to the configuration object. This property is a map of facet field names and a function to determine whether or not the facet should be shown. - -``` -{ - conditionalFacets: { - 'category': ({ filters }) => { - return filters.some(filter => filter.field === 'category' && filter.value === 'books'); - } - } -} -``` - -### Examples - -#### Filter Not Selected Example - -Returns true if the filter is not selected. - -Example below is do not show the category facet if a category filter has been applied. - -```javascript - function FilterNotSelected(fieldName: string, value?: string) { - return ({ filters }) => { - return !filters.some( - (f) => f.field === fieldName && (!value || f.values.includes(value)) - ); - }; - } - -// configuration - - conditionalFacets: { - 'category': FilterNotSelected('category') - } -``` - -Can also be scoped to a particular value of a filter. - -```javascript - conditionalFacets: { - 'category': FilterNotSelected('category', 'books') - } -``` - -#### Filter Is Selected - -Returns true if the filter is selected. - -Example below is show the shoe size facet if the shoes category filter has been applied. - -```javascript - -function FilterIsSelected(fieldName: string, value?: string) { - return ({ filters }) => { - return filters.some( - (f) => f.field === fieldName && (!value || f.values.includes(value)) - ); - }; -} - - conditionalFacets: { - 'shoe_size': FilterIsSelected('category', 'Shoes') - } -``` diff --git a/docs/guides-creating-your-own-components.mdx b/docs/guides-creating-your-own-components.mdx deleted file mode 100644 index 16349f55..00000000 --- a/docs/guides-creating-your-own-components.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -slug: /search-ui/guides/creating-your-own-components -title: Creating Components -description: Build your own components for Search UI -date: 2022-02-27 -tags: ["demo"] ---- - -We provide a variety of Components out of the box. However, there might be cases where we do not have the Component you need. - -In these cases, we recommend you use the low-level Search UI API to create these components yourself. - -## Example: Creating a component for clearing all filters - -For a live example of this, [check out this project on CodeSandbox](https://codesandbox.io/s/search-ui-customize-html-and-styles-demo-30v93e). - -To create your own component: - -1. Create a component. -2. Import the `withSearch` higher order component in order to access Search UI's actions and state. -3. Choose the actions and state you'll need for this component in the first parameter to `withSearch`. In the example below, they are using the `filters` state and the `clearFilters` action. The full list of state and actions is avialable in the API documentation. -4. Pass your component as the second parameter with `withSearch`, which will in turn pass the selected actions and state as props to your component. -5. Use the state and actions from props in your component. - -```jsx -import { withSearch } from "@elastic/react-search-ui"; - -function ClearFilters({ filters, clearFilters }) { - return ( -
    - -
    - ); -} - -export default withSearch(({ filters, clearFilters }) => ({ - filters, - clearFilters -}))(ClearFilters); -``` diff --git a/docs/guides-customizing-styles-and-html.mdx b/docs/guides-customizing-styles-and-html.mdx deleted file mode 100644 index 59306842..00000000 --- a/docs/guides-customizing-styles-and-html.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -slug: /search-ui/guides/customizing-styles-and-html -title: Customizing Styles and HTML -date: 2022-02-27 -tags: ["demo"] ---- - -In this guide we'll customize some styles of the Search UI, modify the default HTML of one of the Search UI components, and also create a completely new Result component. - -Check out the live example below to see all the code in action. - - - -## Customizing styles - -We provide a default stylesheet to get your project started quickly. - -```jsx -import "@elastic/react-search-ui-views/lib/styles/styles.css"; -``` - -You could choose to add your own stylesheet to override or augment these styles: - -```jsx -import "@elastic/react-search-ui-views/lib/styles/styles.css"; -import "your-custom-styles.css"; -``` - -You could also choose to replace these styles completely with your own stylesheet: - -```jsx -import "your-custom-styles.css"; -``` - -When target styles to override, we generally advise that you rely only on styles that are prefixed with `.sui`. We try to keep these compatible for version upgrades so that we don't break your custom styles. However, we do recommend that you test your styles thoroughly when upgrading versions, even within minors. - -Here is an example of a simple stylesheet that overrides much of the blue in the base styles with red to create a simple red theme: - -```css -.sui-search-box__submit { - background: none; - background-color: red; -} - -.sui-layout-sidebar-toggle { - color: red; - border: 1px solid red; -} - -.sui-result__title, -.sui-result__title-link { - color: red; -} - -.sui-facet-view-more { - color: red; -} -``` - -## Customizing html - -All components in this library can be customized by providing a `view` prop. - -The view prop can be used to customize a component's look and feel while still maintaining the component's logic. - -This follows the [React Render Props](https://reactjs.org/docs/render-props.html) pattern. The `view` prop is a function. The various -logic and values your view needs are passed through as parameters to the `view` function you provide. - -Every component will have a different function signature for its view. - -Here is an example of a custom view being provided for the `PagingInfo` component: - -```jsx - ( -
    - - {start} - {end} - -
    - )} -/> -``` - -You'll note that the `view` function here has four parameters that are available to use: - -2. `searchTerm` - The search term used for this query. -3. `start` - The number of the first result shown. -4. `end` - The number of the last result shown. -5. `totalResults` - The total number of results for this query. - -In this case, we've decided to create a simple view that shows the starting and ending result numbers on this page. We've chosen not to use -the `totalResults` or `searchTerm` properties. - -Specific documentation for customizing the view of each component can be found in the documentation for each component. For example, . diff --git a/docs/guides-debugging.mdx b/docs/guides-debugging.mdx deleted file mode 100644 index ce187204..00000000 --- a/docs/guides-debugging.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -slug: /search-ui/guides/debugging -title: Debugging -date: 2022-02-27 -tags: ["demo"] ---- - -There is a `debug` flag available on the configuration for `SearchDriver` and `SearchProvider`. - -```jsx - -``` - -Setting this to `true` will make the `searchUI` object available globally on window. This will allow you to -programmatically execute actions in the browser console which can be helpful for debugging. - -```js -window.searchUI.addFilter("states", "California", "all"); -``` - -This will also log actions and state updates as they occur to the console in the following form: - -``` -Search UI: Action {Action Name} {Action Parameters} -Search UI: State Update {State to update} {Full State after update} -``` diff --git a/docs/guides-nextjs-integration.mdx b/docs/guides-nextjs-integration.mdx deleted file mode 100644 index 3d180118..00000000 --- a/docs/guides-nextjs-integration.mdx +++ /dev/null @@ -1,215 +0,0 @@ ---- -slug: /search-ui/guides/nextjs-integration -title: NextJS Integration -date: 2022-10-05 -tags: ["nextjs", "vercel"] ---- - -### Integrating Search UI with NextJS Router - -Next JS is a popular React framework that provides a number of features out of the box, including server-side rendering, routing, and more. - -To take advantage of being able to save the search criteria in the URL, you need to override the existing routing options and use Next Router. - -Below is an example of how to do achieve this. - -To highlight, we're using React memo to prevent the component from re-rendering the Search UI chrome when the URL changes. - - - - ```jsx - import { memo } from 'react' - import { useNextRouting } from "../utils/useNextRouting"; - - export default function App() { - // useNextRouting is a custom hook that will integrate with Next Router with Search UI config - // config is search-ui configuration. - // baseUrl is the path to the search page - const combinedConfig = useNextRouting(config, ""); - return ; - } - - const Search = memo(({ config }) => { - return ( - - <> - - - - - - ) - }) - - ``` - - - - -```jsx -import { useRouter } from "next/router"; -import { useMemo } from "react"; - -export const useNextRouting = (config, basePathUrl) => { - const router = useRouter(); - const { asPath } = router; - - const getSearchParamsFromUrl = (url) => { - return url.match(/\?(.+)/)?.[1] || ""; - }; - - const routingOptions = { - // read and write only the query string to search UI - // as we are leveraging existing stateToUrl and urlToState functions - // which are based on the query string - readUrl: () => { - return getSearchParamsFromUrl(asPath); - }, - writeUrl: (url, { replaceUrl }) => { - const method = router[replaceUrl ? "replace" : "push"]; - const params = Object.fromEntries(new URLSearchParams(url).entries()); - method({ query: { ...router.query, ...params } }, undefined, { - shallow: true - }); - }, - routeChangeHandler: (callback) => { - const handler = (fullUrl) => { - if (fullUrl.includes(basePathUrl)) { - callback(getSearchParamsFromUrl(fullUrl)); - } - }; - router.events.on("routeChangeComplete", handler); - return () => { - router.events.off("routeChangeComplete", handler); - }; - } - }; - - return useMemo(() => { - return { - ...config, - routingOptions - }; - }, [router.isReady]); -}; -``` - - - - -### Integration with Elasticsearch Connector - -We do not advise exposing your Elasticsearch instance to the public. Fortunately with NextJS, we do not need to do this. NextJS makes it very simple to build an API route so we can move the connector to the server side. - -To start, we create a connector that will send the `requestState` and `queryConfig` over to the client side. - -```js -// located in /services/APIConnector.js - -class APIConnector { - constructor() {} - - onResultClick() { - // optional. Called when a result has been clicked - } - onAutocompleteResultClick() { - // optional. Called when an autocomplete result has been clicked - } - - async onSearch(requestState, queryConfig) { - const response = await fetch("/api/search", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - requestState, - queryConfig - }) - }); - return response.json(); - } - - async onAutocomplete(requestState, queryConfig) { - const response = await fetch("api/autocomplete", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - requestState, - queryConfig - }) - }); - return response.json(); - } -} - -export default APIConnector; -``` - -then add an `api` folder within `/pages` folder. Add two files, `autocomplete.js` and `search.js` - -```js -// located in /pages/api/search.js -import ElasticsearchAPIConnector from "@elastic/search-ui-elasticsearch-connector"; - -const connector = new ElasticsearchAPIConnector({ - host: "", - index: "", - apiKey: "" // optional -}); - -export default async function handler(req, res) { - const { requestState, queryConfig } = req.body; - const response = await connector.onSearch(requestState, queryConfig); - res.json(response); -} -``` - -```js -// located in /pages/api/autocomplete.js -import ElasticsearchAPIConnector from "@elastic/search-ui-elasticsearch-connector"; - -const connector = new ElasticsearchAPIConnector({ - host: "", - index: "", - apiKey: "" // optional -}); - -export default async function handler(req, res) { - const { requestState, queryConfig } = req.body; - const response = await connector.onAutocomplete(requestState, queryConfig); - res.json(response); -} -``` - -then lastly swap the elasticsearch connector to use the APIConnector. With this change, when a user searches, the search will be sent to the server and the API routes will fetch the results from Elasticsearch and will be sent back to the client. - -```js -import Connector from "../services/APIConnector"; - -const apiConnector = new Connector(); - -const searchConfig = { - apiConnector: apiConnector - // ...truncated search configuration -}; -``` - -and then restart your nextjs app. To confirm that this is working, you should see network requests within chrome developer tools performing requests with `requestState` and `queryConfig` to the `/api/search` & `/api/autocomplete` API routes and results being returned back to the client. - -Below is an example of this running within codesandbox. - - -```` diff --git a/docs/guides-search-as-you-type.mdx b/docs/guides-search-as-you-type.mdx deleted file mode 100644 index 04d9bb1e..00000000 --- a/docs/guides-search-as-you-type.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -slug: /search-ui/guides/using-search-as-you-type -title: Using search-as-you-type -date: 2022-05-05 -tags: ["search-as-you-type"] ---- - -Usually, the search query is executed when the user presses the enter key or clicks the search button. - -Search-as-you-type feature allows search queries to be executed on every keystroke. - -To implement this in Search UI, you'll need to add a `searchAsYouType={true}` prop to `` component. - -It's a good idea to add a debounce time — the Search UI will wait for users to finish typing before issuing the request. You can do it by adding a `debounceLength={300}` prop to `` component. - -See the example implementation below. - - - -Related documentation: - -- diff --git a/docs/guides-using-with-vue-js.mdx b/docs/guides-using-with-vue-js.mdx deleted file mode 100644 index 063a1d06..00000000 --- a/docs/guides-using-with-vue-js.mdx +++ /dev/null @@ -1,32 +0,0 @@ ---- -slug: /search-ui/guides/using-with-vue-js -title: Using with Vue.js -date: 2022-07-18 -tags: ["search", "interface", "ui", "example", "vue", "vuejs"] ---- - -While Search UI doesn't have a component library for Vue.js, you can still use them together, just with a little extra work. - -To achieve that you'll need to import and work directly with Search UI Core API. Read a short guide for high-level overview on the approach. - -Once you're familiar with the concept of Search UI core, the following docs will give you deeper dive into available APIs: - -- -- -- - -## Example - -The following demo is a good starting point for your Search UI implementation. The source code is available on GitHub: https://github.com/elastic/search-ui/tree/main/examples/vue - - diff --git a/docs/known-issues.mdx b/docs/known-issues.mdx deleted file mode 100644 index b6316cf4..00000000 --- a/docs/known-issues.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -slug: /search-ui/known-issues -title: Known issues -description: Known issues with Search UI -date: 2023-02-10 -tags: [""] ---- - -- When using the **Elasticsearch connector** Search UI does not render nested objects. diff --git a/docs/nav-searchui.docnav.json b/docs/nav-searchui.docnav.json deleted file mode 100644 index df4489a4..00000000 --- a/docs/nav-searchui.docnav.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "mission": "Search UI", - "id": "search-ui", - "landingPageSlug": "/search-ui/overview", - "icon": "inspect", - "description": "Docs for Elastic's Search UI project", - "items": [ - { - "label": "What is Search UI?", - "slug": "/search-ui/overview" - }, - { - "label": "Ecommerce", - "slug": "/search-ui/solutions/ecommerce", - "items": [ - { "slug": "/search-ui/solutions/ecommerce/autocomplete" }, - { "slug": "/search-ui/solutions/ecommerce/carousel" }, - { "slug": "/search-ui/solutions/ecommerce/category-page" }, - { "slug": "/search-ui/solutions/ecommerce/product-detail-page" }, - { "slug": "/search-ui/solutions/ecommerce/search-page" } - ] - }, - { - "label": "Tutorials", - "slug": "/search-ui/tutorials/connectors", - "items": [ - { "slug": "/search-ui/tutorials/app-search" }, - { "slug": "/search-ui/tutorials/elasticsearch" }, - { "slug": "/search-ui/tutorials/workplace-search" } - ] - }, - { - "label": "Basic usage", - "slug": "/search-ui/guides/customizing-styles-and-html", - "items": [ - { "slug": "/search-ui/guides/using-search-as-you-type" }, - { "slug": "/search-ui/guides/adding-search-bar-to-header" }, - { "slug": "/search-ui/guides/debugging" } - ] - }, - { - "label": "Advanced usage", - "slug": "/search-ui/guides/using-with-vue-js", - "items": [ - { "slug": "/search-ui/guides/conditional-facets" }, - { "slug": "/search-ui/guides/changing-component-behavior" }, - { "slug": "/search-ui/guides/analyzing-performance" }, - { "slug": "/search-ui/guides/creating-your-own-components" }, - { "slug": "/search-ui/guides/building-a-custom-connector" }, - { "slug": "/search-ui/guides/nextjs-integration" } - ] - }, - { - "label": "API reference", - "slug": "/search-ui/api/architecture", - "items": [ - { - "label": "Core API", - "slug": "/search-ui/api/core/configuration", - "items": [ - { "slug": "/search-ui/api/core/state" }, - { "slug": "/search-ui/api/core/actions" } - ] - }, - { - "label": "React API", - "slug": "/search-ui/api/react/search-provider", - "items": [ - { "slug": "/search-ui/api/react/with-search" } - ] - }, - { - "label": "React components", - "slug": "/search-ui/api/react/components/search-box", - "items": [ - { "slug": "/search-ui/api/react/components/results" }, - { "slug": "/search-ui/api/react/components/result" }, - { "slug": "/search-ui/api/react/components/results-per-page" }, - { "slug": "/search-ui/api/react/components/facet" }, - { "slug": "/search-ui/api/react/components/sorting" }, - { "slug": "/search-ui/api/react/components/paging" }, - { "slug": "/search-ui/api/react/components/paging-info" }, - { "slug": "/search-ui/api/react/components/error-boundary" } - ] - }, - { - "label": "Connectors API", - "slug": "/search-ui/api/connectors/app-search", - "items": [ - { "slug": "/search-ui/api/connectors/site-search" }, - { "slug": "/search-ui/api/connectors/workplace-search" }, - { "slug": "/search-ui/api/connectors/elasticsearch" } - ] - }, - { - "label": "Plugins", - "slug": "/search-ui/api/core/plugins/analytics-plugin" - } - ] - }, - { - "label": "Troubleshooting", - "slug": "/search-ui/known-issues" - } - ] -} diff --git a/docs/overview.mdx b/docs/overview.mdx deleted file mode 100644 index 645a7e77..00000000 --- a/docs/overview.mdx +++ /dev/null @@ -1,119 +0,0 @@ ---- -slug: /search-ui/overview -title: Search UI -description: For the fast development of modern, engaging search experiences. 🎉 -date: 2023-01-27 -tags: ["demo"] ---- - -A JavaScript library for the fast development of modern, engaging search experiences with [Elastic](https://www.elastic.co/). Get up and running quickly without re-inventing the wheel. - -## Features 👍 - -- **You know, for search** - Maintained by [Elastic](https://elastic.co), the team behind Elasticsearch. -- **Speedy Implementation** - Build a complete search experience with a few lines of code. -- **Customizable** - Tune the components, markup, styles, and behaviors to your liking. -- **Smart URLs** - Searches, paging, filtering, and more, are captured in the URL for direct result linking. -- **Flexible front-end** - Not just for React. Use with any JavaScript library, even vanilla JavaScript. -- **Flexible back-end** - Use it with Elasticsearch, Elastic Enterprise Search, or any other search API. - -## Live demos 👀 - -### Connectors - -- [Elasticsearch](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/elasticsearch&file=/src/pages/elasticsearch/index.js) -- [Elastic Site Search (Swiftype)](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/site-search&file=/src/pages/site-search/index.js) -- ⚠️ DEPRECATED. [Elastic App Search](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/app-search&file=/src/pages/app-search/index.js) -- ⚠️ DEPRECATED. [Elastic Workplace Search](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/workplace-search&file=/src/pages/workplace-search/index.js) - -### Examples - -- [Search as you type](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/search-as-you-type&file=/src/pages/search-as-you-type/index.js) -- [Search bar in header](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/search-bar-in-header&file=/src/pages/search-bar-in-header/index.js) -- [Customizing Styles and Components](https://codesandbox.io/s/github/elastic/search-ui/tree/main/examples/sandbox?from-embed=&initialpath=/customizing-styles-and-html&file=/src/pages/customizing-styles-and-html/index.js) - -## Get Started 🌟 - -### Installation - -``` -npm install @elastic/search-ui @elastic/react-search-ui @elastic/react-search-ui-views -# or -yarn add @elastic/search-ui @elastic/react-search-ui @elastic/react-search-ui-views -``` - -### Tutorials - -Get started quickly with Search UI and your favorite Elastic product by following one of the tutorials below: - -- -- -- - -## Use Cases 🛠️ - -### Ecommerce - -Search UI works great in the ecommerce use-case. Check out our that includes demo and code examples, as well as general guidance for ecommerce search. - -## FAQ 🔮 - -### Is Search UI only for React? - -Search UI is "headless". You can use vanilla JavaScript or write support for it into any JavaScript framework. - -[Read about the search-ui package](https://github.com/elastic/search-ui/tree/main/packages/search-ui) for more information, or check out the [Vue.js Example](https://github.com/elastic/vue-search-ui-demo). - -### Can I use my own styles? - -You can! - -Read the to learn more, or check out the [Seattle Indies Expo Demo](https://github.com/elastic/seattle-indies-expo-search). - -### Can I build my own Components? - -Yes! Absolutely. - -Check out the . - -### Does Search UI only work with App Search? - -Nope! We do have two first party connectors: Site Search and App Search. - -But Search UI is headless. You can use _any_ Search API. - -Read the to learn more about building your own connector for your API. - -### How do I use this with Elasticsearch? - -Read the docs. - -### Where do I report issues with the Search UI? - -If something is not working as expected, please open an [issue](https://github.com/elastic/search-ui/issues/new). - -### Where can I go to get help? - -The Enterprise Search team at Elastic maintains this library and are happy to help. Try posting your question to the [Elastic Enterprise Search](https://discuss.elastic.co/c/enterprise-search/84) discuss forums. Be sure to mention that you're using Search UI and also let us know what backend your using; whether it's App Search, Site Search, Elasticsearch, or something else entirely. - -## Contribute 🚀 - -We welcome contributors to the project. Before you begin, a couple notes... - -- Read the [Search UI Contributor's Guide](https://github.com/elastic/search-ui/blob/main/CONTRIBUTING.md). -- Prior to opening a pull request, please: - - Create an issue to [discuss the scope of your proposal](https://github.com/elastic/search-ui/issues). - - Sign the [Contributor License Agreement](https://www.elastic.co/contributor-agreement/). We are not asking you to assign copyright to us, but to give us the right to distribute your code without restriction. We ask this of all contributors in order to assure our users of the origin and continuing existence of the code. You only need to sign the CLA once. -- Please write simple code and concise documentation, when appropriate. - -## License 📗 - -[Apache-2.0](https://github.com/elastic/search-ui/blob/main/LICENSE.txt) © [Elastic](https://github.com/elastic) - -Thank you to all the [contributors](https://github.com/elastic/search-ui/graphs/contributors)! 🙏 🙏 diff --git a/docs/solutions-ecommerce-autocomplete.mdx b/docs/solutions-ecommerce-autocomplete.mdx deleted file mode 100644 index bbc02a20..00000000 --- a/docs/solutions-ecommerce-autocomplete.mdx +++ /dev/null @@ -1,454 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce/autocomplete -title: "Autocomplete" -description: Provide suggestions to customers as they type in a search query -date: 2022-07-16 -tags: ["autocomplete"] ---- - -When you start typing in a search box on ecommerce sites like Amazon or Best Buy, you might have seen a dropdown showing suggestions to try next. This is called autocomplete. - -![Search suggestions on Amazon](images/ecommerce/autocomplete/query-suggestions-amazon.png) - -On some of the more popular ecommerce sites, you may see suggestions in the form of search suggestions, product categories, and products. - -![Multiple Search Suggestions](images/ecommerce/autocomplete/federated-search-products.png) - -This article will discuss how to implement an autocomplete search box that provides multiple options on your ecommerce site. - -Search UI can be used to provide different types of suggestions from multiple sources. For example, depending on your use case, you can display query suggestions, products from the product catalog, and a list of popular queries at the same time. - -The code in this article examples powers the following demo. Try typing "monitor" in the search box! - - - -## Before you begin - -This tutorial builds on the . - -## Integrating the Searchbox - -Typically ecommerce sites have a search bar within the site's header, which is accessible on every page. - -For this tutorial, we will assume that the search bar is located in the site's header. - -Within the header, we need to use the `SearchProvider` and `Searchbox` components to integrate the autocomplete search box. - -```jsx - -const config = { - // search provider configuration for autocomplete -} - -function NavigationHeader() { - return ( -
    - - - - { - window.location.href = `${PATH_TO_YOUR_SEARCH_PAGE}?q=${searchTerm}`; - }} - - /> - - -
    - ); -``` - -Should you find the search bar markup too limiting to your needs, you can override the display using the optional `inputView` `autocompleteView` and `resultsView` props. - -```jsx - ( -
    - {autocompletedResults.map((result, i) => ( -
    - Result {i}: {result.title.snippet} -
    - ))} -
    - )} -/> -``` - -For more information of whats possible to customise, see . - -## Term Suggestions - -Term Suggestions help the customer quickly type in the search term. The suggestions are based on keywords that are already present in the index. To do this, you need: - -- An engine or index populated with products - -To configure the SearchBox to provide suggestions based on keywords, you need to pass a `config` object to the `SearchProvider` component and configure the `Searchbox autocompleteSuggestions` to be true. - -![Search suggestions with Search UI](images/ecommerce/autocomplete/query-suggestions-es-shop.png) - -Example Code - - - - ```jsx - const config = { - autocompleteQuery: { - resultsPerPage: 5, - result_fields: { - name: { snippet: { size: 100, fallback: true }}, - url: { raw: {} } - }, - search_fields: { - "name_product_autocomplete": {} - } - }, - }; - ``` - - - ```jsx - ; - ``` - - - -## Product Suggestions - -With this feature, products will be presented as suggestions to the customer. When the customer clicks on the product suggestion, they will be navigated straight to the product's detail page. - -![Search suggestions with Search UI](images/ecommerce/autocomplete/query-results-es-shop.png) - -First, we specify the `autocompleteQuery.results` configuration: - - - - ```jsx - const config = { - alwaysSearchOnInitialLoad: false, - autocompleteQuery: { - results: { - resultsPerPage: 5, - result_fields: { - // specify the fields you want from the index to display the results - image: { raw: {} }, - name: { snippet: { size: 100, fallback: true } }, - url: { raw: {} } - }, - search_fields: { - // specify the fields you want to search on - name: {} - } - } - }, - apiConnector: connector - }; - ``` - - - ```jsx - ; - ``` - - - ```jsx - function AutocompleteView({ - autocompleteResults, - autocompletedResults, - autocompleteSuggestions, - autocompletedSuggestions, - className, - getItemProps, - getMenuProps - }) { - let index = 0; - return ( -
    - <> - {!!autocompleteSuggestions && - Object.entries(autocompletedSuggestions).map( - ([suggestionType, suggestions]) => { - return ( - - {getSuggestionTitle( - suggestionType, - autocompleteSuggestions - ) && - suggestions.length > 0 && ( -
    - {getSuggestionTitle( - suggestionType, - autocompleteSuggestions - )} -
    - )} - {suggestions.length > 0 && ( -
      - {suggestions.map((suggestion) => { - index++; - return ( -
    • - {suggestion.highlight ? ( - - ) : ( - {suggestion.suggestion} - )} -
    • - ); - })} -
    - )} -
    - ); - } - )} - {!!autocompleteResults && - !!autocompletedResults && - typeof autocompleteResults !== "boolean" && - autocompletedResults.length > 0 && - autocompleteResults.sectionTitle && ( -
    - {autocompleteResults.sectionTitle} -
    - )} - {!!autocompleteResults && - !!autocompletedResults && - autocompletedResults.length > 0 && ( -
      - {autocompletedResults.map((result) => { - index++; - const titleField = - typeof autocompleteResults === "boolean" - ? null - : autocompleteResults.titleField; - const titleRaw = getRaw(result, titleField); - return ( -
    • - -
      {titleRaw}
      -
    • - ); - })} -
    - )} - -
    - ); - } - ``` -
    -
    - -## Suggestions from another source index - - - -Sometimes you want to display suggestions from a different index than the one you use for search. For example, you might want to show suggestions from a `popular_queries` or a `designers` index. Search UI supports this within the `autocompleteSuggestions` configuration. - -In this example, we will populate an index with popular queries. The mapping and example documents for the index will be as follows: - - - -```json -{ - "popular_queries" : { - "mappings" : { - "properties" : { - "name" : { - "type" : "text", - "fields" : { - "suggest" : { - "type" : "search_as_you_type", - "doc_values" : false, - "max_shingle_size" : 3 - } - } - } - } - } - } -} -``` - - -```json -{ - "name" : "Iphone 4s" -} -``` - - - -Next, setup Search UI `Searchbox` and `configuration` to display suggestions from the `popular_queries` index. - - - - ```jsx - const config = { - alwaysSearchOnInitialLoad: false, - autocompleteQuery: { - suggestions: { - types: { - popularQueries: { - search_fields: { - "name.suggest": {} // fields used to query - }, - result_fields: { - name: { - raw: {} - } - }, - index: "popular_queries", - queryType: "results" - } - }, - size: 4 - }, - }, - apiConnector: connector - }; - ``` - - - ```jsx - ; - ``` - - - -Now, when you type `was` in the SearchBox, the autocomplete view will display the popular queries: - -![Suggestions from another index](images/ecommerce/autocomplete/query-suggestions-popular-queries.png) - -If you want to display more fields from the index, you can use the `result_fields` configuration and implement a custom `autocompleteView` to display these fields. - -## Suggestions from multiple sources - -Combining the suggestion configurations above allows you to display suggestions from multiple sources simultaneously. - -![Suggestions from multiple sources](images/ecommerce/autocomplete/query-suggestions-multiple-sources.png) - -To do this, extend the `autocompleteQuery` configuration to specify multiple sources. For example, in the screenshot above, we customized the `autocompleteView` CSS to display the popular queries and the results from the `autocompleteSuggestions` configuration side by side and hide the section titles. - - - - ```jsx - const config = { - alwaysSearchOnInitialLoad: false, - autocompleteQuery: { - suggestions: { - types: { - popularQueries: { - search_fields: { - "name.suggest": {} // fields used to query - }, - result_fields: { - name: { - raw: {} - } - }, - index: "popular_queries", - queryType: "results" - } - }, - size: 4 - }, - }, - apiConnector: connector - }; - ``` - - - ```jsx - - ``` - - - - diff --git a/docs/solutions-ecommerce-carousel.mdx b/docs/solutions-ecommerce-carousel.mdx deleted file mode 100644 index 93622c84..00000000 --- a/docs/solutions-ecommerce-carousel.mdx +++ /dev/null @@ -1,122 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce/carousel -title: "Product Carousels" -description: Build a product carousel with Search UI -date: 2022-04-13 -tags: ["ecommerce solution", "ecommerce search ui", "product carousel"] ---- - -Carousels can be used to show groups of products into a row and are typically used to show products within a specific category or tag, like "most popular", "best rated" and "on sale". - -In this example, we show a carousel of products within the "TVs" category using the `Results` component and overriding the `view`. - -You can adjust the number of results returned via the `resultsPerPage` configuration. - -![](images/ecommerce/carousel/carousel.png) - - - - ```jsx - import { Results, SearchProvider } from "@elastic/react-search-ui"; - import { config } from "./config"; - - const CustomResultsView = ({ children }) => { - return ( -
    -
      {children}
    -
    - ); - }; - - const CustomResultView = ({ result }) => { - return ( -
  • - - {result.name.raw} -

    {result.name.raw}

    -
    -
  • - ); - }; - - export default function ProductCarousel(props) { - return ( - -
    -

    - {props.title} -

    - -
    -
    - ); - } - - ``` - -
    - -```js -import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector"; - -const connector = new AppSearchAPIConnector({ -searchKey: "", -engineName: "", -endpointBase: "", -}); - -export const config = () => ({ - alwaysSearchOnInitialLoad: true, - trackUrlState: false, - initialState: { - resultsPerPage: 8 - }, - searchQuery: { - filters: [{ field: "parent_category", values: ["TVs"] }], - result_fields: { - name: { - raw: {} - }, - image: { raw: {} }, - url: { raw: {} } - } - }, - apiConnector: connector -}); -``` - -
    - - - - diff --git a/docs/solutions-ecommerce-category-page.mdx b/docs/solutions-ecommerce-category-page.mdx deleted file mode 100644 index 75c1b84e..00000000 --- a/docs/solutions-ecommerce-category-page.mdx +++ /dev/null @@ -1,342 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce/category-page -title: "Category Page" -description: Show a list of products in a particular category -date: 2022-07-16 -tags: ["Category page", "PLP"] ---- - -This is a category page: - - - -At first glance, the category page looks very similar to a search page — they display a list of products and have facets to help users refine the results. -But while the search page is made for "searching" the entire catalog by typing a query, the category page is made for "exploring" a small subset of products with the help of filters. - -On the screenshot above, we are only exploring the "Women's Athletic Shoes" section of the catalog. - -In this article, we will talk about how to implement a product category page with Search UI. The code examples here power the demo of a category page we've build. See it in action below: - - - -## Applying Filters to the Category Page - -It's important to consider the SEO of a category page. Some of your customers will come from search engines, and having a good-looking URL will help you rank higher. - -Let's say we want to have a category page for TVs. You can do it by taking a search page and applying a filter to only show TVs. - -Now, if we do so on a search page, we'll have a URL like this: - -``` -mystore.com/search?filters%5B0%5D%5Bfield%5D=categories&filters%5B0%5D%5Bvalues%5D%5B0%5D=TVs -``` - -Not very readable! - -What we want instead is to have a URL like this: - -``` -mystore.com/category/tvs/ -``` - -To achieve that, we'll need to: - -1. Create the category page in our application; -1. Apply a filter via Search UI config. - -The first part is highly dependent on your application's framework. Refer to its documentation for creating a new page. - -For the second part, copy the Search UI config from the search page and add the `searchQuery.filters` value. Then pass the new config to your `SearchProvider`: - -```jsx -// import your Search UI config -import { config } from "./config"; -import { SearchProvider, WithSearch } from "@elastic/react-search-ui"; - -const categoryTvsConfig = { - ...config, - searchQuery: { - ...config.searchQuery, - // adding a filter to only show TVs - filters: [{ field: "parent_category", values: ["TVs"] }] - } -}; - -export default function CategoryPageTvs() { - return ( - // Pass the new config to SearchProvider - - ({})}> - {() => { - // The components you want to render go here - }} - - - ); -} -``` - -That's it! The new category page has a good URL and only shows results that match the filter. - -## Facets - - - -Facets are the essential part of the category page. Since category pages typically don't have a search box, facets become the primary tool for finding the products. - -_Facets let users **explore** what's available in your store rather than **search** for a specific product._ - -It's best to provide facets that are unique to the presented category. - -In our example of the TVs category page, in addition to common facets, like: - -- Price -- Brand -- Rating - -we also have TV-specific facets: - -- Smart TV _(boolean)_ -- TV resolution _(string: "Full HD", "4k", etc.)_ -- TV diagonal _(number)_ - -These TV-specific facets are not useful on the search page since they are not relevant to most of the results. - ---- - -There are several ways to implement this in Search UI. They offer different levels of control and flexibility. - -1. All category pages share a single config. It is the simplest option to implement but is also the least flexible and performant. -1. All category pages share a single config, but the facets are shown conditionally. It is a middle ground in simplicity and flexibility and is as performant as the next option. -1. Each category page uses a separate config. It is the most flexible and most performant option, but it requires more work to implement. - -### Single config - -You can use a single Search UI config on the search page and all category pages. However, it comes with a performance drawback: the facets data will be requested on every page even if it's not used. The decision is up to you: a single config will work as well as separate configs if most of your documents share the same properties. - -To implement this, you'll need to: - -1. Add new result fields to `searchQuery.resultFields` -1. Add new facets to `searchQuery.facets` -1. (optional) Add new disjunctiveFacets `searchQuery.disjunctiveFacets` - -Then, add the `Facet` components to UI. - -The resulting code will look something like this: - -```jsx -// import your Search UI config -import { SearchProvider, WithSearch } from "@elastic/react-search-ui"; - -const config = { - searchQuery: { - // 1. Adding new resilt fields, these will be used for the facets - result_fields: { - tv_size: { raw: {} }, - tv_smart_tv: { raw: {} }, - tv_resolution: { raw: {} } - // some other fields - }, - // 2. Adding the new facets - facets: { - tv_size: { - type: "value", - sort: { value: "asc" } - }, - tv_smart_tv: { - type: "value" - }, - tv_resolution: { - type: "value", - sort: { value: "asc" } - } - // some other facets - }, - // 3. Making some of newly added facets disjunctive - disjunctiveFacets: ["tv_size", "tv_resolution"] - } -}; - -export default function CategoryPage() { - return ( - // Pass the config to SearchProvider - - ({})}> - {() => { - return ( - // The components you want to render go here - // For the sake of brevity, we're only showing the new facets - <> - - - - - ); - }} - - - ); -} -``` - -### Conditional facets - -Search UI allows you to show facets conditionally based on the applied filters. -Follow the main guide for more info and code examples: . - -### Separate configs - -This option closely follows the single config option but requires you to make a copy of the main Search UI config (that you use on the search page) first. - -1. Import and make a copy of the main Search UI config -1. Add new result fields to `searchQuery.resultFields` -1. Add new facets to `searchQuery.facets` -1. (optional) Add new disjunctiveFacets `searchQuery.disjunctiveFacets` - -Then, add the `Facet` components to UI. - -Here's how to do it all at once: - -```jsx -// import your Search UI config -import { config } from "./config"; -import { SearchProvider, WithSearch } from "@elastic/react-search-ui"; - -const categoryTvsConfig = { - ...config, - searchQuery: { - ...config.searchQuery, - filters: [{ field: "parent_category", values: ["TVs"] }], - // 1. Adding new resilt fields, these will be used for the facets - result_fields: { - ...config.searchQuery.result_fields, - tv_size: { raw: {} }, - tv_smart_tv: { raw: {} }, - tv_resolution: { raw: {} } - }, - // 2. Adding the new facets - facets: { - ...config.searchQuery.facets, - tv_size: { - type: "value", - sort: { value: "asc" } - }, - tv_smart_tv: { - type: "value" - }, - tv_resolution: { - type: "value", - sort: { value: "asc" } - } - }, - // 3. Making some of newly added facets disjunctive - disjunctiveFacets: [ - ...config.searchQuery.disjunctiveFacets, - "tv_size", - "tv_resolution" - ] - } -}; - -export default function CategoryPageTvs() { - return ( - // Pass the new config to SearchProvider - - ({})}> - {() => { - return ( - // The components you want to render go here - // For the sake of brevity, we're only showing the new facets - <> - - - - - ); - }} - - - ); -} -``` - -### Example - -Search UI offers several kinds of facets out-of-the-box: - -- MultiCheckboxFacet -- BooleanFacet -- SingleLinksFacet - -Here's an example of how to use them: - -```jsx -import { BooleanFacet, SingleLinksFacet } from "@elastic/react-search-ui-views"; - - - - -``` - -And the resulting UI: - - - -You might need a facet that Search UI doesn't offer, for example, a dedicated color-picker. With Search UI, you can build a custom facet that will work like a native one. Refer to the to learn how. - -## Variants - -See the main guide for more info about variants: . - -## Sorting - -See the main guide for more info about sorting: . - - diff --git a/docs/solutions-ecommerce-product-detail-page.mdx b/docs/solutions-ecommerce-product-detail-page.mdx deleted file mode 100644 index 5943364a..00000000 --- a/docs/solutions-ecommerce-product-detail-page.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce/product-detail-page -title: "Product Detail Page" -description: Display product detail and cross-sell recommendations -date: 2022-07-16 -tags: ["Product Detail Page", "PDP"] ---- - - - -You can put many things on a product detail page: image, description, specs. They are all describing the product itself. - -But a critical piece that often gets overlooked is cross-sell recommendations. - - - -These are the lists of products located under the product description. They often come under such headings: - -- People who viewed this item also viewed -- Often bought together -- You might also like -- etc. - -Cross-sell recommendations help users find the right product if the current one does not satisfy their criteria or find the related products faster (for example, frying pan + lid). - -Technically, cross-sell recommendations are usually implemented as product carousels. To build one, check out our , which has an implementation example. - - diff --git a/docs/solutions-ecommerce-search-page.mdx b/docs/solutions-ecommerce-search-page.mdx deleted file mode 100644 index a959f5c7..00000000 --- a/docs/solutions-ecommerce-search-page.mdx +++ /dev/null @@ -1,222 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce/search-page -title: "Search Page" -description: Display products that match a customer's search query -date: 2022-07-16 -tags: ["Search Page", "Search relevance"] ---- - -The most important part of the search page is the relevance of the displayed results. - -There are many ways to improve the relevance. In this article we'll cover: - -- tools available in the admin interface, -- combining similar results with variants, -- sorting — improved relevance achieved by a user. - -## Improving relevance - -App Search offers many tools to improve the relevance of your search results. - -### Start with a language optimization - -Choosing the correct language during the engine creation is the easiest way to improve the relevance. - -Language optimization will fine-tune features like **stemming**, **bigram matching**, **phrase matching**, and **typo tolerance** for your chosen language. - -Follow this guide for the exact steps: [Language optimization guide](https://www.elastic.co/guide/en/app-search/current/language-optimization-guide.html). - -### Set up relevance tuning - -App Search's relevance tuning feature allows you to fine-tune the order of the results for any given query. - -Follow the [Relevance tuning guide](https://www.elastic.co/guide/en/app-search/current/relevance-tuning-guide.html) for the full feature description. - -### Add synonyms - -This step is optional but can also improve the relevance. - -Sometimes users will use a query that doesn't _exactly_ match your results. You're selling **couches**, but a user searches for **sofa**? Tough luck! - -To solve this problem, App Search offers a Synonyms feature. It lets you create groups of synonyms that will be used for matching. - -Our [Synonyms guide](https://www.elastic.co/guide/en/app-search/current/relevance-tuning-guide.html) goes into more detail about the feature. - -### Create curations - -Curations allow you to - -- promote some results to always show up at the top of the search results for a specific query -- hide some results from showing up in the search results for a specific query - -Learn more about curations in our [Curations guide](https://www.elastic.co/guide/en/app-search/current/curations-guide.html) - -## Variants - -You might have several products that are essentially the same but have one different attribute. For example, it could be shirts of different colors. In our demo, it's the same TV models but with different diagonal sizes. - -If you have such products in your store, consider combining them into a single result. That will prevents users from being overwhelmed by the number of options. - -Here's a demo of this feature: - - - -To implement this in Search UI, you'll need to do the following: - -1. Enrich your dataset. -2. Enable grouping in Search UI config. -3. Add variants rendering into your Result component. - -### Enriching dataset - -Add a new field to all documents in your dataset that will be used for grouping search results. Here's the example: - -```json -[ - { - "name": "Samsung TV 55 inch", - "product_group": "[GROUP_ID_1]" - }, - { - "name": "Samsung TV 45 inch", - "product_group": "[GROUP_ID_1]" - }, - { - "name": "LG TV 55 inch", - "product_group": "[GROUP_ID_2]" - } -] -``` - -Make sure to add that new field to all the documents in a dataset! Otherwise, API will combine all the documents missing that field into a single group. - -### Enabling grouping in Search UI config - -Search UI does not directly support the grouping, but it is supported by the underlying [App Search API](https://www.elastic.co/guide/en/app-search/current/grouping.html). -So instead of enabling it in the Search UI config, we'll enable it in the App Search connector config. -Here's an example: - -```js -const connector = new AppSearchAPIConnector({ - searchKey: "search-key", - engineName: "engine-name", - endpointBase: "endpointBase", - // enabling grouping in App Search connector config - beforeSearchCall: (existingSearchOptions, next) => - next({ - ...existingSearchOptions, - group: { field: "product_group", collapse: true } - }) -}); - -export const config = { - alwaysSearchOnInitialLoad: true, - apiConnector: connector - // other config properties -}; -``` - -### Adding variants rendering into your Result component - -Once the grouping is enabled, the variants will be available via the `_group` field in your result document. -Here's a simplified example of how to use it: - -```jsx -{ - result._group && result._group.length > 0 && ( -
      - {result._group.map((variant) => ( -
    • - - - -
    • - ))} -
    - ); -} -``` - -## Sorting - - - -Adding sorting is simple — just use our `` component, like so: - -```js -import { Sorting } from "@elastic/react-search-ui"; - -; -``` - -A good starting point for sorting options is to have these three: - -- Relevance / Featured / Best Match (usually the default option) -- Price: Low to High -- Price: High to Low - -Consider adding some of these if they apply to your data: - -- Popularity -- User rating -- Distance (to the user) -- Newest first - -Check out how sorting is implemented in our demo: - - - - diff --git a/docs/solutions-ecommerce.mdx b/docs/solutions-ecommerce.mdx deleted file mode 100644 index 76ee9e5f..00000000 --- a/docs/solutions-ecommerce.mdx +++ /dev/null @@ -1,46 +0,0 @@ ---- -slug: /search-ui/solutions/ecommerce -title: "Overview" -description: Build an ecommerce experience with Search UI -date: 2022-04-13 -tags: ["ecommerce solution", "ecommerce search ui", "overview"] ---- - -In ecommerce, to build great search experiences for your customers, you need to focus on these major experiences: - -- **Global Search bar**: to give customers the ability to perform a search on any page of your store. -- **Search Page**: to give your customers a place to see results relevant to their query and refine them using facets. -- **Category Page**: to show a list of products from a particular category to help users explore available products. -- **Product Carousel**: to show a list of products within pages like the Homepage or Checkout, or if a query returns no results. -- **Product Detail Page**: to describe the product and provide cross-sell recommendations, like similar products from the same category or "frequently bought with" items. - -Below you can see a demo of an ecommerce store built with Search UI. We're going to use it to demonstrate different concepts in the next several articles. - -Full code of this demo is available here: https://github.com/elastic/search-ui/tree/main/examples/sandbox, with the Ecommerce code located under `pages/ecommerce`. - - - - diff --git a/docs/tutorials-app-search.mdx b/docs/tutorials-app-search.mdx deleted file mode 100644 index cfeaf717..00000000 --- a/docs/tutorials-app-search.mdx +++ /dev/null @@ -1,418 +0,0 @@ ---- -slug: /search-ui/tutorials/app-search -title: "Search UI with App Search" -description: Build a search experience with App Search and Search UI -date: 2022-04-13 -tags: ["Tutorial", "Parks", "US"] ---- - - - App Search connector for Search UI is deprecated and will no longer be - supported. Please migrate to{" "} - {" "} - for continued support. - - -This tutorial will guide you through the process of creating a Search UI with [App Search](https://elastic.co/app-search), using the `search-ui-app-search-connector`. We will be using a sample engine in App Search, which comes pre-loaded with A US national parks dataset. - -Within this tutorial, we assume that you have Node.js installed on your machine. - -## Setup App Search - -First we need to setup App Search, which is a part of [Elastic Enterprise Search](https://elastic.co/enterprise-search). The easiest way to do this is to create a deployment on [Elastic Cloud](https://elastic.co/cloud). You can sign up for a free 14-day trial [here](https://cloud.elastic.co/register), no credit card required. - -Once your deployment has been created, navigate to Enterprise Search in Kibana. You should be able to see a link to Enterprise Search from the home menu. - -![search-ui](images/app-search-tutorial/kibana-home.png) -![search-ui](images/app-search-tutorial/ent-search-home.png) - -In the next step, we'll navigate to App Search and create an engine that will hold our US national parks documents. - -## Create an Engine with Sample Data - -Select "Try a sample engine", which creates a engine loaded with useful sample data. The sample engine will be pre-loaded with the US national parks dataset that we'll need for our search experience. Easy! - -![search-ui](images/app-search-tutorial/create-engine.png) - -### Configure Schema - -Once our sample engine has been created, the next step is to inspect our engine's schema. By default, App Search will choose the field type "text" for each field, but we can manually configure the field types to match the type of data each field represents — text, date, geolocation, or number. **For the sample engine, the fields have been pre-configured for us.** - -![search-ui](images/app-search-tutorial/configure-schema.png) - -If you inspect the schema, you'll notice that a number of fields have been changed from their default `text` field type: - -- `visitors` to be a **number** -- `square_km` to be a **number** -- `date_established` to be a **date** -- `location` to be a **geolocation** -- `acres` to be a **number** - -Adjusting the field type allows us to use different queries, facets, and filters only applicable to the field types we are using. [Learn more about App Search schemas](https://www.elastic.co/guide/en/app-search/current/indexing-documents-guide.html#indexing-documents-guide-schema) - -### API Keys - -API keys are used to access the engine. By default, there are two key types available: - -- private-key: This is the key that is used to read and write to the engine. -- search-key: This is the key that has read only access to the engine. - -![search-ui](images/app-search-tutorial/credentials.png) - -For this example, we are going to use the search-key. By default the search-key has been created. To use it, we must copy the key. Keep this key safe, we will be using it later on. - -Also above is the host url. Copy this as we will use it later on as well. - -## Build a Search Experience with Search UI - -For this tutorial, we are going to be using the popular [Create React App (CRA) framework](https://reactjs.org/docs/create-a-new-react-app.html). To get started, we run the following command - -```shell - npx create-react-app us-parks-demo --template typescript -``` - -Once this has been completed, we can navigate to the directory of the project. - -### Install Search UI dependencies - -Now we need to install the dependencies for the search UI into our project. We can do this by running the following command: - -```shell -yarn add @elastic/search-ui @elastic/react-search-ui-views @elastic/search-ui-app-search-connector @elastic/react-search-ui -``` - -This will download the latest version of the packages and install them into our project. - -### Add Search UI React Components - -We can now add the Search UI React components to our project. First we need to open `src/App.tsx` and replace it's contents with the following: - -```jsx -import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector"; -import React from "react"; -import { - ErrorBoundary, - Facet, - SearchProvider, - SearchBox, - Results, - PagingInfo, - ResultsPerPage, - Paging, - WithSearch -} from "@elastic/react-search-ui"; -import { - BooleanFacet, - Layout, - SingleLinksFacet, - SingleSelectFacet -} from "@elastic/react-search-ui-views"; -import "@elastic/react-search-ui-views/lib/styles/styles.css"; -import { SearchDriverOptions } from "@elastic/search-ui"; - -const connector = new AppSearchAPIConnector({ - searchKey: "", - engineName: "national-parks-demo", - endpointBase: "" -}); - -const config: SearchDriverOptions = { - alwaysSearchOnInitialLoad: true, - apiConnector: connector, - hasA11yNotifications: true, - searchQuery: { - result_fields: { - title: { raw: {} } - }, - search_fields: {}, - disjunctiveFacets: [""], - facets: {} - } -}; - -export default function App() { - return ( - - ({ - wasSearched - })} - > - {({ wasSearched }) => { - return ( -
    - - } - sideContent={
    } - bodyContent={ - - } - bodyHeader={ - - {wasSearched && } - {wasSearched && } - - } - bodyFooter={} - /> -
    -
    - ); - }} -
    -
    - ); -} -``` - -Before we can run our app, we'll have to do some initial configuration. To start, let's add our deployment details to the `connector` configuration. Replace `` with your deployment's public search key and replace `` with your deployment's endpoint URL. - -```jsx -const connector = new AppSearchAPIConnector({ - searchKey: "", - engineName: "national-parks-demo", - endpointBase: "" -}); -``` - -Next, we'll have to add at least one field to `search_fields` within the `config` object, otherwise Search UI won't be able to successfully execute a query. Let's start by adding the `title` field: - -```jsx -search_fields: { - title: {} -}, -``` - -Lets check that the app works by running the following command: - -```shell -yarn start -``` - -You should now have a working, basic search experience that looks similar to the example below: - -![search-ui](images/app-search-tutorial/initial-cra.png) - -## Configure Search UI - -We now have a working search experience, but we need to configure it now to take advantage of the data we have. Lets start by identifying which fields we want to search, display, and make available as facets. - -Here's an example document from the data that we have indexed: - -```json -{ - "id": "park_rocky-mountain", - "title": "Rocky Mountain", - "description": "Bisected north to south by the Continental Divide, this portion of the Rockies has ecosystems varying from over 150 riparian lakes to montane and subalpine forests to treeless alpine tundra. Wildlife including mule deer, bighorn sheep, black bears, and cougars inhabit its igneous mountains and glacial valleys. Longs Peak, a classic Colorado fourteener, and the scenic Bear Lake are popular destinations, as well as the historic Trail Ridge Road, which reaches an elevation of more than 12,000 feet (3,700 m).", - "nps_link": "https://www.nps.gov/romo/index.htm", - "states": ["Colorado"], - "visitors": 4517585, - "world_heritage_site": false, - "location": "40.4,-105.58", - "acres": 265795.2, - "square_km": 1075.6, - "date_established": "1915-01-26T06:00:00Z" -} -``` - -Based on this document, we can determine the fields that we want to be: - -- **Searchable**: title, description, states -- **Displayable**: title, description, states, visitors, acres, square_km, date_established, nps_link -- **Facetable**: states, visitors, acres, square_km, date_established - -### Searchable Configuration - -In a previous step we added the `title` to `search_fields`, but we'll expand on that here. For our complete search experience, we want `title`, `description`, and `states` to be searchable. We can do this by adding the following to the `config` object: - -```js -search_fields: { - title: { - weight: 5 - }, - description: {}, - states: {} -} -``` - -The `weight` parameter that we added to `title` is the weight of the field. The higher the weight, the more important the field is when relevance is calculated. [Learn more about relevance tuning](https://www.elastic.co/guide/en/app-search/current/relevance-tuning-guide.html) - -### Displayble Configuration - -We want `title`, `description`, `states`, `visitors`, `acres`, `square_km`, `nps_link` and `date_established` to be displayable, or usable in our search results. We can do this by adding the following to the `config` object: - -```js -result_fields: { - title: { - snippet: { - fallback: true - } - }, - description: { - snippet: { - fallback: true - } - }, - states: { - snippet: { - fallback: true - } - }, - visitors: { raw: {} }, - acres: { raw: {} }, - square_km: { raw: {} }, - date_established: { raw: {} }, - nps_link: { raw: {} }, -} -``` - -`snippet` is a configuration for the display of the field. Any value that matches a field will be displayed in the results as a highlight. The `fallback` will be used if a highlight is not found. [Learn more about result settings](https://www.elastic.co/guide/en/app-search/current/result-settings-guide.html) - -### Facetable Configuration - -We want `states`, `visitors`, `acres`, `square_km`, and `date_established` to be facetable. We can do this by adding the following to the `config` object: - -```js -facets: { - states: { type: "value", size: 30 }, - acres: { - type: "range", - ranges: [ - { from: -1, name: "Any" }, - { from: 0, to: 1000, name: "Small" }, - { from: 1001, to: 100000, name: "Medium" }, - { from: 100001, name: "Large" } - ] - }, - location: { - // San Francisco. In the future, make this the user's current position - center: "37.7749, -122.4194", - type: "range", - unit: "mi", - ranges: [ - { from: 0, to: 100, name: "Nearby" }, - { from: 100, to: 500, name: "A longer drive" }, - { from: 500, name: "Perhaps fly?" } - ] - }, - date_established: { - type: "range", - - ranges: [ - { - from: '1972-04-13T12:48:33.420Z', - name: "Within the last 50 years" - }, - { - from: '1922-04-13T12:48:33.420Z', - to: '1972-04-13T12:48:33.420Z', - name: "50 - 100 years ago" - }, - { - to: '1922-04-13T12:48:33.420Z', - name: "More than 100 years ago" - } - ] - }, - visitors: { - type: "range", - ranges: [ - { from: 0, to: 10000, name: "0 - 10000" }, - { from: 10001, to: 100000, name: "10001 - 100000" }, - { from: 100001, to: 500000, name: "100001 - 500000" }, - { from: 500001, to: 1000000, name: "500001 - 1000000" }, - { from: 1000001, to: 5000000, name: "1000001 - 5000000" }, - { from: 5000001, to: 10000000, name: "5000001 - 10000000" }, - { from: 10000001, name: "10000001+" } - ] - } -} -``` - -The example above shows a variety of facet types, including: - -- value facet: displays a list of filters aggregated by their counts -- range facet: displays a list of range filters (both numeric and date) aggregated by their counts -- geo-location facet: geo distance filters based on a location - -[Learn more about facets](https://www.elastic.co/guide/en/app-search/current/facets-guide.html) - -For these facets to appear, we need to add the facet components to our view. Let's replace the `sideContent` prop in our view with the example below: - -```jsx -sideContent={ -
    - - - - - - -
    -} -``` - -### Disjunctive facets - -Last but not least, we want some of our facets to be "OR" facets rather than "AND". Making that change is a two step process: - -1. Make the facet "disjunctive" by adding it to the `disjunctiveFacets` list config. This will ensure that the facet displays all - available options for selection, so that users can make multiple selections. - -```jsx -disjunctiveFacets: ["states"], -``` - -2. Make the `Facet` component user the `filterType` of `any`. - -```jsx - -``` - -## Test Drive! - -You should be able to see the results of your search like below: - -![search-ui](images/app-search-tutorial/completed-ui.png) - -## Next Steps - -Lets recap of the steps we have covered: - -- We created an App Search Engine and indexed a sample data set of us-parks -- We configured the engine's schema and fields -- We created a new React project and added the Search UI components -- We configured the search UI to search the engine and display facets to help the user narrow down the results - -Next you can add more data into the index, , and deploy the app. diff --git a/docs/tutorials-connectors.mdx b/docs/tutorials-connectors.mdx deleted file mode 100644 index ef186010..00000000 --- a/docs/tutorials-connectors.mdx +++ /dev/null @@ -1,30 +0,0 @@ ---- -slug: /search-ui/tutorials/connectors -title: Which connector to choose? -date: 2022-04-18 -tags: ["demo"] ---- - -The first thing you want to consider before implementing your search is the backend you're going to use for your data. - -### Recommended connectors - -Search UI works best with **Elastic App Search** and **Elasticsearch**. - -If you're relatively new to the search problem or Elastic ecosystem, we recommend choosing **[App Search](https://www.elastic.co/enterprise-search/search-applications)**. It solves many search problems out-of-box and is generally simpler to start with, althought it's not as flexible as Elasticsearch. - -On the other hand, if you prefer flexibility over simplicity and already familiar with **[Elasticsearch](https://www.elastic.co/elasticsearch)**, go with it! Just note that our Elasticsearch connector is still in technical preview and its API might change in the future. - -If you're still not sure, go with App Search. It'll help you start quickly, and you can switch to Elasticsearch later if you need to. - -### Other connectors - -Search UI also works with **Elastic Workplace Search** and **Elastic Site Search**. - -Choose **[Workplace Search](https://www.elastic.co/enterprise-search/workplace-search)** if it's critical for you to search data from one of the [supported sources](https://www.elastic.co/guide/en/workplace-search/current/workplace-search-content-sources.html#oauth-first-party-content-sources), like Confluence, Salesforce, Jira or others. - -Choose **[Site Search](https://www.elastic.co/enterprise-search/site-search)** if you are already using [Swiftype](https://swiftype.com/), these are basically a single product with two names. Otherwise, it's best to go with the **App Search** connector, since the functionalty of Site Search has already been implemented in the App Search's web crawler. - -### Custom connector - -It is possible to implement your own connector to Search UI. Read our to learn more. diff --git a/docs/tutorials-elasticsearch.mdx b/docs/tutorials-elasticsearch.mdx deleted file mode 100644 index 6ddc29c8..00000000 --- a/docs/tutorials-elasticsearch.mdx +++ /dev/null @@ -1,474 +0,0 @@ ---- -slug: /search-ui/tutorials/elasticsearch -title: "Search UI with Elasticsearch" -description: Build a search experience with Elasticsearch and Search UI -date: 2022-04-13 -tags: ["Tutorial", "Elasticsearch", "movies"] ---- - - - Elasticsearch connector for Search UI is currently in technical preview - status. It is not ready for production use. - - -This tutorial will guide you through the process of creating a Search UI with Elasticsearch directly, using the `elasticsearch-connector`. We will be using a sample movie data-set of around 1000 movies. - -Within this tutorial, we assume that you have Node.js installed on your machine. - -## Step 1: Setup Elasticsearch - -First we need to setup Elasticsearch. The easiest way to do this is to create an Elasticsearch instance via [Elastic Cloud](https://cloud.elastic.co/registration). - -### Setting up an Index - -We are going to issue commands via [Kibana's dev tools console](https://www.elastic.co/guide/en/kibana/current/console-kibana.html). You can alternatively use a REST client like Postman to achieve this. - -First we need to create an index for our data. We can do this simply via the following request: - -```shell -PUT /my-example-movies -``` - -![Create Index](images/elasticsearch-tutorial/create-index.jpeg) - -Elasticsearch will acknowledge our request in the response. - -### Setting up a read-only API Key - -Next we need to setup an API key to access the data from the index. We can do this via Kibana's Stack Management API Keys page (`/app/management/security/api_keys`). Note that security needs to be enabled for this option to be available. - -Notice here we are only giving read privileges for this api key. You will need to setup an api key with write privileges to add and update data to the index. - -```json -{ - "superuser": { - "cluster": ["all"], - "indices": [ - { - "names": ["my-example-movies"], - "privileges": ["read"], - "allow_restricted_indices": false - } - ] - } -} -``` - -![creating api key](images/elasticsearch-tutorial/api-keys.jpeg) - -Once saved, you are presented with the api-key. Copy this and keep it safe. We will need to use this further down in the tutorial. - -![copy api key](images/elasticsearch-tutorial/api-key-view.jpeg) - -### Enabling CORS - -If you're going to be accessing Elasticsearch directly from a browser and the Elasticsearch host domain doesn't match your site's domain, you will need to enable CORS. - -CORS is a browser mechanism which enables controlled access to resources located outside of the current domain. In order for the browser to make requests to Elasticsearch, CORS configuration headers need to specified in the Elasticsearch configuration. - -![edit-deployment-settings](images/elasticsearch-tutorial/edit-settings.png) - -You can do this in cloud by going to the deployment settings for your Elasticsearch instance, click "Edit user settings and plugins" and under "user settings", add the CORS configuration below: - -```yaml -http.cors.allow-origin: "*" -http.cors.enabled: true -http.cors.allow-credentials: true -http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE -http.cors.allow-headers: X-Requested-With, X-Auth-Token, Content-Type, Content-Length, Authorization, Access-Control-Allow-Headers, Accept, x-elastic-client-meta -``` - -![edit-deployment-settings](images/elasticsearch-tutorial/cors-settings.png) - -then save. Your Elasticsearch instance will be restarted and the CORS configuration will be active. - -## Step 2: Setup Movies Index - -Next we need to setup the index fields, ready for us to ingest data. - -The mapping for an index depends on the data you want to index and the features you want. - -### Examples - -We want to be able to search on title. We need only one field of type text. - -```json -{ - "properties": { - "title": { - "type": "text" - } - } -} -``` - -We want to be able to search and product facets for writers field. We need two fields of different types: keyword and text. - -```json -{ - "properties": { - "writers": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - } - } - } -} -``` - -We want to be able to filter on a date field. We only need one date field. - -```json -{ - "properties": { - "released": { - "type": "date" - } - } -} -``` - -We want to be able to filter on a numeric field. We only need one numeric field. Can be a choice of integer, float and [more documented here](https://www.elastic.co/guide/en/elasticsearch/reference/current/number.html) - -```json -{ - "properties": { - "imdbRating": { - "type": "float" - } - } -} -``` - -For our movie data-set, we will be using the following fields: - -- title (searchable) -- plot (searchable) -- genre (searchable, facetable) -- actors (searchable, facetable) -- directors (searchable, facetable) -- released (filterable) -- imdbRating (filterable) -- url - -The mapping file will be as follows, and we'll once again use Kibana's dev tools console to update the mapping file for our index. - -```shell -PUT /my-example-movies/_mapping -{ - "properties": { - "title": { - "type": "text", - "fields": { - "suggest": { - "type": "search_as_you_type" - } - } - }, - "plot": { - "type": "text" - }, - "genre": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - } - }, - "actors": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - } - }, - "directors": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword" - } - } - }, - "released": { - "type": "date" - }, - "imdbRating": { - "type": "float" - }, - "url": { - "type": "keyword" - }, - "movie_completion": { - "type": "completion" - } - } -} -``` - -![add mapping](images/elasticsearch-tutorial/update-mapping.jpeg) - -Elasticsearch will acknowledge the request in the response. - -We also want to provide autocomplete functionality, so we need to setup fields for autocomplete. - -For suggestions, we want to suggest terms that appear within the actors, directors and genre fields. -For quick result hits, we want to suggest movies that partially match the title field. - -In the above example: - -- we have included `movie_completion` field, which is used to provide suggestion completion functionality. This field is not searchable, but is used to provide autocomplete functionality. -- we have included a `suggest` field for the title field. This field is searchable, but is used to provide "quick hits" functionality. - -## Step 3: Index Movies Data - -Now with our index and mapping file created, we are ready to index some data! We will use the bulk API to index our data. - -We will use the following request. In this example we will be indexing the first movie in the data-set to verify that the data fields is being indexed correctly. - -```shell -PUT /my-example-movies/_bulk -{ "index": {}} -{"title": "The Godfather", "released": "1972-03-23T23:00:00.000Z","genre": ["Crime", "Drama"],"directors": ["Francis Ford Coppola"],"actors": ["Marlon Brando", "Al Pacino", "James Caan", "Richard S. Castellano"],"plot": "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.","imdbRating": "9.2", "movie_completion": ["Crime", "Drama", "Marlon Brando", "Al Pacino", "James Caan", "Richard S. Castellano"], "url": "https://www.imdb.com/title/tt0068646/"} -``` - -## Step 4: Setup CRA for Search UI - -First, download the Search-UI's starter app from github by - -```shell -curl https://codeload.github.com/elastic/app-search-reference-ui-react/tar.gz/master | tar -xz -``` - -and should appear as a folder called `app-search-reference-ui-react-main`. - -Navigate to the root to the folder and install the dependencies using the following command: - -```shell -yarn -``` - -### Installing connector - -Within the folder, we can now install the `@elastic/search-ui-elasticsearch-connector` library with Yarn. - -```shell -yarn add @elastic/search-ui-elasticsearch-connector -``` - -Make sure to check and update Search UI dependencies to the latest version. You can find the latest version by going to [NPM's page for @elastic/search-ui](https://www.npmjs.com/package/@elastic/search-ui). - -### Setting up the connector - -Open the project within your favorite editor. - -Within `src/App.js`, change line 3 to import the Elasticsearch connector. You no longer need the app-search connector. - -```js -import ElasticsearchAPIConnector from "@elastic/search-ui-elasticsearch-connector"; -``` - -and then update the options to the connector - -```js -const connector = new ElasticsearchAPIConnector({ - cloud: { - id: "" - }, - apiKey: "", - index: "my-example-movies" -}); -``` - -If you're using Elastic Cloud, you can find your cloud id within your deployment's details. - -![copy es endpoint](images/elasticsearch-tutorial/copy-cloud-id.jpg) - -alternatively, if you're using an on-premise Elasticsearch instance, you can connect via specifying the host. - -```js -const connector = new ElasticsearchAPIConnector({ - host: "http://localhost:9200", - index: "my-example-movies" -}); -``` - -## Step 5: Configure Search UI - -Next lets configure Search UI for our needs! Navigate to the config within app.js and update the following: - -```js -const config = { - searchQuery: { - search_fields: { - title: { - weight: 3 - }, - plot: {}, - genre: {}, - actors: {}, - directors: {} - }, - result_fields: { - title: { - snippet: {} - }, - plot: { - snippet: {} - } - }, - disjunctiveFacets: ["genre.keyword", "actors.keyword", "directors.keyword"], - facets: { - "genre.keyword": { type: "value" }, - "actors.keyword": { type: "value" }, - "directors.keyword": { type: "value" }, - released: { - type: "range", - ranges: [ - { - from: "2012-04-07T14:40:04.821Z", - name: "Within the last 10 years" - }, - { - from: "1962-04-07T14:40:04.821Z", - to: "2012-04-07T14:40:04.821Z", - name: "10 - 50 years ago" - }, - { - to: "1962-04-07T14:40:04.821Z", - name: "More than 50 years ago" - } - ] - }, - imdbRating: { - type: "range", - ranges: [ - { from: 1, to: 3, name: "Pants" }, - { from: 3, to: 6, name: "Mediocre" }, - { from: 6, to: 8, name: "Pretty Good" }, - { from: 8, to: 10, name: "Excellent" } - ] - } - } - }, - autocompleteQuery: { - results: { - resultsPerPage: 5, - search_fields: { - "title.suggest": { - weight: 3 - } - }, - result_fields: { - title: { - snippet: { - size: 100, - fallback: true - } - }, - url: { - raw: {} - } - } - }, - suggestions: { - types: { - results: { fields: ["movie_completion"] } - }, - size: 4 - } - }, - apiConnector: connector, - alwaysSearchOnInitialLoad: true -}; -``` - -In the above example, we configured the: - -- query fields to search on title, plot, genre, actors and directors using the text fields -- result fields to display title, plot, genre, actors and directors using the text fields -- facets to display genre, actors and directors using the keyword fields -- we made the facets disjunctive for better user experience. The user can select more than one facet to expand their search. -- autocomplete results to suggest results with the same query fields as main search + returning some fields for display. - -For more information on configuration, visit the . - -### Updating Components - -We are going to do several steps here: - -- update the `` component to configure autocomplete -- remove sorting options -- add a `` component for each facet field -- update the `` component to display all the fields - -```jsx -
    - - - } - sideContent={ -
    - {wasSearched && } - - - - - -
    - } - bodyContent={} - bodyHeader={ - - {wasSearched && } - {wasSearched && } - - } - bodyFooter={} - /> -
    -
    -``` - -## Step 6: Test Drive! - -Lets run the project with the command: - -```shell -yarn start -``` - -and then view the results in the browser at http://localhost:3000/ - -![search-ui](images/elasticsearch-tutorial/search-ui.jpeg) - -## Next Steps - -Lets recap of the steps we have covered: - -- we setup and configured the Elasticsearch index for our data -- we indexed an example movie -- we checked out the starter app and added the Elasticsearch connector -- we configured the Elasticsearch connector to connect to our Elasticsearch index -- we updated the Search UI configuration to specify the fields to be searchable, facetable -- we updated the components to use these fields - -Next you can add more data into the index, , and deploy the app. diff --git a/docs/tutorials-workplace-search.mdx b/docs/tutorials-workplace-search.mdx deleted file mode 100644 index 69cc770e..00000000 --- a/docs/tutorials-workplace-search.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -slug: /search-ui/tutorials/workplace-search -title: Search UI with Workplace Search -date: 2022-04-18 -tags: ["demo"] ---- - - - Workplace Search connector for Search UI is deprecated and will no longer be - supported. Please migrate to{" "} - {" "} - for continued support. - - -This guide will walk you through getting up and running with a Search UI using [Elastic Workplace Search](https://www.elastic.co/workplace-search/) as a backend. - -Have problems with the setup? Let us know in the [feedback issue](https://github.com/elastic/search-ui/issues/707), and we'll try to help. - -## Prerequisites - -Before continuing with this guide, make sure you: - -1. have a running Elastic deployment with Enterprise Search and -2. indexed some data in Workplace Search. - -The best way to get started with Elastic Workplace Search is to follow our [Getting Started guide](https://www.elastic.co/guide/en/workplace-search/current/workplace-search-getting-started.html). - -To index data into Workplace Search, read the [Content Sources Overview](https://www.elastic.co/guide/en/workplace-search/current/workplace-search-content-sources.html) and follow a guide for any content source available there. - -## Creating a search page - -Have you indexed data into Workplace Search? Great! Let's create a search page in your application. - -We'll use React components in this tutorial, but you can use Search UI with any UI framework and even vanilla JavaScript. Read about our to learn more about using Search UI outside of React. - -First, let's install Search UI packages: - -```shell -npm install @elastic/react-search-ui @elastic/search-ui-workplace-search-connector -``` - -Next, create a new page in your application and add the following code: - -```jsx -import React from "react"; -import WorkplaceSearchAPIConnector from "@elastic/search-ui-workplace-search-connector"; -import { - SearchProvider, - SearchBox, - Results, - Paging, - WithSearch -} from "@elastic/react-search-ui"; -import { Layout } from "@elastic/react-search-ui-views"; -import "@elastic/react-search-ui-views/lib/styles/styles.css"; - -const connector = new WorkplaceSearchAPIConnector({ - kibanaBase: "", - enterpriseSearchBase: "", - redirectUri: "", - clientId: "" -}); - -const config = { - apiConnector: connector, - alwaysSearchOnInitialLoad: true -}; - -export default function WorkplaceSearch() { - return ( - - ({ - authorizeUrl, - isLoggedIn, - logout - })} - > - {({ authorizeUrl, isLoggedIn, logout }) => { - return ( -
    - {isLoggedIn ? ( - - ) : ( - Log in - )} - } - bodyContent={} - bodyFooter={} - /> -
    - ); - }} -
    -
    - ); -} -``` - -This page shouldn't work yet. To connect to the Workplace Search backend, you need to provide some details in the connector configuration. - -## Adding connector configuration - -Here's where to get the required configuration parameters: - -### `kibanaBase` and `enterpriseSearchBase` - -You can get both values on the API Keys page in Workplace Search: - -- `kibanaBase` — from the url, -- `enterpriseSearchBase` — from the Endpoint panel. - -![endpoints](images/workplace-search-tutorial/endpoints.png) - -### `redirectUri` - -Use the path to the page where Search UI is going to live. - -### `clientId` - -To get a clientId, you need to create a new OAuth application in Workplace Search. - -1. In Workplace Search, go to Settings, then OAuth application. -2. In the Redirect URIs field, add the `redirectUri` value from the previous step. -3. Deselect Confidential toggle. -4. Save changes. -5. Copy the `Client id` from the Credentials section. - -![oauth-application](images/workplace-search-tutorial/oauth-application.png) - -After finishing these steps, you should have a configuration that looks something like this: - -```js -const connector = new WorkplaceSearchAPIConnector({ - kibanaBase: - "https://my-deployment-10151b.kb.us-central1.gcp.cloud.es.io:9243", - enterpriseSearchBase: - "https://my-deployment-10151b.ent.us-central1.gcp.cloud.es.io", - redirectUri: "http://localhost:3001", - clientId: "d06a6d2db34ac6f6315cb5e37f84186fa84279371b5fd44186ed84afba14c70e" -}); -``` - -## Authorizing the application - -You should now be able to authorize. - -Click on the "Log in" link in the Search UI and authorize the application to search your data. - -![authorize](images/workplace-search-tutorial/authorize.png) - -Once you click the Authorize button, you should be redirected back to your application and see the search results. - -![search-ui-results](images/workplace-search-tutorial/search-ui-results.png) - -Congratulations! You have successfully connected to Workplace Search. - -## Next steps - -The UI we have now is very minimal. That is intentional to get you started quickly. - -Some of the next steps you could take to improve your search experience are: - -- adding facets, -- adding paging info, -- adding sorting, -- setting up autocomplete -- improving the design of results. - -Check out our [example page](https://github.com/elastic/search-ui/blob/7cf8710a8037123ee42dc1616ec8f23b842a66f0/examples/sandbox/src/pages/workplace-search/index.js) where we added some of these items, or follow other guides in this documentation.