mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:51:57 +00:00
Search: Add initial keyword search toggle (#59779)
This change adds a simple toggle to enable/ disable keyword search, and removes the prototype toggle called "Precise (NEW)". It also removes the smart search toggle, since smart search doesn't pair well with the new keyword search behavior. When the feature is disabled, we revert to the old UI and defaults (smart search is still present, and we default to the 'standard' patterntype). This helps mitigate risk for the initial release, since we can always disable the change completely. The toggle behaves like other toggles in the nav bar: the setting sticks unless the user opens a new tab or refreshes the page. Then it reverts back, defaulting to "keyword search".
This commit is contained in:
parent
84235b58d8
commit
cfa1faeefc
@ -116,9 +116,9 @@ ts_project(
|
||||
"src/search-ui/input/experimental/placeholder.ts",
|
||||
"src/search-ui/input/experimental/suggestionsExtension.ts",
|
||||
"src/search-ui/input/experimental/utils.ts",
|
||||
"src/search-ui/input/toggles/LegacyToggles.tsx",
|
||||
"src/search-ui/input/toggles/QueryInputToggle.tsx",
|
||||
"src/search-ui/input/toggles/SmartSearchToggle.tsx",
|
||||
"src/search-ui/input/toggles/SmartSearchToggleExtended.tsx",
|
||||
"src/search-ui/input/toggles/Toggles.tsx",
|
||||
"src/search-ui/input/toggles/index.ts",
|
||||
"src/search-ui/results/AnnotatedSearchExample.tsx",
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
import { getGlobalSearchContextFilter } from '@sourcegraph/shared/src/search/query/query'
|
||||
import { omitFilter } from '@sourcegraph/shared/src/search/query/transformer'
|
||||
import type { fetchStreamSuggestions as defaultFetchStreamSuggestions } from '@sourcegraph/shared/src/search/suggestions'
|
||||
import { useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
|
||||
import type { RecentSearch } from '@sourcegraph/shared/src/settings/temporary/recentSearches'
|
||||
import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
@ -22,7 +23,8 @@ import { SearchButton } from './SearchButton'
|
||||
import { SearchContextDropdown } from './SearchContextDropdown'
|
||||
import { SearchHelpDropdownButton } from './SearchHelpDropdownButton'
|
||||
import { SearchHistoryDropdown } from './SearchHistoryDropdown'
|
||||
import { Toggles, type TogglesProps } from './toggles'
|
||||
import { LegacyToggles } from './toggles'
|
||||
import { Toggles, type TogglesProps } from './toggles/Toggles'
|
||||
|
||||
import styles from './SearchBox.module.scss'
|
||||
|
||||
@ -117,6 +119,8 @@ export const SearchBox: FC<SearchBoxProps> = props => {
|
||||
})
|
||||
}, [recentSearches, selectedSearchContextSpec])
|
||||
|
||||
const showKeywordSearchToggle = useExperimentalFeatures(features => features.keywordSearch)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
@ -185,19 +189,33 @@ export const SearchBox: FC<SearchBoxProps> = props => {
|
||||
searchHistory={recentSearchesWithoutSearchContext}
|
||||
onSelectSearchFromHistory={onInlineSearchHistorySelect}
|
||||
/>
|
||||
<Toggles
|
||||
patternType={props.patternType}
|
||||
setPatternType={props.setPatternType}
|
||||
caseSensitive={props.caseSensitive}
|
||||
setCaseSensitivity={props.setCaseSensitivity}
|
||||
searchMode={props.searchMode}
|
||||
setSearchMode={props.setSearchMode}
|
||||
submitSearch={props.submitSearchOnToggle}
|
||||
navbarSearchQuery={queryState.query}
|
||||
className={styles.searchBoxToggles}
|
||||
structuralSearchDisabled={props.structuralSearchDisabled}
|
||||
showExtendedPicker={props.showExtendedPicker}
|
||||
/>
|
||||
{showKeywordSearchToggle ? (
|
||||
<Toggles
|
||||
patternType={props.patternType}
|
||||
setPatternType={props.setPatternType}
|
||||
caseSensitive={props.caseSensitive}
|
||||
setCaseSensitivity={props.setCaseSensitivity}
|
||||
searchMode={props.searchMode}
|
||||
setSearchMode={props.setSearchMode}
|
||||
submitSearch={props.submitSearchOnToggle}
|
||||
navbarSearchQuery={queryState.query}
|
||||
className={styles.searchBoxToggles}
|
||||
structuralSearchDisabled={props.structuralSearchDisabled}
|
||||
/>
|
||||
) : (
|
||||
<LegacyToggles
|
||||
patternType={props.patternType}
|
||||
setPatternType={props.setPatternType}
|
||||
caseSensitive={props.caseSensitive}
|
||||
setCaseSensitivity={props.setCaseSensitivity}
|
||||
searchMode={props.searchMode}
|
||||
setSearchMode={props.setSearchMode}
|
||||
submitSearch={props.submitSearchOnToggle}
|
||||
navbarSearchQuery={queryState.query}
|
||||
className={styles.searchBoxToggles}
|
||||
structuralSearchDisabled={props.structuralSearchDisabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.searchBoxButton}>
|
||||
|
||||
186
client/branded/src/search-ui/input/toggles/LegacyToggles.tsx
Normal file
186
client/branded/src/search-ui/input/toggles/LegacyToggles.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
import { mdiCodeBrackets, mdiFormatLetterCase, mdiRegex } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import {
|
||||
type CaseSensitivityProps,
|
||||
type SearchPatternTypeMutationProps,
|
||||
type SubmitSearchProps,
|
||||
SearchMode,
|
||||
type SearchModeProps,
|
||||
type SearchPatternTypeProps,
|
||||
} from '@sourcegraph/shared/src/search'
|
||||
import { findFilter, FilterKind } from '@sourcegraph/shared/src/search/query/query'
|
||||
|
||||
import { QueryInputToggle } from './QueryInputToggle'
|
||||
import { SmartSearchToggle } from './SmartSearchToggle'
|
||||
|
||||
import styles from './Toggles.module.scss'
|
||||
|
||||
export interface LegacyTogglesProps
|
||||
extends SearchPatternTypeProps,
|
||||
SearchPatternTypeMutationProps,
|
||||
CaseSensitivityProps,
|
||||
SearchModeProps,
|
||||
Partial<Pick<SubmitSearchProps, 'submitSearch'>> {
|
||||
navbarSearchQuery: string
|
||||
className?: string
|
||||
showSmartSearchButton?: boolean
|
||||
/**
|
||||
* If set to false makes all buttons non-actionable. The main use case for
|
||||
* this prop is showing the toggles in examples. This is different from
|
||||
* being disabled, because the buttons still render normally.
|
||||
*/
|
||||
interactive?: boolean
|
||||
/** Comes from JSContext only set in the web app. */
|
||||
structuralSearchDisabled?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggles displayed in the query input.
|
||||
*
|
||||
* @deprecated This component is only used when the 'keyword search' language update
|
||||
* is disabled, and will be removed in a follow-up release.
|
||||
*/
|
||||
export const LegacyToggles: React.FunctionComponent<React.PropsWithChildren<LegacyTogglesProps>> = (
|
||||
props: LegacyTogglesProps
|
||||
) => {
|
||||
const {
|
||||
navbarSearchQuery,
|
||||
patternType,
|
||||
setPatternType,
|
||||
caseSensitive,
|
||||
setCaseSensitivity,
|
||||
searchMode,
|
||||
setSearchMode,
|
||||
className,
|
||||
submitSearch,
|
||||
showSmartSearchButton = true,
|
||||
structuralSearchDisabled,
|
||||
} = props
|
||||
|
||||
const submitOnToggle = useCallback(
|
||||
(
|
||||
args:
|
||||
| { newPatternType: SearchPatternType }
|
||||
| { newCaseSensitivity: boolean }
|
||||
| { newPowerUser: boolean }
|
||||
| { newSearchMode: SearchMode }
|
||||
): void => {
|
||||
submitSearch?.({
|
||||
source: 'filter',
|
||||
patternType: 'newPatternType' in args ? args.newPatternType : patternType,
|
||||
caseSensitive: 'newCaseSensitivity' in args ? args.newCaseSensitivity : caseSensitive,
|
||||
searchMode: 'newSearchMode' in args ? args.newSearchMode : searchMode,
|
||||
})
|
||||
},
|
||||
[caseSensitive, patternType, searchMode, submitSearch]
|
||||
)
|
||||
|
||||
const toggleCaseSensitivity = useCallback((): void => {
|
||||
const newCaseSensitivity = !caseSensitive
|
||||
setCaseSensitivity(newCaseSensitivity)
|
||||
submitOnToggle({ newCaseSensitivity })
|
||||
}, [caseSensitive, setCaseSensitivity, submitOnToggle])
|
||||
|
||||
const toggleRegexp = useCallback((): void => {
|
||||
const newPatternType =
|
||||
patternType !== SearchPatternType.regexp ? SearchPatternType.regexp : SearchPatternType.standard
|
||||
|
||||
setPatternType(newPatternType)
|
||||
submitOnToggle({ newPatternType })
|
||||
}, [patternType, setPatternType, submitOnToggle])
|
||||
|
||||
const toggleStructuralSearch = useCallback((): void => {
|
||||
const newPatternType: SearchPatternType =
|
||||
patternType !== SearchPatternType.structural ? SearchPatternType.structural : SearchPatternType.standard
|
||||
|
||||
setPatternType(newPatternType)
|
||||
submitOnToggle({ newPatternType })
|
||||
}, [patternType, setPatternType, submitOnToggle])
|
||||
|
||||
const onSelectSmartSearch = useCallback(
|
||||
(enabled: boolean): void => {
|
||||
const newSearchMode: SearchMode = enabled ? SearchMode.SmartSearch : SearchMode.Precise
|
||||
setSearchMode(newSearchMode)
|
||||
submitOnToggle({ newSearchMode })
|
||||
},
|
||||
[setSearchMode, submitOnToggle]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={classNames(className, styles.toggleContainer)}>
|
||||
<>
|
||||
<QueryInputToggle
|
||||
title="Case sensitivity"
|
||||
isActive={caseSensitive}
|
||||
onToggle={toggleCaseSensitivity}
|
||||
iconSvgPath={mdiFormatLetterCase}
|
||||
interactive={props.interactive}
|
||||
className={`test-case-sensitivity-toggle ${styles.caseSensitivityToggle}`}
|
||||
disableOn={[
|
||||
{
|
||||
condition: findFilter(navbarSearchQuery, 'case', FilterKind.Subexpression) !== undefined,
|
||||
reason: 'Query already contains one or more case subexpressions',
|
||||
},
|
||||
{
|
||||
condition:
|
||||
findFilter(navbarSearchQuery, 'patterntype', FilterKind.Subexpression) !== undefined,
|
||||
reason: 'Query contains one or more patterntype subexpressions, cannot apply global case-sensitivity',
|
||||
},
|
||||
{
|
||||
condition: patternType === SearchPatternType.structural,
|
||||
reason: 'Structural search is always case sensitive',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<QueryInputToggle
|
||||
title="Regular expression"
|
||||
isActive={patternType === SearchPatternType.regexp}
|
||||
onToggle={toggleRegexp}
|
||||
iconSvgPath={mdiRegex}
|
||||
interactive={props.interactive}
|
||||
className={`test-regexp-toggle ${styles.regularExpressionToggle}`}
|
||||
disableOn={[
|
||||
{
|
||||
condition:
|
||||
findFilter(navbarSearchQuery, 'patterntype', FilterKind.Subexpression) !== undefined,
|
||||
reason: 'Query already contains one or more patterntype subexpressions',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<>
|
||||
{!structuralSearchDisabled && (
|
||||
<QueryInputToggle
|
||||
title="Structural search"
|
||||
className={`test-structural-search-toggle ${styles.structuralSearchToggle}`}
|
||||
isActive={patternType === SearchPatternType.structural}
|
||||
onToggle={toggleStructuralSearch}
|
||||
iconSvgPath={mdiCodeBrackets}
|
||||
interactive={props.interactive}
|
||||
disableOn={[
|
||||
{
|
||||
condition:
|
||||
findFilter(navbarSearchQuery, 'patterntype', FilterKind.Subexpression) !==
|
||||
undefined,
|
||||
reason: 'Query already contains one or more patterntype subexpressions',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
{showSmartSearchButton && <div className={styles.separator} />}
|
||||
{showSmartSearchButton && (
|
||||
<SmartSearchToggle
|
||||
className="test-smart-search-toggle"
|
||||
isActive={searchMode === SearchMode.SmartSearch}
|
||||
onSelect={onSelectSmartSearch}
|
||||
interactive={props.interactive}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,171 +0,0 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import { mdiClose, mdiRadioboxBlank, mdiRadioboxMarked, mdiHeart } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
Position,
|
||||
Tooltip,
|
||||
H4,
|
||||
H2,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import type { ToggleProps } from './QueryInputToggle'
|
||||
|
||||
import smartStyles from './SmartSearchToggle.module.scss'
|
||||
import styles from './Toggles.module.scss'
|
||||
|
||||
export const smartSearchIconSvgPath =
|
||||
'M11.3956 20H10.2961L11.3956 13.7778H7.54754C6.58003 13.7778 7.18473 13.1111 7.20671 13.0844C8.62499 11.0578 10.7579 8.03556 13.6054 4H14.7049L13.6054 10.2222H17.4645C17.9042 10.2222 18.1461 10.3911 17.9042 10.8089C13.5615 16.9333 11.3956 20 11.3956 20Z'
|
||||
|
||||
export enum SearchModes {
|
||||
Smart = 'Smart',
|
||||
PreciseNew = 'Precise (NEW) 💖',
|
||||
Precise = 'Precise (legacy)',
|
||||
}
|
||||
|
||||
interface SmartSearchToggleProps extends Omit<ToggleProps, 'title' | 'iconSvgPath' | 'onToggle' | 'isActive'> {
|
||||
onSelect: (mode: SearchModes) => void
|
||||
mode: SearchModes
|
||||
}
|
||||
|
||||
/**
|
||||
* A toggle displayed in the QueryInput.
|
||||
*/
|
||||
export const SmartSearchToggleExtended: React.FunctionComponent<SmartSearchToggleProps> = ({
|
||||
onSelect,
|
||||
interactive = true,
|
||||
mode,
|
||||
className,
|
||||
}) => {
|
||||
const tooltipValue = mode.toString()
|
||||
|
||||
const interactiveProps = interactive ? {} : { tabIndex: -1, 'aria-hidden': true }
|
||||
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<Popover isOpen={isPopoverOpen} onOpenChange={event => setIsPopoverOpen(event.isOpen)}>
|
||||
<Tooltip content={tooltipValue} placement="bottom">
|
||||
<PopoverTrigger
|
||||
as={Button}
|
||||
className={classNames(
|
||||
'a11y-ignore',
|
||||
styles.toggle,
|
||||
smartStyles.button,
|
||||
className,
|
||||
!interactive && styles.toggleNonInteractive,
|
||||
mode !== SearchModes.Precise && styles.toggleActive
|
||||
)}
|
||||
variant="icon"
|
||||
{...interactiveProps}
|
||||
>
|
||||
<Icon
|
||||
aria-label={tooltipValue}
|
||||
svgPath={mode === SearchModes.PreciseNew ? mdiHeart : smartSearchIconSvgPath}
|
||||
// compensate for left margin set on "svg" for the flash symbol
|
||||
className={mode === SearchModes.PreciseNew ? 'ml-0' : ''}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
</Tooltip>
|
||||
|
||||
<SmartSearchToggleMenu onSelect={onSelect} mode={mode} closeMenu={() => setIsPopoverOpen(false)} />
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
const SmartSearchToggleMenu: React.FunctionComponent<
|
||||
Pick<SmartSearchToggleProps, 'onSelect' | 'mode'> & { closeMenu: () => void }
|
||||
> = ({ onSelect, mode, closeMenu }) => {
|
||||
const [getMode, setMode] = useState(mode)
|
||||
useEffect(() => {
|
||||
setMode(mode)
|
||||
}, [mode])
|
||||
|
||||
const onChange = useCallback(
|
||||
(value: SearchModes) => {
|
||||
setMode(value)
|
||||
// Wait a tiny bit for user to see the selection change before closing the popover
|
||||
setTimeout(() => {
|
||||
onSelect(value)
|
||||
closeMenu()
|
||||
}, 100)
|
||||
},
|
||||
[onSelect, closeMenu]
|
||||
)
|
||||
|
||||
return (
|
||||
<PopoverContent
|
||||
aria-labelledby="smart-search-popover-header"
|
||||
position={Position.bottomEnd}
|
||||
className={smartStyles.popoverWindow}
|
||||
>
|
||||
<div className="d-flex justify-content-end px-3 py-2">
|
||||
<H4 as={H2} id="smart-search-popover-header" className="m-0 flex-1">
|
||||
Search Mode Picker
|
||||
</H4>
|
||||
<Button onClick={() => closeMenu()} variant="icon" aria-label="Close">
|
||||
<Icon aria-hidden={true} svgPath={mdiClose} />
|
||||
</Button>
|
||||
</div>
|
||||
<RadioItem
|
||||
value={SearchModes.Smart}
|
||||
header="Smart"
|
||||
description="Suggest variations of your query to find more results that may relate."
|
||||
isChecked={getMode === SearchModes.Smart}
|
||||
onSelect={onChange}
|
||||
/>
|
||||
<RadioItem
|
||||
value={SearchModes.PreciseNew}
|
||||
header="Precise (NEW) 💖"
|
||||
description="Spaces are interpreted as AND."
|
||||
isChecked={getMode === SearchModes.PreciseNew}
|
||||
onSelect={onChange}
|
||||
/>
|
||||
<RadioItem
|
||||
value={SearchModes.Precise}
|
||||
header="Precise (legacy)"
|
||||
description="Spaces are interpreted literaly."
|
||||
isChecked={getMode === SearchModes.Precise}
|
||||
onSelect={onChange}
|
||||
/>
|
||||
</PopoverContent>
|
||||
)
|
||||
}
|
||||
|
||||
const RadioItem: React.FunctionComponent<{
|
||||
value: SearchModes
|
||||
isChecked: boolean
|
||||
onSelect: (value: SearchModes) => void
|
||||
header: string
|
||||
description: string
|
||||
}> = ({ value, isChecked, onSelect, header, description }) => (
|
||||
<Label className={smartStyles.label}>
|
||||
<Input
|
||||
className="sr-only"
|
||||
type="radio"
|
||||
name="smartSearch"
|
||||
value={value.toString()}
|
||||
checked={isChecked}
|
||||
onChange={() => onSelect(value)}
|
||||
/>
|
||||
<Icon
|
||||
svgPath={isChecked ? mdiRadioboxMarked : mdiRadioboxBlank}
|
||||
aria-hidden={true}
|
||||
className={classNames(smartStyles.radioIcon, isChecked && smartStyles.radioIconActive)}
|
||||
inline={false}
|
||||
/>
|
||||
|
||||
<span className="d-flex flex-column">
|
||||
<span className={smartStyles.radioHeader}>{header}</span>
|
||||
<span className={smartStyles.radioDescription}>{description}</span>
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
@ -8,15 +8,12 @@ import {
|
||||
type CaseSensitivityProps,
|
||||
type SearchPatternTypeMutationProps,
|
||||
type SubmitSearchProps,
|
||||
SearchMode,
|
||||
type SearchModeProps,
|
||||
type SearchPatternTypeProps,
|
||||
} from '@sourcegraph/shared/src/search'
|
||||
import { findFilter, FilterKind } from '@sourcegraph/shared/src/search/query/query'
|
||||
|
||||
import { QueryInputToggle } from './QueryInputToggle'
|
||||
import { SmartSearchToggle } from './SmartSearchToggle'
|
||||
import { SmartSearchToggleExtended, SearchModes } from './SmartSearchToggleExtended'
|
||||
|
||||
import styles from './Toggles.module.scss'
|
||||
|
||||
@ -28,12 +25,6 @@ export interface TogglesProps
|
||||
Partial<Pick<SubmitSearchProps, 'submitSearch'>> {
|
||||
navbarSearchQuery: string
|
||||
className?: string
|
||||
showSmartSearchButton?: boolean
|
||||
/**
|
||||
* If set to true, the search mode picker will let the user select the new
|
||||
* pattern type as a new alternative
|
||||
*/
|
||||
showExtendedPicker?: boolean
|
||||
/**
|
||||
* If set to false makes all buttons non-actionable. The main use case for
|
||||
* this prop is showing the toggles in examples. This is different from
|
||||
@ -54,31 +45,20 @@ export const Toggles: React.FunctionComponent<React.PropsWithChildren<TogglesPro
|
||||
setPatternType,
|
||||
caseSensitive,
|
||||
setCaseSensitivity,
|
||||
searchMode,
|
||||
setSearchMode,
|
||||
className,
|
||||
submitSearch,
|
||||
showSmartSearchButton = true,
|
||||
showExtendedPicker = false,
|
||||
structuralSearchDisabled,
|
||||
} = props
|
||||
|
||||
const submitOnToggle = useCallback(
|
||||
(
|
||||
args:
|
||||
| { newPatternType: SearchPatternType }
|
||||
| { newCaseSensitivity: boolean }
|
||||
| { newPowerUser: boolean }
|
||||
| { newSearchMode: SearchMode }
|
||||
): void => {
|
||||
(args: { newPatternType: SearchPatternType } | { newCaseSensitivity: boolean }): void => {
|
||||
submitSearch?.({
|
||||
source: 'filter',
|
||||
patternType: 'newPatternType' in args ? args.newPatternType : patternType,
|
||||
caseSensitive: 'newCaseSensitivity' in args ? args.newCaseSensitivity : caseSensitive,
|
||||
searchMode: 'newSearchMode' in args ? args.newSearchMode : searchMode,
|
||||
})
|
||||
},
|
||||
[caseSensitive, patternType, searchMode, submitSearch]
|
||||
[caseSensitive, patternType, submitSearch]
|
||||
)
|
||||
|
||||
const toggleCaseSensitivity = useCallback((): void => {
|
||||
@ -89,62 +69,20 @@ export const Toggles: React.FunctionComponent<React.PropsWithChildren<TogglesPro
|
||||
|
||||
const toggleRegexp = useCallback((): void => {
|
||||
const newPatternType =
|
||||
patternType !== SearchPatternType.regexp ? SearchPatternType.regexp : SearchPatternType.standard
|
||||
patternType !== SearchPatternType.regexp ? SearchPatternType.regexp : SearchPatternType.keyword
|
||||
|
||||
setPatternType(newPatternType)
|
||||
submitOnToggle({ newPatternType })
|
||||
}, [patternType, setPatternType, submitOnToggle])
|
||||
|
||||
const toggleKeyword = useCallback((): void => {
|
||||
const newPatternType =
|
||||
patternType !== SearchPatternType.keyword ? SearchPatternType.keyword : SearchPatternType.standard
|
||||
|
||||
setPatternType(newPatternType)
|
||||
|
||||
// We always want precise mode when switching to the experimental pattern type.
|
||||
setSearchMode(SearchMode.Precise)
|
||||
|
||||
submitOnToggle({ newPatternType })
|
||||
}, [patternType, setPatternType, submitOnToggle, setSearchMode])
|
||||
|
||||
const toggleStructuralSearch = useCallback((): void => {
|
||||
const newPatternType: SearchPatternType =
|
||||
patternType !== SearchPatternType.structural ? SearchPatternType.structural : SearchPatternType.standard
|
||||
patternType !== SearchPatternType.structural ? SearchPatternType.structural : SearchPatternType.keyword
|
||||
|
||||
setPatternType(newPatternType)
|
||||
submitOnToggle({ newPatternType })
|
||||
}, [patternType, setPatternType, submitOnToggle])
|
||||
|
||||
const onSelectSmartSearch = useCallback(
|
||||
(enabled: boolean): void => {
|
||||
const newSearchMode: SearchMode = enabled ? SearchMode.SmartSearch : SearchMode.Precise
|
||||
|
||||
// Disable the experimental pattern type the user activates smart search
|
||||
if (patternType === SearchPatternType.keyword) {
|
||||
setPatternType(SearchPatternType.standard)
|
||||
}
|
||||
|
||||
setSearchMode(newSearchMode)
|
||||
submitOnToggle({ newSearchMode })
|
||||
},
|
||||
[setSearchMode, submitOnToggle, patternType, setPatternType]
|
||||
)
|
||||
|
||||
// This is hacky and is just for demo purposes. Once we have made the new
|
||||
// pattern type the default we can revert this.
|
||||
const onSelectSearchMode = useCallback(
|
||||
(mode: SearchModes): void => {
|
||||
if (mode === SearchModes.Smart) {
|
||||
onSelectSmartSearch(true)
|
||||
} else if (mode === SearchModes.PreciseNew) {
|
||||
toggleKeyword()
|
||||
} else {
|
||||
onSelectSmartSearch(false)
|
||||
}
|
||||
},
|
||||
[onSelectSmartSearch, toggleKeyword]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={classNames(className, styles.toggleContainer)}>
|
||||
<>
|
||||
@ -206,29 +144,6 @@ export const Toggles: React.FunctionComponent<React.PropsWithChildren<TogglesPro
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
{showSmartSearchButton && <div className={styles.separator} />}
|
||||
{showSmartSearchButton &&
|
||||
(showExtendedPicker ? (
|
||||
<SmartSearchToggleExtended
|
||||
className="test-smart-search-toggle"
|
||||
mode={
|
||||
patternType === SearchPatternType.keyword
|
||||
? SearchModes.PreciseNew
|
||||
: searchMode === SearchMode.SmartSearch
|
||||
? SearchModes.Smart
|
||||
: SearchModes.Precise
|
||||
}
|
||||
onSelect={onSelectSearchMode}
|
||||
interactive={props.interactive}
|
||||
/>
|
||||
) : (
|
||||
<SmartSearchToggle
|
||||
className="test-smart-search-toggle"
|
||||
isActive={searchMode === SearchMode.SmartSearch}
|
||||
onSelect={onSelectSmartSearch}
|
||||
interactive={props.interactive}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './QueryInputToggle'
|
||||
export * from './SmartSearchToggle'
|
||||
export * from './LegacyToggles'
|
||||
export * from './Toggles'
|
||||
|
||||
@ -30,7 +30,6 @@ export const FEATURE_FLAGS = [
|
||||
'enable-sveltekit',
|
||||
'enable-sveltekit-toggle',
|
||||
'search-content-based-lang-detection',
|
||||
'search-keyword',
|
||||
'search-debug',
|
||||
'search-simple',
|
||||
'cody-chat-mock-test',
|
||||
|
||||
@ -8,8 +8,10 @@ import MagnifyIcon from 'mdi-react/MagnifyIcon'
|
||||
import { NavLink, useLocation, useNavigate } from 'react-router-dom'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import { Toggles } from '@sourcegraph/branded'
|
||||
import { LegacyToggles } from '@sourcegraph/branded'
|
||||
import { Toggles } from '@sourcegraph/branded/src/search-ui/input/toggles/Toggles'
|
||||
import { SearchQueryState, SubmitSearchParameters } from '@sourcegraph/shared/src/search'
|
||||
import { useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
|
||||
import { Text, Icon, Button, Modal, Link, ProductStatusBadge, ButtonLink } from '@sourcegraph/wildcard'
|
||||
@ -182,11 +184,7 @@ const NavigationSearchBox: FC<NavigationSearchBoxProps> = props => {
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
|
||||
// If the feature-flag "search-keyword" is set, we allow the user to
|
||||
// choose between precise (legacy), precise (new), and smart search. This
|
||||
// is only temporary for internal testing. The goal is to make the new
|
||||
// precise search the default.
|
||||
const [showExtendedPicker] = useFeatureFlag('search-keyword')
|
||||
const showKeywordSearchToggle = useExperimentalFeatures(features => features.keywordSearch)
|
||||
|
||||
const [isFocused, setFocused] = useState(false)
|
||||
const { searchMode, queryState, searchPatternType, searchCaseSensitivity, setQueryState, submitSearch } =
|
||||
@ -234,18 +232,31 @@ const NavigationSearchBox: FC<NavigationSearchBoxProps> = props => {
|
||||
onChange={setQueryState}
|
||||
onSubmit={submitSearchOnChange}
|
||||
>
|
||||
<Toggles
|
||||
searchMode={searchMode}
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
navbarSearchQuery={queryState.query}
|
||||
structuralSearchDisabled={structuralSearchDisabled}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
setSearchMode={setSearchMode}
|
||||
submitSearch={submitSearchOnChange}
|
||||
showExtendedPicker={showExtendedPicker}
|
||||
/>
|
||||
{showKeywordSearchToggle ? (
|
||||
<Toggles
|
||||
searchMode={searchMode}
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
navbarSearchQuery={queryState.query}
|
||||
structuralSearchDisabled={structuralSearchDisabled}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
setSearchMode={setSearchMode}
|
||||
submitSearch={submitSearchOnChange}
|
||||
/>
|
||||
) : (
|
||||
<LegacyToggles
|
||||
searchMode={searchMode}
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
navbarSearchQuery={queryState.query}
|
||||
structuralSearchDisabled={structuralSearchDisabled}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
setSearchMode={setSearchMode}
|
||||
submitSearch={submitSearchOnChange}
|
||||
/>
|
||||
)}
|
||||
</LazyV2SearchInput>
|
||||
|
||||
{isFocused && <div className={styles.overlay} />}
|
||||
|
||||
@ -3,15 +3,15 @@ import React, { useCallback, useRef, useEffect } from 'react'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import { SearchBox, Toggles } from '@sourcegraph/branded'
|
||||
import { SearchBox, LegacyToggles } from '@sourcegraph/branded'
|
||||
import { Toggles } from '@sourcegraph/branded/src/search-ui/input/toggles/Toggles'
|
||||
import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
|
||||
import type { SearchContextInputProps, SubmitSearchParameters } from '@sourcegraph/shared/src/search'
|
||||
import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { useExperimentalFeatures, type SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { Form } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { AuthenticatedUser } from '../../auth'
|
||||
import { useFeatureFlag } from '../../featureFlags/useFeatureFlag'
|
||||
import { useNavbarQueryState, setSearchCaseSensitivity } from '../../stores'
|
||||
import { type NavbarQueryState, setSearchMode, setSearchPatternType } from '../../stores/navbarSearchQueryState'
|
||||
import { useV2QueryInput } from '../useV2QueryInput'
|
||||
@ -78,11 +78,7 @@ export const SearchNavbarItem: React.FunctionComponent<React.PropsWithChildren<P
|
||||
submitSearchOnChangeRef.current()
|
||||
}, [])
|
||||
|
||||
// If the feature-flag "search-keyword" is set, we allow the user to
|
||||
// choose between precise (legacy), precise (new), and smart search. This
|
||||
// is only temporary for internal testing. The goal is to make the new
|
||||
// precise search the default.
|
||||
const [showExtendedPicker] = useFeatureFlag('search-keyword')
|
||||
const showKeywordSearchToggle = useExperimentalFeatures(features => features.keywordSearch)
|
||||
|
||||
// TODO (#48103): Remove/simplify when new search input is released
|
||||
if (v2QueryInput) {
|
||||
@ -105,18 +101,35 @@ export const SearchNavbarItem: React.FunctionComponent<React.PropsWithChildren<P
|
||||
selectedSearchContextSpec={props.selectedSearchContextSpec}
|
||||
className="flex-grow-1"
|
||||
>
|
||||
<Toggles
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
submitSearch={submitSearchOnChange}
|
||||
structuralSearchDisabled={window.context?.experimentalFeatures?.structuralSearch !== 'enabled'}
|
||||
showExtendedPicker={showExtendedPicker}
|
||||
/>
|
||||
{showKeywordSearchToggle ? (
|
||||
<Toggles
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
submitSearch={submitSearchOnChange}
|
||||
structuralSearchDisabled={
|
||||
window.context?.experimentalFeatures?.structuralSearch !== 'enabled'
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyToggles
|
||||
patternType={searchPatternType}
|
||||
caseSensitive={searchCaseSensitivity}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
submitSearch={submitSearchOnChange}
|
||||
structuralSearchDisabled={
|
||||
window.context?.experimentalFeatures?.structuralSearch !== 'enabled'
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</LazyV2SearchInput>
|
||||
</Form>
|
||||
)
|
||||
@ -147,7 +160,6 @@ export const SearchNavbarItem: React.FunctionComponent<React.PropsWithChildren<P
|
||||
hideHelpButton={false}
|
||||
showSearchHistory={true}
|
||||
recentSearches={recentSearches}
|
||||
showExtendedPicker={showExtendedPicker}
|
||||
/>
|
||||
</Form>
|
||||
)
|
||||
|
||||
@ -22,7 +22,7 @@ import { useFeatureFlag } from '../../featureFlags/useFeatureFlag'
|
||||
import { useFeatureFlagOverrides } from '../../featureFlags/useFeatureFlagOverrides'
|
||||
import type { CodeInsightsProps } from '../../insights/types'
|
||||
import type { OwnConfigProps } from '../../own/OwnConfigProps'
|
||||
import { useDeveloperSettings, useNavbarQueryState } from '../../stores'
|
||||
import { setSearchPatternType, useDeveloperSettings, useNavbarQueryState } from '../../stores'
|
||||
import { submitSearch } from '../helpers'
|
||||
import { useRecentSearches } from '../input/useRecentSearches'
|
||||
|
||||
@ -213,6 +213,26 @@ export const StreamingSearchResults: FC<StreamingSearchResultsProps> = props =>
|
||||
})
|
||||
}, [caseSensitive, location, navigate, props, submittedURLQuery])
|
||||
|
||||
const onTogglePatternType = useCallback(
|
||||
(patternType: SearchPatternType) => {
|
||||
const newPatternType =
|
||||
patternType !== SearchPatternType.keyword ? SearchPatternType.keyword : SearchPatternType.standard
|
||||
const { selectedSearchContextSpec } = props
|
||||
|
||||
setSearchPatternType(newPatternType)
|
||||
submitSearch({
|
||||
historyOrNavigate: navigate,
|
||||
location,
|
||||
selectedSearchContextSpec,
|
||||
caseSensitive,
|
||||
patternType: newPatternType,
|
||||
query: submittedURLQuery,
|
||||
source: 'nav',
|
||||
})
|
||||
},
|
||||
[caseSensitive, location, navigate, props, submittedURLQuery]
|
||||
)
|
||||
|
||||
const hasResultsToAggregate = results?.state === 'complete' ? (results?.results.length ?? 0) > 0 : true
|
||||
const showAggregationPanel = searchAggregationEnabled && hasResultsToAggregate
|
||||
|
||||
@ -226,6 +246,7 @@ export const StreamingSearchResults: FC<StreamingSearchResultsProps> = props =>
|
||||
trace={!!trace}
|
||||
searchContextsEnabled={props.searchContextsEnabled}
|
||||
patternType={patternType}
|
||||
setPatternType={setSearchPatternType}
|
||||
results={results}
|
||||
showAggregationPanel={showAggregationPanel}
|
||||
selectedSearchContextSpec={props.selectedSearchContextSpec}
|
||||
@ -243,6 +264,7 @@ export const StreamingSearchResults: FC<StreamingSearchResultsProps> = props =>
|
||||
onExpandAllResultsToggle={onExpandAllResultsToggle}
|
||||
onSearchAgain={onSearchAgain}
|
||||
onDisableSmartSearch={onDisableSmartSearch}
|
||||
onTogglePatternType={onTogglePatternType}
|
||||
onLogSearchResultClick={logSearchResultClicked}
|
||||
settingsCascade={props.settingsCascade}
|
||||
telemetryService={telemetryService}
|
||||
|
||||
@ -20,7 +20,14 @@ import { FilePrefetcher } from '@sourcegraph/shared/src/components/PrefetchableF
|
||||
import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller'
|
||||
import { HighlightResponseFormat, SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
|
||||
import { QueryState, QueryStateUpdate, QueryUpdate, SearchMode } from '@sourcegraph/shared/src/search'
|
||||
import {
|
||||
QueryState,
|
||||
QueryStateUpdate,
|
||||
QueryUpdate,
|
||||
SearchMode,
|
||||
SearchPatternTypeMutationProps,
|
||||
SearchPatternTypeProps,
|
||||
} from '@sourcegraph/shared/src/search'
|
||||
import { stringHuman } from '@sourcegraph/shared/src/search/query/printer'
|
||||
import { scanSearchQuery } from '@sourcegraph/shared/src/search/query/scanner'
|
||||
import {
|
||||
@ -30,7 +37,7 @@ import {
|
||||
PathMatch,
|
||||
StreamSearchOptions,
|
||||
} from '@sourcegraph/shared/src/search/stream'
|
||||
import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { SettingsCascadeProps, useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { NOOP_TELEMETRY_SERVICE, TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
|
||||
import { Button, Icon, H2, H4, useScrollManager, Panel, useLocalStorage, Link } from '@sourcegraph/wildcard'
|
||||
@ -68,7 +75,9 @@ interface NewSearchContentProps
|
||||
extends TelemetryProps,
|
||||
SettingsCascadeProps,
|
||||
PlatformContextProps,
|
||||
ExtensionsControllerProps {
|
||||
ExtensionsControllerProps,
|
||||
SearchPatternTypeProps,
|
||||
SearchPatternTypeMutationProps {
|
||||
submittedURLQuery: string
|
||||
queryState: QueryState
|
||||
liveQuery: string
|
||||
@ -76,7 +85,6 @@ interface NewSearchContentProps
|
||||
searchMode: SearchMode
|
||||
trace: boolean
|
||||
searchContextsEnabled: boolean
|
||||
patternType: SearchPatternType
|
||||
results: AggregateStreamingSearchResults | undefined
|
||||
showAggregationPanel: boolean
|
||||
selectedSearchContextSpec: string | undefined
|
||||
@ -94,6 +102,7 @@ interface NewSearchContentProps
|
||||
onExpandAllResultsToggle: () => void
|
||||
onSearchAgain: (additionalFilters: string[]) => void
|
||||
onDisableSmartSearch: () => void
|
||||
onTogglePatternType: (patternType: SearchPatternType) => void
|
||||
onLogSearchResultClick: (index: number, type: string, resultsLength: number) => void
|
||||
}
|
||||
|
||||
@ -127,6 +136,7 @@ export const NewSearchContent: FC<NewSearchContentProps> = props => {
|
||||
onExpandAllResultsToggle,
|
||||
onSearchAgain,
|
||||
onDisableSmartSearch,
|
||||
onTogglePatternType,
|
||||
onLogSearchResultClick,
|
||||
} = props
|
||||
|
||||
@ -168,6 +178,8 @@ export const NewSearchContent: FC<NewSearchContentProps> = props => {
|
||||
[onSearchSubmit]
|
||||
)
|
||||
|
||||
const showKeywordSearchToggle = useExperimentalFeatures(features => features.keywordSearch)
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.root, { [styles.rootWithNewFilters]: newFiltersEnabled })}>
|
||||
{newFiltersEnabled && (
|
||||
@ -216,6 +228,8 @@ export const NewSearchContent: FC<NewSearchContentProps> = props => {
|
||||
className={styles.infobar}
|
||||
onExpandAllResultsToggle={onExpandAllResultsToggle}
|
||||
onShowMobileFiltersChanged={setSidebarCollapsed}
|
||||
showKeywordSearchToggle={!!showKeywordSearchToggle}
|
||||
onTogglePatternType={onTogglePatternType}
|
||||
stats={
|
||||
<>
|
||||
<StreamingProgress
|
||||
|
||||
@ -24,6 +24,8 @@ const COMMON_PROPS: Omit<SearchResultsInfoBarProps, 'enableCodeMonitoring'> = {
|
||||
stats: <div />,
|
||||
telemetryService: NOOP_TELEMETRY_SERVICE,
|
||||
patternType: SearchPatternType.standard,
|
||||
showKeywordSearchToggle: false,
|
||||
onTogglePatternType: noop,
|
||||
caseSensitive: false,
|
||||
setSidebarCollapsed: noop,
|
||||
sidebarCollapsed: false,
|
||||
|
||||
@ -4,13 +4,14 @@ import { mdiChevronDoubleDown, mdiChevronDoubleUp, mdiOpenInNew, mdiThumbDown, m
|
||||
import classNames from 'classnames'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
||||
import { Toggle } from '@sourcegraph/branded/src/components/Toggle'
|
||||
import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import type { CaseSensitivityProps, SearchPatternTypeProps } from '@sourcegraph/shared/src/search'
|
||||
import { FilterKind, findFilter } from '@sourcegraph/shared/src/search/query/query'
|
||||
import type { AggregateStreamingSearchResults, StreamSearchOptions } from '@sourcegraph/shared/src/search/stream'
|
||||
import { useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { Alert, Button, Icon, Link, Text, useSessionStorage } from '@sourcegraph/wildcard'
|
||||
import { Alert, Button, Icon, Label, Link, Text, useSessionStorage } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { AuthenticatedUser } from '../../../../auth'
|
||||
import {
|
||||
@ -73,6 +74,9 @@ export interface SearchResultsInfoBarProps
|
||||
isSourcegraphDotCom: boolean
|
||||
patternType: SearchPatternType
|
||||
sourcegraphURL: string
|
||||
|
||||
showKeywordSearchToggle: boolean
|
||||
onTogglePatternType: (patternType: SearchPatternType) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,6 +231,18 @@ export const SearchResultsInfoBar: FC<SearchResultsInfoBarProps> = props => {
|
||||
|
||||
<div className={styles.expander} />
|
||||
|
||||
{props.showKeywordSearchToggle && (
|
||||
<Label className={styles.toggle}>
|
||||
Search language update{' '}
|
||||
<Toggle
|
||||
value={props.patternType === SearchPatternType.keyword}
|
||||
onToggle={() => props.onTogglePatternType(props.patternType)}
|
||||
title="Enable search language update"
|
||||
className="mr-2"
|
||||
/>
|
||||
</Label>
|
||||
)}
|
||||
|
||||
<ul className="nav align-items-center">
|
||||
<SearchActionsMenu
|
||||
authenticatedUser={props.authenticatedUser}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { SearchMode } from '@sourcegraph/shared/src/search'
|
||||
|
||||
import { parseSearchURL } from '../search'
|
||||
|
||||
@ -122,5 +123,20 @@ describe('navbar query state', () => {
|
||||
|
||||
expect(useNavbarQueryState.getState()).toHaveProperty('searchPatternType', SearchPatternType.regexp)
|
||||
})
|
||||
|
||||
it('chooses correct defaults when keyword search is enabled', () => {
|
||||
setQueryStateFromURL(parseSearchURL(''))
|
||||
setQueryStateFromSettings({
|
||||
subjects: [],
|
||||
final: {
|
||||
experimentalFeatures: {
|
||||
keywordSearch: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(useNavbarQueryState.getState()).toHaveProperty('searchMode', SearchMode.Precise)
|
||||
expect(useNavbarQueryState.getState()).toHaveProperty('searchPatternType', SearchPatternType.keyword)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,7 +4,8 @@ import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import type { NavbarQueryState } from 'src/stores/navbarSearchQueryState'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import { SearchBox, Toggles } from '@sourcegraph/branded'
|
||||
import { SearchBox, LegacyToggles } from '@sourcegraph/branded'
|
||||
import { Toggles } from '@sourcegraph/branded/src/search-ui/input/toggles/Toggles'
|
||||
import { TraceSpanProvider } from '@sourcegraph/observability-client'
|
||||
import {
|
||||
type CaseSensitivityProps,
|
||||
@ -15,6 +16,7 @@ import {
|
||||
type SearchModeProps,
|
||||
getUserSearchContextNamespaces,
|
||||
} from '@sourcegraph/shared/src/search'
|
||||
import { useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { Form } from '@sourcegraph/wildcard'
|
||||
|
||||
import { Notices } from '../../../global/Notices'
|
||||
@ -126,6 +128,8 @@ export const SearchPageInput: FC<SearchPageInputProps> = props => {
|
||||
[setQueryState]
|
||||
)
|
||||
|
||||
const showKeywordSearchToggle = useExperimentalFeatures(features => features.keywordSearch)
|
||||
|
||||
// TODO (#48103): Remove/simplify when new search input is released
|
||||
const input = v2QueryInput ? (
|
||||
<LazyV2SearchInput
|
||||
@ -141,18 +145,32 @@ export const SearchPageInput: FC<SearchPageInputProps> = props => {
|
||||
selectedSearchContextSpec={selectedSearchContextSpec}
|
||||
className="flex-grow-1"
|
||||
>
|
||||
<Toggles
|
||||
patternType={patternType}
|
||||
caseSensitive={caseSensitive}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
showSmartSearchButton={false}
|
||||
showExtendedPicker={false}
|
||||
structuralSearchDisabled={window.context?.experimentalFeatures?.structuralSearch !== 'enabled'}
|
||||
/>
|
||||
{showKeywordSearchToggle ? (
|
||||
<Toggles
|
||||
patternType={patternType}
|
||||
caseSensitive={caseSensitive}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
submitSearch={submitSearchOnChange}
|
||||
structuralSearchDisabled={window.context?.experimentalFeatures?.structuralSearch !== 'enabled'}
|
||||
/>
|
||||
) : (
|
||||
<LegacyToggles
|
||||
patternType={patternType}
|
||||
caseSensitive={caseSensitive}
|
||||
setPatternType={setSearchPatternType}
|
||||
setCaseSensitivity={setSearchCaseSensitivity}
|
||||
searchMode={searchMode}
|
||||
setSearchMode={setSearchMode}
|
||||
navbarSearchQuery={queryState.query}
|
||||
submitSearch={submitSearchOnChange}
|
||||
showSmartSearchButton={false}
|
||||
structuralSearchDisabled={window.context?.experimentalFeatures?.structuralSearch !== 'enabled'}
|
||||
/>
|
||||
)}
|
||||
</LazyV2SearchInput>
|
||||
) : (
|
||||
<SearchBox
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { startCase } from 'lodash'
|
||||
|
||||
import { isErrorLike } from '@sourcegraph/common'
|
||||
import type { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { SettingsExperimentalFeatures } from '@sourcegraph/shared/src/schema/settings.schema'
|
||||
import { SearchMode } from '@sourcegraph/shared/src/search'
|
||||
import type { SettingsCascadeOrError, SettingsSubjectCommonFields } from '@sourcegraph/shared/src/settings/settings'
|
||||
|
||||
@ -34,6 +35,12 @@ export function viewerSubjectFromSettings(
|
||||
* configured by the user.
|
||||
*/
|
||||
export function defaultSearchModeFromSettings(settingsCascade: SettingsCascadeOrError): SearchMode | undefined {
|
||||
// When the 'keyword search' language update is enabled, make sure to disable smart search
|
||||
const features = getFromSettings(settingsCascade, 'experimentalFeatures') as SettingsExperimentalFeatures
|
||||
if (features?.keywordSearch) {
|
||||
return SearchMode.Precise
|
||||
}
|
||||
|
||||
switch (getFromSettings(settingsCascade, 'search.defaultMode')) {
|
||||
case 'precise': {
|
||||
return SearchMode.Precise
|
||||
@ -50,6 +57,12 @@ export function defaultSearchModeFromSettings(settingsCascade: SettingsCascadeOr
|
||||
* configured by the user.
|
||||
*/
|
||||
export function defaultPatternTypeFromSettings(settingsCascade: SettingsCascadeOrError): SearchPatternType | undefined {
|
||||
// When the 'keyword search' language update is enabled, default to the 'keyword' patterntype
|
||||
const features = getFromSettings(settingsCascade, 'experimentalFeatures') as SettingsExperimentalFeatures
|
||||
if (features?.keywordSearch) {
|
||||
return SearchPatternType.keyword
|
||||
}
|
||||
|
||||
return getFromSettings(settingsCascade, 'search.defaultPatternType')
|
||||
}
|
||||
|
||||
|
||||
@ -2513,6 +2513,8 @@ type SettingsExperimentalFeatures struct {
|
||||
FuzzyFinderSymbols *bool `json:"fuzzyFinderSymbols,omitempty"`
|
||||
// GoCodeCheckerTemplates description: Shows a panel with code insights templates for go code checker results.
|
||||
GoCodeCheckerTemplates *bool `json:"goCodeCheckerTemplates,omitempty"`
|
||||
// KeywordSearch description: Whether to enable the 'keyword search' language improvement
|
||||
KeywordSearch bool `json:"keywordSearch,omitempty"`
|
||||
// NewSearchNavigationUI description: Enables new experimental search UI navigation
|
||||
NewSearchNavigationUI *bool `json:"newSearchNavigationUI,omitempty"`
|
||||
// NewSearchResultFiltersPanel description: Enables new experimental search results filters panel
|
||||
@ -2583,6 +2585,7 @@ func (v *SettingsExperimentalFeatures) UnmarshalJSON(data []byte) error {
|
||||
delete(m, "fuzzyFinderRepositories")
|
||||
delete(m, "fuzzyFinderSymbols")
|
||||
delete(m, "goCodeCheckerTemplates")
|
||||
delete(m, "keywordSearch")
|
||||
delete(m, "newSearchNavigationUI")
|
||||
delete(m, "newSearchResultFiltersPanel")
|
||||
delete(m, "newSearchResultsUI")
|
||||
|
||||
@ -222,6 +222,11 @@
|
||||
"!go": {
|
||||
"pointer": true
|
||||
}
|
||||
},
|
||||
"keywordSearch": {
|
||||
"description": "Whether to enable the 'keyword search' language improvement",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"group": "Experimental"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user