feat(noResults): allow providing URL to report missing results (#1289)
This commit is contained in:
parent
e324f4ce51
commit
2c1fe7c77c
7 changed files with 149 additions and 41 deletions
|
|
@ -42,6 +42,7 @@ export interface DocSearchProps {
|
|||
initialQuery?: string;
|
||||
navigator?: AutocompleteOptions<InternalDocSearchHit>['navigator'];
|
||||
translations?: DocSearchTranslations;
|
||||
getMissingResultsUrl?: ({ query: string }) => string;
|
||||
}
|
||||
|
||||
export function DocSearch(props: DocSearchProps) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export function DocSearchModal({
|
|||
disableUserPersonalization = false,
|
||||
initialQuery: initialQueryFromProp = '',
|
||||
translations = {},
|
||||
getMissingResultsUrl,
|
||||
}: DocSearchModalProps) {
|
||||
const {
|
||||
footer: footerTranslations,
|
||||
|
|
@ -429,6 +430,7 @@ export function DocSearchModal({
|
|||
favoriteSearches={favoriteSearches}
|
||||
inputRef={inputRef}
|
||||
translations={screenStateTranslations}
|
||||
getMissingResultsUrl={getMissingResultsUrl}
|
||||
onItemClick={(item) => {
|
||||
saveRecentSearch(item);
|
||||
onClose();
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import type { InternalDocSearchHit } from './types';
|
|||
export type NoResultsScreenTranslations = Partial<{
|
||||
noResultsText: string;
|
||||
suggestedQueryText: string;
|
||||
openIssueText: string;
|
||||
openIssueLinkText: string;
|
||||
reportMissingResultsText: string;
|
||||
reportMissingResultsLinkText: string;
|
||||
}>;
|
||||
|
||||
type NoResultsScreenProps = Omit<
|
||||
|
|
@ -25,8 +25,8 @@ export function NoResultsScreen({
|
|||
const {
|
||||
noResultsText = 'No results for',
|
||||
suggestedQueryText = 'Try searching for',
|
||||
openIssueText = 'Believe this query should return results?',
|
||||
openIssueLinkText = 'Let us know',
|
||||
reportMissingResultsText = 'Believe this query should return results?',
|
||||
reportMissingResultsLinkText = 'Let us know.',
|
||||
} = translations;
|
||||
const searchSuggestions: string[] | undefined = props.state.context
|
||||
.searchSuggestions as string[];
|
||||
|
|
@ -68,17 +68,18 @@ export function NoResultsScreen({
|
|||
</div>
|
||||
)}
|
||||
|
||||
<p className="DocSearch-Help">
|
||||
{`${openIssueText} `}
|
||||
<a
|
||||
href={`https://github.com/algolia/docsearch-configs/issues/new?template=Missing_results.md&title=[${props.indexName}]+Missing+results+for+query+"${props.state.query}"`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{openIssueLinkText}
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
{props.getMissingResultsUrl && (
|
||||
<p className="DocSearch-Help">
|
||||
{`${reportMissingResultsText} `}
|
||||
<a
|
||||
href={props.getMissingResultsUrl({ query: props.state.query })}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{reportMissingResultsLinkText}
|
||||
</a>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export interface ScreenStateProps<TItem extends BaseItem>
|
|||
disableUserPersonalization: boolean;
|
||||
resultsFooterComponent: DocSearchProps['resultsFooterComponent'];
|
||||
translations: ScreenStateTranslations;
|
||||
getMissingResultsUrl?: DocSearchProps['getMissingResultsUrl'];
|
||||
}
|
||||
|
||||
export const ScreenState = React.memo(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,27 @@ function DocSearch(props: Partial<DocSearchProps>) {
|
|||
return <DocSearchComponent apiKey="foo" indexName="bar" {...props} />;
|
||||
}
|
||||
|
||||
// mock empty response
|
||||
function noResultSearch(_queries: any, _requestOptions?: any): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
resolve({
|
||||
results: [
|
||||
{
|
||||
hits: [],
|
||||
hitsPerPage: 0,
|
||||
nbHits: 0,
|
||||
nbPages: 0,
|
||||
page: 0,
|
||||
processingTimeMS: 0,
|
||||
exhaustiveNbHits: true,
|
||||
params: '',
|
||||
query: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('api', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
|
|
@ -71,40 +92,23 @@ describe('api', () => {
|
|||
it('overrides the default DocSearchModal noResultsScreen text', async () => {
|
||||
render(
|
||||
<DocSearch
|
||||
// mock empty response
|
||||
transformSearchClient={(searchClient) => {
|
||||
return {
|
||||
...searchClient,
|
||||
search: () => {
|
||||
return new Promise((resolve) => {
|
||||
resolve({
|
||||
results: [
|
||||
{
|
||||
hits: [],
|
||||
hitsPerPage: 0,
|
||||
nbHits: 0,
|
||||
nbPages: 0,
|
||||
page: 0,
|
||||
processingTimeMS: 0,
|
||||
exhaustiveNbHits: true,
|
||||
params: '',
|
||||
query: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
},
|
||||
search: noResultSearch,
|
||||
};
|
||||
}}
|
||||
translations={{
|
||||
modal: {
|
||||
noResultsScreen: {
|
||||
noResultsText: 'Pas de résultats pour',
|
||||
openIssueText: 'Ouvrez une issue sur docsearch-configs',
|
||||
openIssueLinkText: 'Lien du repo',
|
||||
reportMissingResultsText:
|
||||
'Ouvrez une issue sur docsearch-configs',
|
||||
reportMissingResultsLinkText: 'Lien du repo',
|
||||
},
|
||||
},
|
||||
}}
|
||||
getMissingResultsUrl={() => 'algolia.com'}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
@ -190,4 +194,68 @@ describe('api', () => {
|
|||
expect(screen.getByText('Selectionner')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMissingResultsUrl', () => {
|
||||
it('does not render the link to the repository by default', async () => {
|
||||
render(
|
||||
<DocSearch
|
||||
transformSearchClient={(searchClient) => {
|
||||
return {
|
||||
...searchClient,
|
||||
search: noResultSearch,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await waitFor(() => {
|
||||
fireEvent.click(document.querySelector('.DocSearch-Button'));
|
||||
});
|
||||
|
||||
fireEvent.input(document.querySelector('.DocSearch-Input'), {
|
||||
target: { value: 'q' },
|
||||
});
|
||||
});
|
||||
|
||||
expect(screen.getByText(/No results for/)).toBeInTheDocument();
|
||||
expect(
|
||||
document.querySelector('.DocSearch-Help a')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('render the link to the repository', async () => {
|
||||
render(
|
||||
<DocSearch
|
||||
transformSearchClient={(searchClient) => {
|
||||
return {
|
||||
...searchClient,
|
||||
search: noResultSearch,
|
||||
};
|
||||
}}
|
||||
getMissingResultsUrl={({ query }) =>
|
||||
`https://github.com/algolia/docsearch/issues/new?title=${query}`
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await waitFor(() => {
|
||||
fireEvent.click(document.querySelector('.DocSearch-Button'));
|
||||
});
|
||||
|
||||
fireEvent.input(document.querySelector('.DocSearch-Input'), {
|
||||
target: { value: 'q' },
|
||||
});
|
||||
});
|
||||
|
||||
expect(screen.getByText(/No results for/)).toBeInTheDocument();
|
||||
|
||||
const link = document.querySelector('.DocSearch-Help a');
|
||||
expect(link).toBeInTheDocument();
|
||||
expect(link.getAttribute('href')).toBe(
|
||||
'https://github.com/algolia/docsearch/issues/new?title=q'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ title: API Reference
|
|||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
:::info
|
||||
|
||||
|
|
@ -160,8 +161,8 @@ const translations: DocSearchTranslations = {
|
|||
noResultsScreen: {
|
||||
noResultsText: 'No results for',
|
||||
suggestedQueryText: 'Try searching for',
|
||||
openIssueText: 'Believe this query should return results?',
|
||||
openIssueLinkText: 'Let us know',
|
||||
reportMissingResultsText: 'Believe this query should return results?',
|
||||
reportMissingResultsLinkText: 'Let us know.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -170,6 +171,23 @@ const translations: DocSearchTranslations = {
|
|||
</div>
|
||||
</details>
|
||||
|
||||
## `getMissingResultsUrl`
|
||||
|
||||
> `type: ({ query: string }) => string` | **optional**
|
||||
|
||||
> example: ({ query }) => `https://github.com/algolia/docsearch/issues/new?title=${query}`
|
||||
|
||||
Function to return the URL of your documentation repository.
|
||||
|
||||
When provided, an informative message wrapped with your link will be displayed on no results searches. The default text can be changed using the [translations](#translations) property.
|
||||
|
||||
<div className="uil-ta-center">
|
||||
<img
|
||||
src={useBaseUrl('img/assets/noResultsScreen.png')}
|
||||
alt="No results screen with informative message"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="react">
|
||||
|
|
@ -299,8 +317,8 @@ const translations: DocSearchTranslations = {
|
|||
noResultsScreen: {
|
||||
noResultsText: 'No results for',
|
||||
suggestedQueryText: 'Try searching for',
|
||||
openIssueText: 'Believe this query should return results?',
|
||||
openIssueLinkText: 'Let us know',
|
||||
reportMissingResultsText: 'Believe this query should return results?',
|
||||
reportMissingResultsLinkText: 'Let us know.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -309,6 +327,23 @@ const translations: DocSearchTranslations = {
|
|||
</div>
|
||||
</details>
|
||||
|
||||
## `getMissingResultsUrl`
|
||||
|
||||
> `type: ({ query: string }) => string` | **optional**
|
||||
|
||||
> example: ({ query }) => `https://github.com/algolia/docsearch/issues/new?title=${query}`
|
||||
|
||||
Function to return the URL of your documentation repository.
|
||||
|
||||
When provided, an informative message wrapped with your link will be displayed on no results searches. The default text can be changed using the [translations](#translations) property.
|
||||
|
||||
<div className="uil-ta-center">
|
||||
<img
|
||||
src={useBaseUrl('img/assets/noResultsScreen.png')}
|
||||
alt="No results screen with informative message"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
|
|
|||
BIN
packages/website/static/img/assets/noResultsScreen.png
Normal file
BIN
packages/website/static/img/assets/noResultsScreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Loading…
Reference in a new issue