Skip to content

Commit f054a04

Browse files
committed
#RI-6222 - fix auto-suggest at first column
* start refactoring
1 parent 43ba936 commit f054a04

File tree

8 files changed

+130
-30
lines changed

8 files changed

+130
-30
lines changed

redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useEffect, useRef, useState } from 'react'
1+
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
33
import { compact, first } from 'lodash'
44
import cx from 'classnames'
@@ -32,7 +32,7 @@ import { addOwnTokenToArgs, findCurrentArgument, } from 'uiSrc/pages/workbench/u
3232
import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco'
3333
import { CursorContext } from 'uiSrc/pages/workbench/types'
3434
import { asSuggestionsRef, getCommandsSuggestions, isIndexComplete } from 'uiSrc/pages/workbench/utils/suggestions'
35-
import { COMMANDS_TO_GET_INDEX_INFO, COMPOSITE_ARGS, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants'
35+
import { COMMANDS_TO_GET_INDEX_INFO, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants'
3636
import { useDebouncedEffect } from 'uiSrc/services'
3737
import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch'
3838
import { findSuggestionsByArg } from 'uiSrc/pages/workbench/utils/searchSuggestions'
@@ -106,7 +106,15 @@ const Query = (props: Props) => {
106106
const monacoObjects = useRef<Nullable<IEditorMount>>(null)
107107

108108
// TODO: need refactor to avoid this
109-
const REDIS_COMMANDS = commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) }))
109+
const REDIS_COMMANDS = useMemo(
110+
() => commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) })),
111+
[commands]
112+
)
113+
114+
const COMPOSITE_ARGS = useMemo(() => commands
115+
.filter((command) => command.name && command.name.includes(' '))
116+
.map(({ name }) => name),
117+
[commands])
110118

111119
const { instanceId = '' } = useParams<{ instanceId: string }>()
112120

@@ -329,7 +337,13 @@ const Query = (props: Props) => {
329337
return
330338
}
331339

332-
const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY, COMPOSITE_ARGS)
340+
const command = findCompleteQuery(
341+
model,
342+
e.position,
343+
REDIS_COMMANDS_SPEC,
344+
REDIS_COMMANDS_ARRAY,
345+
COMPOSITE_ARGS as string[]
346+
)
333347
handleSuggestions(editor, command)
334348
handleDslSyntax(e, command)
335349
}
@@ -539,7 +553,7 @@ const Query = (props: Props) => {
539553
if (position.column === 1) {
540554
helpWidgetRef.current.isOpen = false
541555
if (command) return asSuggestionsRef([])
542-
return asSuggestionsRef(getCommandsSuggestions(commands, range), false)
556+
return asSuggestionsRef(getCommandsSuggestions(commands, range), false, false)
543557
}
544558

545559
if (!command) {
@@ -569,7 +583,8 @@ const Query = (props: Props) => {
569583
helpWidgetRef.current = {
570584
isOpen,
571585
parent: parent || helpWidgetRef.current.parent,
572-
currentArg: currentArg || helpWidgetRef.current.currentArg }
586+
currentArg: currentArg || helpWidgetRef.current.currentArg
587+
}
573588
}
574589

575590
return suggestions

redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from 'react'
1+
import React, { useEffect, useMemo } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
33
import { EuiLoadingContent } from '@elastic/eui'
44

@@ -40,7 +40,10 @@ const QueryWrapper = (props: Props) => {
4040
const { data: indexes = [] } = useSelector(redisearchListSelector)
4141
const { spec: COMMANDS_SPEC } = useSelector(appRedisCommandsSelector)
4242

43-
const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC)
43+
const REDIS_COMMANDS = useMemo(
44+
() => mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC),
45+
[COMMANDS_SPEC, SEARCH_COMMANDS_SPEC]
46+
)
4447

4548
const dispatch = useDispatch()
4649

redisinsight/ui/src/pages/workbench/constants.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,6 @@ export const COMMANDS_WITHOUT_INDEX_PROPOSE = [
8383
'FT.CREATE'
8484
]
8585

86-
export const COMPOSITE_ARGS = [
87-
'LOAD *',
88-
'FT.CONFIG GET',
89-
'FT.CONFIG SET',
90-
'FT.CURSOR DEL',
91-
'FT.CURSOR READ',
92-
]
93-
9486
export enum DefinedArgumentName {
9587
index = 'index',
9688
query = 'query',

redisinsight/ui/src/pages/workbench/utils/query.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { findLastIndex, isNumber, toNumber } from 'lodash'
44
import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils'
55
import { CommandProvider, IRedisCommand, IRedisCommandTree, ICommandTokenType } from 'uiSrc/constants'
6+
import { isStringsEqual } from 'uiSrc/pages/workbench/utils/queryUtils'
67
import { ArgName, FoundCommandArgument } from '../types'
78

89
export const findCurrentArgument = (
@@ -20,8 +21,7 @@ export const findCurrentArgument = (
2021
return findCurrentArgument(currentArg.arguments, prev.slice(i), prev, currentWithParent)
2122
}
2223

23-
const tokenIndex = args.findIndex((cArg) =>
24-
cArg.token?.toLowerCase() === arg.toLowerCase())
24+
const tokenIndex = args.findIndex((cArg) => isStringsEqual(cArg.token, arg))
2525
const token = args[tokenIndex]
2626

2727
if (token) {
@@ -79,9 +79,9 @@ const findStopArgumentInQuery = (
7979
}
8080

8181
if (!isBlockedOnCommand && currentCommandArg?.optional) {
82-
const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase()
82+
const isNotToken = currentCommandArg?.token && !isStringsEqual(currentCommandArg.token, arg)
8383
const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === ICommandTokenType.OneOf
84-
&& currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase())
84+
&& currentCommandArg?.arguments?.every(({ token }) => !isStringsEqual(token, arg))
8585

8686
if (isNotToken || isNotOneOfToken) {
8787
moveToNextCommandArg()
@@ -99,8 +99,8 @@ const findStopArgumentInQuery = (
9999
blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat()
100100
}
101101

102-
const currentQueryArg = queryArgs.slice(i)?.[0]?.toUpperCase()
103-
const isBlockHasToken = blockArguments?.[0]?.token === currentQueryArg
102+
const currentQueryArg = queryArgs.slice(i)?.[0]
103+
const isBlockHasToken = isStringsEqual(blockArguments?.[0]?.token, currentQueryArg)
104104

105105
if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) {
106106
blockArguments.unshift({
@@ -132,7 +132,7 @@ const findStopArgumentInQuery = (
132132
}
133133

134134
// if we are on token - that requires one more argument
135-
if (currentCommandArg?.token === arg.toUpperCase()) {
135+
if (isStringsEqual(currentCommandArg?.token, arg)) {
136136
blockCommand()
137137
continue
138138
}
@@ -153,7 +153,7 @@ const findStopArgumentInQuery = (
153153

154154
if (currentCommandArg?.type === ICommandTokenType.OneOf && currentCommandArg?.optional) {
155155
// if oneof is optional then we can switch to another argument
156-
if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) {
156+
if (!currentCommandArg?.arguments?.some(({ token }) => isStringsEqual(token, arg))) {
157157
moveToNextCommandArg()
158158
}
159159

@@ -303,7 +303,7 @@ export const getAllRestArguments = (
303303
const currentToken = current?.type === ICommandTokenType.Block ? current?.arguments?.[0].token : current?.token
304304
const lastTokenIndex = findLastIndex(
305305
untilTokenArgs,
306-
(arg) => arg?.toLowerCase() === currentToken?.toLowerCase()
306+
(arg) => isStringsEqual(arg, currentToken)
307307
)
308308
const currentLvlNextArgs = removeNotSuggestedArgs(
309309
untilTokenArgs.slice(lastTokenIndex > 0 ? lastTokenIndex : 0),
@@ -331,7 +331,7 @@ export const removeNotSuggestedArgs = (args: string[], commandArgs: IRedisComman
331331
if (arg.type === ICommandTokenType.OneOf) {
332332
return !args
333333
.some((queryArg) => arg.arguments
334-
?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase()))
334+
?.some((oneOfArg) => isStringsEqual(oneOfArg.token, queryArg)))
335335
}
336336

337337
if (arg.type === ICommandTokenType.Block) {
@@ -373,8 +373,8 @@ export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedi
373373
export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe<IRedisCommand> =>
374374
list.find((cArg) =>
375375
(cArg.type === ICommandTokenType.OneOf
376-
? cArg.arguments?.some((oneOfArg: IRedisCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase())
377-
: cArg.arguments?.[0]?.token?.toLowerCase() === arg?.toLowerCase()))
376+
? cArg.arguments?.some((oneOfArg: IRedisCommand) => isStringsEqual(oneOfArg?.token, arg))
377+
: isStringsEqual(cArg.arguments?.[0].token, arg)))
378378

379379
export const generateDetail = (command: Maybe<IRedisCommand>) => {
380380
if (!command) return ''
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants'
2+
import { Maybe } from 'uiSrc/utils'
3+
4+
export const isStringsEqual = (str1?: string, str2?: string) => str1?.toLowerCase() === str2?.toLowerCase()
5+
6+
export const isTokenEqualsArg = (token: IRedisCommand, arg: string) => {
7+
if (token.type === ICommandTokenType.OneOf) {
8+
return token.arguments
9+
?.some((oneOfArg: IRedisCommand) => isStringsEqual(oneOfArg?.token, arg))
10+
}
11+
if (isStringsEqual(token.token, arg)) return true
12+
if (token.type === ICommandTokenType.Block) return isStringsEqual(token.arguments?.[0]?.token, arg)
13+
return false
14+
}
15+
16+
export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe<IRedisCommand> =>
17+
list.find((command) => isTokenEqualsArg(command, arg))
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* eslint-disable no-continue */
2+
import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants'
3+
import { Maybe } from 'uiSrc/utils'
4+
import { isStringsEqual, isTokenEqualsArg } from 'uiSrc/pages/workbench/utils/queryUtils'
5+
6+
interface BlockTokensTree {
7+
queryArgs: string[]
8+
command?: IRedisCommand
9+
parent?: BlockTokensTree
10+
}
11+
12+
export const findSuggestionsByQueryArgs = (
13+
commands: IRedisCommand[],
14+
queryArgs: string[],
15+
) => {
16+
const firstQueryArg = queryArgs[0]
17+
const scopeCommand = firstQueryArg
18+
? commands.find((command) => isStringsEqual(command.token, firstQueryArg))
19+
: undefined
20+
21+
const getLastBlock = (
22+
args: string[],
23+
command?: IRedisCommand,
24+
parent?: any,
25+
): BlockTokensTree => {
26+
for (let i = args.length - 1; i >= 0; i--) {
27+
const arg = args[i]
28+
const currentArg = findArgByToken(command?.arguments || [], arg)
29+
30+
if (currentArg?.type === ICommandTokenType.Block) {
31+
return getLastBlock(args.slice(i), currentArg, { queryArgs: queryArgs.slice(i), command: currentArg, parent })
32+
}
33+
}
34+
35+
return parent
36+
}
37+
38+
const blockToken: BlockTokensTree = { queryArgs: queryArgs.slice(scopeCommand ? 1 : 0), command: scopeCommand }
39+
const currentBlock = getLastBlock(queryArgs, scopeCommand, blockToken)
40+
const stopArgument = findStopArgumentWithSuggestions(currentBlock)
41+
42+
console.log(stopArgument)
43+
44+
return null
45+
}
46+
47+
const getStopArgument = (
48+
queryArgs: string[],
49+
command: Maybe<IRedisCommand>
50+
) => {
51+
let currentCommandArgIndex = 0
52+
53+
for (let i = 0; i < queryArgs.length; i++) {
54+
const arg = queryArgs[i]
55+
const currentCommandArg = command?.arguments?.[currentCommandArgIndex]
56+
57+
currentCommandArgIndex++
58+
}
59+
60+
return null
61+
}
62+
63+
const findStopArgumentWithSuggestions = (currentBlock: BlockTokensTree) => {
64+
console.log(currentBlock)
65+
const stopArgument = getStopArgument(currentBlock.queryArgs, currentBlock.command)
66+
67+
return null
68+
}
69+
70+
const findArgByToken = (list: IRedisCommand[], arg: string): Maybe<IRedisCommand> =>
71+
list.find((command) => isTokenEqualsArg(command, arg))

redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ const handleCommonSuggestions = (
182182
const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscaped)
183183
if (shouldHideSuggestions) {
184184
return {
185-
helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg },
185+
helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg },
186186
suggestions: asSuggestionsRef([])
187187
}
188188
}

redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { SearchCommand, TokenType } from 'uiSrc/pages/search/types'
22
import { Maybe, splitQueryByArgs } from 'uiSrc/utils'
33
import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands'
44
import { IRedisCommand } from 'uiSrc/constants'
5-
import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants'
65
import {
76
commonfindCurrentArgumentCases,
87
findArgumentftAggreageTests,
@@ -16,6 +15,9 @@ const COMMANDS = Object.keys(MOCKED_REDIS_COMMANDS).map((name) => ({
1615
name,
1716
...MOCKED_REDIS_COMMANDS[name]
1817
}))
18+
const COMPOSITE_ARGS = COMMANDS
19+
.filter((command) => command.name && command.name.includes(' '))
20+
.map(({ name }) => name)
1921

2022
describe('findCurrentArgument', () => {
2123
describe('with list of commands', () => {

0 commit comments

Comments
 (0)