mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:31:48 +00:00
Search filters: update empty state for dynamic filter searches (#60239)
This commit is contained in:
parent
c470599dce
commit
3e9459c3de
@ -118,6 +118,10 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
telemetryService.log('SearchFiltersApplyFiltersClick')
|
||||
}
|
||||
|
||||
const onAddFilterToQuery = (filter: string): void => {
|
||||
onQueryChange(`${query} ${filter}`)
|
||||
}
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
if (e.altKey && e.key === 'Backspace') {
|
||||
@ -173,6 +177,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={repoFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -182,6 +187,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={languageFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -191,6 +197,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={symbolFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -200,6 +207,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={authorFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -209,6 +217,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={commitDateFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -217,6 +226,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
filters={filters}
|
||||
selectedFilters={selectedFilters}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SearchDynamicFilter
|
||||
@ -226,6 +236,7 @@ export const NewSearchFilters: FC<NewSearchFiltersProps> = ({
|
||||
selectedFilters={selectedFilters}
|
||||
renderItem={utilityFilter}
|
||||
onSelectedFilterChange={handleFilterChange}
|
||||
onAddFilterToQuery={onAddFilterToQuery}
|
||||
/>
|
||||
|
||||
<SyntheticCountFilter
|
||||
@ -339,6 +350,7 @@ const SyntheticCountFilter: FC<SyntheticCountFilterProps> = props => {
|
||||
selectedFilters={selectedCountFilter}
|
||||
renderItem={commitDateFilter}
|
||||
onSelectedFilterChange={handleCountAllFilter}
|
||||
onAddFilterToQuery={() => {}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -67,18 +67,37 @@
|
||||
}
|
||||
|
||||
.description {
|
||||
&-header {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
// margin: 0 0.65rem -0.25rem 0.65rem;
|
||||
background-color: var(--secondary);
|
||||
background-color: var(--secondary-2);
|
||||
color: var(--text-muted);
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.zero-state-search-button {
|
||||
text-decoration: underline;
|
||||
.zero-state-query-button {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
font-size: 0.75rem;
|
||||
padding: 0 0.125rem;
|
||||
border-radius: 3px;
|
||||
background-color: var(--primary-4);
|
||||
font-size: inherit;
|
||||
text-align: unset;
|
||||
color: var(--text-muted);
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
border: none;
|
||||
vertical-align: unset;
|
||||
}
|
||||
|
||||
.zero-state-search-button {
|
||||
text-decoration: underline;
|
||||
display: inline;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
text-align: unset;
|
||||
color: var(--text-muted);
|
||||
font-weight: normal;
|
||||
|
||||
@ -11,6 +11,7 @@ import { SymbolKind } from '@sourcegraph/shared/src/symbols/SymbolKind'
|
||||
import { Button, Icon, H2, H4, Input, LanguageIcon, Code, Tooltip } from '@sourcegraph/wildcard'
|
||||
|
||||
import { codeHostIcon } from '../../../../components'
|
||||
import { SyntaxHighlightedSearchQuery } from '../../../../components/SyntaxHighlightedSearchQuery'
|
||||
import { URLQueryFilter } from '../../hooks'
|
||||
import { DynamicFilterBadge } from '../DynamicFilterBadge'
|
||||
|
||||
@ -48,6 +49,8 @@ interface SearchDynamicFilterProps {
|
||||
* @param nextQuery
|
||||
*/
|
||||
onSelectedFilterChange: (filterKind: Filter['kind'], filters: URLQueryFilter[]) => void
|
||||
|
||||
onAddFilterToQuery: (newFilter: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,6 +64,7 @@ export const SearchDynamicFilter: FC<SearchDynamicFilterProps> = ({
|
||||
selectedFilters,
|
||||
renderItem,
|
||||
onSelectedFilterChange,
|
||||
onAddFilterToQuery,
|
||||
}) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
@ -109,6 +113,12 @@ export const SearchDynamicFilter: FC<SearchDynamicFilterProps> = ({
|
||||
? filteredFilters.slice(0, MAX_FILTERS_NUMBER)
|
||||
: filteredFilters.slice(0, DEFAULT_FILTERS_NUMBER)
|
||||
|
||||
// HACK(camdencheek): we limit the number of filters of each type to 1000, so if we get
|
||||
// exactly 1000 filters, assume that we hit that limit. Ideally, we wouldn't hard-code this
|
||||
// and the backend would tell us whether we hit that limit.
|
||||
const limitHit = filters?.some(filter => !filter.exhaustive) || filters?.length === 1000
|
||||
const suggestedQueryFilter = filterForSearchTerm(searchTerm, filterKind)
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
{title && (
|
||||
@ -139,12 +149,31 @@ export const SearchDynamicFilter: FC<SearchDynamicFilterProps> = ({
|
||||
|
||||
{filtersToShow.length === 0 && (
|
||||
<small className={styles.description}>
|
||||
<b>We couldn’t return a {filterKind} that matched your filter input.</b> Try a more expansive
|
||||
search{' '}
|
||||
<Button onClick={handleZeroStateButtonClick} className={styles.zeroStateSearchButton}>
|
||||
using the search bar
|
||||
</Button>{' '}
|
||||
above.
|
||||
<div className={styles.descriptionHeader}>No matches in search results.</div>
|
||||
{limitHit && suggestedQueryFilter ? (
|
||||
<>
|
||||
Try adding{' '}
|
||||
<Button
|
||||
onClick={() => onAddFilterToQuery(suggestedQueryFilter)}
|
||||
className={styles.zeroStateQueryButton}
|
||||
>
|
||||
<SyntaxHighlightedSearchQuery query={suggestedQueryFilter} />
|
||||
</Button>{' '}
|
||||
to your original search query to narrow results to that repo.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Try expanding your search using the{' '}
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={handleZeroStateButtonClick}
|
||||
className={styles.zeroStateSearchButton}
|
||||
>
|
||||
search bar
|
||||
</Button>{' '}
|
||||
above.
|
||||
</>
|
||||
)}
|
||||
</small>
|
||||
)}
|
||||
</ul>
|
||||
@ -191,6 +220,27 @@ const DynamicFilterItem: FC<DynamicFilterItemProps> = props => {
|
||||
)
|
||||
}
|
||||
|
||||
function filterForSearchTerm(input: string, filterKind: Filter['kind']): string | null {
|
||||
switch (filterKind) {
|
||||
case 'repo': {
|
||||
return `repo:${maybeQuoteString(input)}`
|
||||
}
|
||||
case 'author': {
|
||||
return `author:${maybeQuoteString(input)}`
|
||||
}
|
||||
default: {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function maybeQuoteString(input: string): string {
|
||||
if (input.match(/\s/)) {
|
||||
return `"${input.replaceAll('"', '\\"')}"`
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
function filtersEqual(a: URLQueryFilter, b: URLQueryFilter): boolean {
|
||||
return a.kind === b.kind && a.label === b.label && a.value === b.value
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user