-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: stub in All tab for unified search behind flag (#1986)
* chore: add search-test page * feat: WIP set up All tab for unified search * chore: enable unified search in previews * chore: ensure unified search is disabled in prod * chore: start cleaning up all tab * chore: continue cleanup * chore: continue refactor * refactor: un-abstract all-tab-contents * chore: split out getShouldRenderIntegrationsTab * chore: fix typo * refactor: add back hit count with filter split * chore: get no results message working * chore: revert not-needed change to hit-counts-provider * chore: revert unhelpful rename * chore: enable unified search in development * chore: split out utils, continue cleanup * chore: split out use-debounced-recent-searches * chore: clean up imports a little * chore: useMemo for integrations tab bool * docs: add comment on unified-hit work * chore: cleanup to co-locate helpers with related code * chore: continue helper co-location * chore: remove unused export * docs: add comment on build-url-path * chore: add magenta border to ugly-first-draft card * chore: update comment typo * chore: add console error for build-url-path issue * chore: turn off search flags * chore: clarify use of edition filter * chore: enable dark mode on hit placeholder
- Loading branch information
Showing
21 changed files
with
816 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,8 @@ | |
"extends": "base", | ||
"io_sites": { | ||
"max_static_paths": 10 | ||
}, | ||
"flags": { | ||
"enable_unified_search": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
.../command-bar/commands/search/unified-search/components/dialog-body/dialog-body.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.suggestedPagesWrapper { | ||
padding: 16px; | ||
} |
34 changes: 34 additions & 0 deletions
34
...search/unified-search/components/dialog-body/helpers/get-algolia-product-filter-string.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { ProductSlug } from 'types/products' | ||
|
||
/** | ||
* Given an optional product slug, | ||
* | ||
* Return an Algolia `filter` string that will filter for search objects | ||
* of any type (`docs`, `tutorial`, or `integration`) that match the | ||
* specified product slug. | ||
* | ||
* Note: intended for use with our unified search indices, which are | ||
* named `<env>_DEVDOT_omni` in Algolia. | ||
*/ | ||
export function getAlgoliaProductFilterString( | ||
productSlug?: ProductSlug | ||
): string { | ||
let filterString = '' | ||
|
||
if (productSlug) { | ||
filterString = `products:${productSlug}` | ||
|
||
/** | ||
* The edition:hcp only applies to `tutorials` records, which will | ||
* never have products:hcp, but we can't apply complex filters | ||
* via the Algolia filters API parameter to only apply the `edition` | ||
* filter to tutorial records, so we use an OR filter instead. | ||
* Ref: https://www.algolia.com/doc/api-reference/api-parameters/filters/ | ||
*/ | ||
if (productSlug === 'hcp') { | ||
filterString += ` OR edition:${productSlug}` | ||
} | ||
} | ||
|
||
return filterString | ||
} |
3 changes: 3 additions & 0 deletions
3
...onents/command-bar/commands/search/unified-search/components/dialog-body/helpers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './get-algolia-product-filter-string' | ||
export * from './use-command-bar-product-tag' | ||
export * from './use-debounced-recent-searches' |
68 changes: 68 additions & 0 deletions
68
...mands/search/unified-search/components/dialog-body/helpers/use-command-bar-product-tag.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { useCallback, useMemo } from 'react' | ||
import { useCommandBar } from 'components/command-bar' | ||
import { useCurrentProduct } from 'contexts' | ||
import { getCurrentProductTag } from '../../../../helpers' | ||
import { useSetUpAndCleanUpCommandState } from 'components/command-bar/hooks' | ||
|
||
/** | ||
* Set and un-set the command-bar-level product filtering tag. | ||
* | ||
* TODO: consider refactoring this. | ||
* | ||
* We've had feedback from design at least that the "product tag" interface | ||
* doesn't feel right within the search modal. This raises a few questions: | ||
* | ||
* - Is this genuinely a command-bar-wide setting, or are "product tag" filters | ||
* something we could apply to the "Search" command only for now? (Note: | ||
* I'm not even sure other "commands" (ie "settings") are implemented yet... | ||
* managing the "tags" at the command bar level feels like it may have | ||
* been a premature abstraction based on relatively speculative use cases). | ||
* | ||
* - In the context of search, specifically auto-filtering to a given product | ||
* when in that product context, Would typing-based filters, such as | ||
* `product:<productSlug>`, be preferable to the "product tag" approach? | ||
*/ | ||
export function useCommandBarProductTag() { | ||
const currentProduct = useCurrentProduct() | ||
const { addTag, currentTags, removeTag } = useCommandBar() | ||
|
||
/** | ||
* Create callback for setting up this command's state. | ||
*/ | ||
const setUpCommandState = useCallback(() => { | ||
if (currentProduct) { | ||
addTag({ | ||
id: currentProduct.slug, | ||
text: currentProduct.slug === 'hcp' ? 'HCP' : currentProduct.name, | ||
}) | ||
} | ||
}, [addTag, currentProduct]) | ||
|
||
/** | ||
* Create callback for cleaning up this command's state. | ||
*/ | ||
const cleanUpCommandState = useCallback(() => { | ||
if (currentProduct) { | ||
removeTag(currentProduct.slug) | ||
} | ||
}, [currentProduct, removeTag]) | ||
|
||
/** | ||
* Leveraging the set up + clean up hook exposed by CommandBarDialog. | ||
*/ | ||
useSetUpAndCleanUpCommandState(setUpCommandState, cleanUpCommandState) | ||
|
||
/** | ||
* Get the CommandBarTag object for the current product if it's present. | ||
*/ | ||
const currentProductTag = useMemo( | ||
() => | ||
getCurrentProductTag({ | ||
currentProduct, | ||
currentTags, | ||
}), | ||
[currentProduct, currentTags] | ||
) | ||
|
||
return currentProductTag | ||
} |
56 changes: 56 additions & 0 deletions
56
...nds/search/unified-search/components/dialog-body/helpers/use-debounced-recent-searches.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { useEffect, useState } from 'react' | ||
import useRecentSearches from '../../../../hooks/use-recent-searches' | ||
// Types | ||
import type { Dispatch, SetStateAction } from 'react' | ||
|
||
/** | ||
* Debounce a setState function to the providing millisecond timing. | ||
* | ||
* Used as a temporary measure to retain debouncing of "recent search" query | ||
* strings. Later, we may want to consider a different debounce method. | ||
*/ | ||
export function useSetStateDebounce<T>( | ||
setStateFn: Dispatch<SetStateAction<T>>, | ||
stateValue: T, | ||
timing: number | ||
) { | ||
useEffect(() => { | ||
const typingDebounce = setTimeout(() => { | ||
setStateFn(stateValue) | ||
}, timing) | ||
return () => clearTimeout(typingDebounce) | ||
}, [stateValue, timing, setStateFn]) | ||
} | ||
|
||
/** | ||
* Given the current input value, | ||
* | ||
* Save recent search input values to local storage with the `useRecentSearches` | ||
* hook, while debouncing input value changes to prevent every keystroke | ||
* from being saves. | ||
* | ||
* TODO: consider longer debounce for setting recent search queries? | ||
* Or maybe additional debounce should be built into `useRecentSearches`? | ||
* | ||
* Maybe the debounce should be part of some variation of the | ||
* `useRecentSearches` hook instead of how things currently are? | ||
*/ | ||
export function useDebouncedRecentSearches(currentInputValue: string) { | ||
const [debouncedInput, setDebouncedInput] = useState<string>(undefined) | ||
const { recentSearches, addRecentSearch } = useRecentSearches() | ||
|
||
/** | ||
* Delay recording search queries while the user is typing | ||
*/ | ||
useSetStateDebounce(setDebouncedInput, currentInputValue, 300) | ||
|
||
/** | ||
* Add a new "recent search" when the debounced input value updates. | ||
*/ | ||
useEffect( | ||
() => addRecentSearch(debouncedInput), | ||
[addRecentSearch, debouncedInput] | ||
) | ||
|
||
return recentSearches | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...mmand-bar/commands/search/unified-search/components/unified-hit/helpers/build-url-path.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { getTutorialSlug } from 'views/collection-view/helpers' | ||
import { getIntegrationUrl } from 'lib/integrations' | ||
// Types | ||
import type { Hit } from 'instantsearch.js' | ||
|
||
/** | ||
* Builds a URL path to an arbitrary hit from our unified `<env>_DEVDOT_omni` | ||
* Algolia indices. | ||
* | ||
* TODO: consider baking a `urlPath` property into each Algolia object? | ||
*/ | ||
export function buildUrlPath(searchHit: Hit): string { | ||
if (searchHit.type === 'docs') { | ||
const objectIdWithoutType = searchHit.objectID.replace('docs_', '') | ||
return `/${objectIdWithoutType}`.replace(/\/index$/, '') | ||
} else if (searchHit.type === 'tutorial') { | ||
const { slug, defaultContext } = searchHit | ||
return getTutorialSlug(slug, defaultContext.slug) | ||
} else if (searchHit.type === 'integration') { | ||
const { | ||
external_only, | ||
external_url, | ||
product_slug, | ||
organization_slug, | ||
slug, | ||
} = searchHit | ||
/** | ||
* TODO: refactor `getIntegrationUrl` to `Pick<>` what's actually needed. | ||
* For now, using `$TSFixMe` to avoid inaccurate TS errors about what | ||
* argument properties are needed for the function to work. | ||
*/ | ||
return getIntegrationUrl({ | ||
external_only, | ||
external_url, | ||
product: { slug: product_slug } as $TSFixMe, | ||
organization: { slug: organization_slug } as $TSFixMe, | ||
slug, | ||
} as $TSFixMe) | ||
} else { | ||
/** | ||
* Something's gone wrong, this should never happen in our indexing. | ||
* Link to the home page as insurance. And ideally, should log | ||
* an error here, not just locally, but maybe elsewhere? | ||
* | ||
* TODO: figure out where to log errors like this in such a way that | ||
* they're surfaced to the team, rather than only appearing in-browser. | ||
*/ | ||
console.error( | ||
`Unexpected input in build-url-path: content type "${searchHit.type}" is not a recognized content type. Valid content types are "docs", "tutorial", and "integration". Please ensure the object pushed to Algolia only use these content types.` | ||
) | ||
return '/' | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
...onents/command-bar/commands/search/unified-search/components/unified-hit/helpers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './build-url-path' | ||
export * from './render-highlight-array-html' |
20 changes: 20 additions & 0 deletions
20
...mands/search/unified-search/components/unified-hit/helpers/render-highlight-array-html.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* Placeholder function to render some highlighted information. | ||
* | ||
* We'll replace this with something properly usable in a future pass | ||
* to the "All" tab work for unified search. | ||
*/ | ||
export function renderHighlightArrayHtml(facet, matchesOnly = false) { | ||
return (facet || []) | ||
.filter((entry) => { | ||
if (matchesOnly) { | ||
return entry.matchLevel !== 'none' | ||
} else { | ||
return true | ||
} | ||
}) | ||
.map((entry) => { | ||
return entry?.value | ||
}) | ||
.join(', ') | ||
} |
Oops, something went wrong.
0263405
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
dev-portal – ./
dev-portal-git-main-hashicorp.vercel.app
docs.hashicorp.com
dev-portal-hashicorp.vercel.app
developer.hashicorp.com