Skip to content

Commit

Permalink
feat(noResults): allow providing URL to report missing results (#1289)
Browse files Browse the repository at this point in the history
  • Loading branch information
shortcuts committed Feb 2, 2022
1 parent e324f4c commit 2c1fe7c
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 41 deletions.
1 change: 1 addition & 0 deletions packages/docsearch-react/src/DocSearch.tsx
Expand Up @@ -42,6 +42,7 @@ export interface DocSearchProps {
initialQuery?: string;
navigator?: AutocompleteOptions<InternalDocSearchHit>['navigator'];
translations?: DocSearchTranslations;
getMissingResultsUrl?: ({ query: string }) => string;
}

export function DocSearch(props: DocSearchProps) {
Expand Down
2 changes: 2 additions & 0 deletions packages/docsearch-react/src/DocSearchModal.tsx
Expand Up @@ -50,6 +50,7 @@ export function DocSearchModal({
disableUserPersonalization = false,
initialQuery: initialQueryFromProp = '',
translations = {},
getMissingResultsUrl,
}: DocSearchModalProps) {
const {
footer: footerTranslations,
Expand Down Expand Up @@ -429,6 +430,7 @@ export function DocSearchModal({
favoriteSearches={favoriteSearches}
inputRef={inputRef}
translations={screenStateTranslations}
getMissingResultsUrl={getMissingResultsUrl}
onItemClick={(item) => {
saveRecentSearch(item);
onClose();
Expand Down
31 changes: 16 additions & 15 deletions packages/docsearch-react/src/NoResultsScreen.tsx
Expand Up @@ -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<
Expand All @@ -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[];
Expand Down Expand Up @@ -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>
);
}
1 change: 1 addition & 0 deletions packages/docsearch-react/src/ScreenState.tsx
Expand Up @@ -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(
Expand Down
112 changes: 90 additions & 22 deletions packages/docsearch-react/src/__tests__/api.test.tsx
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -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'}
/>
);

Expand Down Expand Up @@ -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'
);
});
});
});
43 changes: 39 additions & 4 deletions packages/website/docs/api.mdx
Expand Up @@ -4,6 +4,7 @@ title: API Reference

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

:::info

Expand Down Expand Up @@ -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.',
},
},
};
Expand All @@ -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">
Expand Down Expand Up @@ -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.',
},
},
};
Expand All @@ -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>
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2c1fe7c

Please sign in to comment.