Skip to content

Commit 0934664

Browse files
committed
feat(noResults): allow providing URL to report missing results
1 parent e324f4c commit 0934664

7 files changed

Lines changed: 145 additions & 41 deletions

File tree

packages/docsearch-react/src/DocSearch.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface DocSearchProps {
4242
initialQuery?: string;
4343
navigator?: AutocompleteOptions<InternalDocSearchHit>['navigator'];
4444
translations?: DocSearchTranslations;
45+
reportMissingResultsUrl?: ({ query: string }) => string;
4546
}
4647

4748
export function DocSearch(props: DocSearchProps) {

packages/docsearch-react/src/DocSearchModal.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export function DocSearchModal({
5050
disableUserPersonalization = false,
5151
initialQuery: initialQueryFromProp = '',
5252
translations = {},
53+
reportMissingResultsUrl,
5354
}: DocSearchModalProps) {
5455
const {
5556
footer: footerTranslations,
@@ -429,6 +430,7 @@ export function DocSearchModal({
429430
favoriteSearches={favoriteSearches}
430431
inputRef={inputRef}
431432
translations={screenStateTranslations}
433+
reportMissingResultsUrl={reportMissingResultsUrl}
432434
onItemClick={(item) => {
433435
saveRecentSearch(item);
434436
onClose();

packages/docsearch-react/src/NoResultsScreen.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import type { InternalDocSearchHit } from './types';
77
export type NoResultsScreenTranslations = Partial<{
88
noResultsText: string;
99
suggestedQueryText: string;
10-
openIssueText: string;
11-
openIssueLinkText: string;
10+
reportMissingResultsText: string;
11+
reportMissingResultsLinkText: string;
1212
}>;
1313

1414
type NoResultsScreenProps = Omit<
@@ -25,8 +25,8 @@ export function NoResultsScreen({
2525
const {
2626
noResultsText = 'No results for',
2727
suggestedQueryText = 'Try searching for',
28-
openIssueText = 'Believe this query should return results?',
29-
openIssueLinkText = 'Let us know',
28+
reportMissingResultsText = 'Believe this query should return results?',
29+
reportMissingResultsLinkText = 'Let us know.',
3030
} = translations;
3131
const searchSuggestions: string[] | undefined = props.state.context
3232
.searchSuggestions as string[];
@@ -68,17 +68,18 @@ export function NoResultsScreen({
6868
</div>
6969
)}
7070

71-
<p className="DocSearch-Help">
72-
{`${openIssueText} `}
73-
<a
74-
href={`https://github.com/algolia/docsearch-configs/issues/new?template=Missing_results.md&title=[${props.indexName}]+Missing+results+for+query+"${props.state.query}"`}
75-
target="_blank"
76-
rel="noopener noreferrer"
77-
>
78-
{openIssueLinkText}
79-
</a>
80-
.
81-
</p>
71+
{props.reportMissingResultsUrl && (
72+
<p className="DocSearch-Help">
73+
{`${reportMissingResultsText} `}
74+
<a
75+
href={props.reportMissingResultsUrl({ query: props.state.query })}
76+
target="_blank"
77+
rel="noopener noreferrer"
78+
>
79+
{reportMissingResultsLinkText}
80+
</a>
81+
</p>
82+
)}
8283
</div>
8384
);
8485
}

packages/docsearch-react/src/ScreenState.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface ScreenStateProps<TItem extends BaseItem>
3939
disableUserPersonalization: boolean;
4040
resultsFooterComponent: DocSearchProps['resultsFooterComponent'];
4141
translations: ScreenStateTranslations;
42+
reportMissingResultsUrl?: DocSearchProps['reportMissingResultsUrl'];
4243
}
4344

4445
export const ScreenState = React.memo(

packages/docsearch-react/src/__tests__/api.test.tsx

Lines changed: 90 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ function DocSearch(props: Partial<DocSearchProps>) {
1616
return <DocSearchComponent apiKey="foo" indexName="bar" {...props} />;
1717
}
1818

19+
// mock empty response
20+
function noResultSearch(_queries: any, _requestOptions?: any): Promise<any> {
21+
return new Promise((resolve) => {
22+
resolve({
23+
results: [
24+
{
25+
hits: [],
26+
hitsPerPage: 0,
27+
nbHits: 0,
28+
nbPages: 0,
29+
page: 0,
30+
processingTimeMS: 0,
31+
exhaustiveNbHits: true,
32+
params: '',
33+
query: '',
34+
},
35+
],
36+
});
37+
});
38+
}
39+
1940
describe('api', () => {
2041
beforeEach(() => {
2142
document.body.innerHTML = '';
@@ -71,40 +92,23 @@ describe('api', () => {
7192
it('overrides the default DocSearchModal noResultsScreen text', async () => {
7293
render(
7394
<DocSearch
74-
// mock empty response
7595
transformSearchClient={(searchClient) => {
7696
return {
7797
...searchClient,
78-
search: () => {
79-
return new Promise((resolve) => {
80-
resolve({
81-
results: [
82-
{
83-
hits: [],
84-
hitsPerPage: 0,
85-
nbHits: 0,
86-
nbPages: 0,
87-
page: 0,
88-
processingTimeMS: 0,
89-
exhaustiveNbHits: true,
90-
params: '',
91-
query: '',
92-
},
93-
],
94-
});
95-
});
96-
},
98+
search: noResultSearch,
9799
};
98100
}}
99101
translations={{
100102
modal: {
101103
noResultsScreen: {
102104
noResultsText: 'Pas de résultats pour',
103-
openIssueText: 'Ouvrez une issue sur docsearch-configs',
104-
openIssueLinkText: 'Lien du repo',
105+
reportMissingResultsText:
106+
'Ouvrez une issue sur docsearch-configs',
107+
reportMissingResultsLinkText: 'Lien du repo',
105108
},
106109
},
107110
}}
111+
reportMissingResultsUrl={() => 'algolia.com'}
108112
/>
109113
);
110114

@@ -190,4 +194,68 @@ describe('api', () => {
190194
expect(screen.getByText('Selectionner')).toBeInTheDocument();
191195
});
192196
});
197+
198+
describe('reportMissingResultsUrl', () => {
199+
it('does not render the link to the repository by default', async () => {
200+
render(
201+
<DocSearch
202+
transformSearchClient={(searchClient) => {
203+
return {
204+
...searchClient,
205+
search: noResultSearch,
206+
};
207+
}}
208+
/>
209+
);
210+
211+
await act(async () => {
212+
await waitFor(() => {
213+
fireEvent.click(document.querySelector('.DocSearch-Button'));
214+
});
215+
216+
fireEvent.input(document.querySelector('.DocSearch-Input'), {
217+
target: { value: 'q' },
218+
});
219+
});
220+
221+
expect(screen.getByText(/No results for/)).toBeInTheDocument();
222+
expect(
223+
document.querySelector('.DocSearch-Help a')
224+
).not.toBeInTheDocument();
225+
});
226+
227+
it('render the link to the repository', async () => {
228+
render(
229+
<DocSearch
230+
transformSearchClient={(searchClient) => {
231+
return {
232+
...searchClient,
233+
search: noResultSearch,
234+
};
235+
}}
236+
reportMissingResultsUrl={({ query }) =>
237+
`https://github.com/algolia/docsearch/issues/new?title=${query}`
238+
}
239+
/>
240+
);
241+
242+
await act(async () => {
243+
await waitFor(() => {
244+
fireEvent.click(document.querySelector('.DocSearch-Button'));
245+
});
246+
247+
fireEvent.input(document.querySelector('.DocSearch-Input'), {
248+
target: { value: 'q' },
249+
});
250+
});
251+
252+
expect(screen.getByText(/No results for/)).toBeInTheDocument();
253+
254+
const link = document.querySelector('.DocSearch-Help a');
255+
expect(link).toBeInTheDocument();
256+
expect(link.getAttribute('href')).toBe(
257+
'https://github.com/algolia/docsearch/issues/new?title=q'
258+
);
259+
});
260+
});
193261
});

packages/website/docs/api.mdx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ title: API Reference
44

55
import Tabs from '@theme/Tabs';
66
import TabItem from '@theme/TabItem';
7+
import useBaseUrl from '@docusaurus/useBaseUrl';
78

89
:::info
910

@@ -160,8 +161,8 @@ const translations: DocSearchTranslations = {
160161
noResultsScreen: {
161162
noResultsText: 'No results for',
162163
suggestedQueryText: 'Try searching for',
163-
openIssueText: 'Believe this query should return results?',
164-
openIssueLinkText: 'Let us know',
164+
reportMissingResultsText: 'Believe this query should return results?',
165+
reportMissingResultsLinkText: 'Let us know.',
165166
},
166167
},
167168
};
@@ -170,6 +171,21 @@ const translations: DocSearchTranslations = {
170171
</div>
171172
</details>
172173

174+
## `reportMissingResultsUrl`
175+
176+
> `type: string` | **optional**
177+
178+
URL of your documentation repository.
179+
180+
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.
181+
182+
<div className="uil-ta-center">
183+
<img
184+
src={useBaseUrl('img/assets/noResultsScreen.png')}
185+
alt="No results screen with informative message"
186+
/>
187+
</div>
188+
173189
</TabItem>
174190

175191
<TabItem value="react">
@@ -299,8 +315,8 @@ const translations: DocSearchTranslations = {
299315
noResultsScreen: {
300316
noResultsText: 'No results for',
301317
suggestedQueryText: 'Try searching for',
302-
openIssueText: 'Believe this query should return results?',
303-
openIssueLinkText: 'Let us know',
318+
reportMissingResultsText: 'Believe this query should return results?',
319+
reportMissingResultsLinkText: 'Let us know.',
304320
},
305321
},
306322
};
@@ -309,6 +325,21 @@ const translations: DocSearchTranslations = {
309325
</div>
310326
</details>
311327

328+
## `reportMissingResultsUrl`
329+
330+
> `type: string` | **optional**
331+
332+
URL of your documentation repository.
333+
334+
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.
335+
336+
<div className="uil-ta-center">
337+
<img
338+
src={useBaseUrl('img/assets/noResultsScreen.png')}
339+
alt="No results screen with informative message"
340+
/>
341+
</div>
342+
312343
</TabItem>
313344

314345
</Tabs>
41.4 KB
Loading

0 commit comments

Comments
 (0)