-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51633 from software-mansion-labs/kicu/autocomplet…
…e-query-ids Make autocomplete work with entity ids
- Loading branch information
Showing
14 changed files
with
687 additions
and
285 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
src/components/Search/SearchRouter/getQueryWithSubstitutions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; | ||
import * as parser from '@libs/SearchParser/autocompleteParser'; | ||
|
||
type SubstitutionMap = Record<string, string>; | ||
|
||
const getSubstitutionMapKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; | ||
|
||
/** | ||
* Given a plaintext query and a SubstitutionMap object, this function will return a transformed query where: | ||
* - any autocomplete mention in the original query will be substituted with an id taken from `substitutions` object | ||
* - anything that does not match will stay as is | ||
* | ||
* Ex: | ||
* query: `A from:@johndoe A` | ||
* substitutions: { | ||
* from:@johndoe: 9876 | ||
* } | ||
* return: `A from:9876 A` | ||
*/ | ||
function getQueryWithSubstitutions(changedQuery: string, substitutions: SubstitutionMap) { | ||
const parsed = parser.parse(changedQuery) as {ranges: SearchAutocompleteQueryRange[]}; | ||
|
||
const searchAutocompleteQueryRanges = parsed.ranges; | ||
|
||
if (searchAutocompleteQueryRanges.length === 0) { | ||
return changedQuery; | ||
} | ||
|
||
let resultQuery = changedQuery; | ||
let lengthDiff = 0; | ||
|
||
for (const range of searchAutocompleteQueryRanges) { | ||
const itemKey = getSubstitutionMapKey(range.key, range.value); | ||
const substitutionEntry = substitutions[itemKey]; | ||
|
||
if (substitutionEntry) { | ||
const substitutionStart = range.start + lengthDiff; | ||
const substitutionEnd = range.start + range.length; | ||
|
||
// generate new query but substituting "user-typed" value with the entity id/email from substitutions | ||
resultQuery = resultQuery.slice(0, substitutionStart) + substitutionEntry + changedQuery.slice(substitutionEnd); | ||
lengthDiff = lengthDiff + substitutionEntry.length - range.length; | ||
} | ||
} | ||
|
||
return resultQuery; | ||
} | ||
|
||
export {getQueryWithSubstitutions, getSubstitutionMapKey}; | ||
export type {SubstitutionMap}; |
43 changes: 43 additions & 0 deletions
43
src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import type {SearchAutocompleteQueryRange, SearchFilterKey} from '@components/Search/types'; | ||
import * as parser from '@libs/SearchParser/autocompleteParser'; | ||
import type {SubstitutionMap} from './getQueryWithSubstitutions'; | ||
|
||
const getSubstitutionsKey = (filterKey: SearchFilterKey, value: string) => `${filterKey}:${value}`; | ||
|
||
/** | ||
* Given a plaintext query and a SubstitutionMap object, | ||
* this function will remove any substitution keys that do not appear in the query and return an updated object | ||
* | ||
* Ex: | ||
* query: `Test from:John1` | ||
* substitutions: { | ||
* from:SomeOtherJohn: 12345 | ||
* } | ||
* return: {} | ||
*/ | ||
function getUpdatedSubstitutionsMap(query: string, substitutions: SubstitutionMap): SubstitutionMap { | ||
const parsedQuery = parser.parse(query) as {ranges: SearchAutocompleteQueryRange[]}; | ||
|
||
const searchAutocompleteQueryRanges = parsedQuery.ranges; | ||
|
||
if (searchAutocompleteQueryRanges.length === 0) { | ||
return {}; | ||
} | ||
|
||
const autocompleteQueryKeys = searchAutocompleteQueryRanges.map((range) => getSubstitutionsKey(range.key, range.value)); | ||
|
||
// Build a new substitutions map consisting of only the keys from old map, that appear in query | ||
const updatedSubstitutionMap = autocompleteQueryKeys.reduce((map, key) => { | ||
if (substitutions[key]) { | ||
// eslint-disable-next-line no-param-reassign | ||
map[key] = substitutions[key]; | ||
} | ||
|
||
return map; | ||
}, {} as SubstitutionMap); | ||
|
||
return updatedSubstitutionMap; | ||
} | ||
|
||
// eslint-disable-next-line import/prefer-default-export | ||
export {getUpdatedSubstitutionsMap}; |
Oops, something went wrong.