Skip to content

Commit c1c23d7

Browse files
authored
Merge pull request #1912 from RedisInsight/feature/RI-4149-Enhance_syntax_in_auto-completion
Feature/ri 4149 enhance syntax in auto completion
2 parents 38aa64c + d9d4c22 commit c1c23d7

File tree

19 files changed

+1269
-407
lines changed

19 files changed

+1269
-407
lines changed

redisinsight/api/src/__mocks__/commands.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const mockMainCommands = {
44
complexity: 'O(N). Where N is the number of configured users.',
55
since: '6.0.0',
66
group: 'server',
7+
provider: 'main',
78
},
89
};
910

@@ -19,6 +20,7 @@ export const mockRedisearchCommands = {
1920
],
2021
since: '1.0.0',
2122
group: 'search',
23+
provider: 'search',
2224
},
2325
};
2426

@@ -39,6 +41,7 @@ export const mockRedijsonCommands = {
3941
],
4042
since: '1.0.0',
4143
group: 'json',
44+
provider: 'json',
4245
},
4346
};
4447

@@ -102,6 +105,7 @@ export const mockRedistimeseriesCommands = {
102105
],
103106
since: '1.0.0',
104107
group: 'timeseries',
108+
provider: 'timeseries',
105109
},
106110
};
107111

@@ -143,6 +147,7 @@ export const mockRedisaiCommands = {
143147
],
144148
since: '1.2.5',
145149
group: 'tensor',
150+
provider: 'sai',
146151
},
147152
};
148153

@@ -161,6 +166,7 @@ export const mockRedisgraphCommands = {
161166
],
162167
since: '1.0.0',
163168
group: 'graph',
169+
provider: 'graph',
164170
},
165171
};
166172

redisinsight/api/src/modules/commands/commands.service.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { assign } from 'lodash';
1+
import { assign, forEach } from 'lodash';
22
import { Injectable, OnModuleInit } from '@nestjs/common';
33
import { CommandsJsonProvider } from 'src/modules/commands/commands-json.provider';
44

@@ -31,10 +31,15 @@ export class CommandsService implements OnModuleInit {
3131
* Get all commands merged into single object
3232
*/
3333
async getAll(): Promise<any> {
34-
return assign(
35-
{},
36-
...Object.values(await this.getCommandsGroups()),
37-
);
34+
const commands = {};
35+
36+
Object.entries(await this.getCommandsGroups()).forEach(([provider, groupCommands]) => {
37+
return forEach(groupCommands as {}, (value: {}, command) => {
38+
commands[command] = { ...value, provider };
39+
});
40+
});
41+
42+
return commands;
3843
}
3944

4045
async getCommandsGroups(): Promise<any> {

redisinsight/ui/src/components/cli/components/cli-input/CliAutocomplete/CliAutocomplete.spec.tsx

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@ const scanArgs = [
2222
type: 'integer',
2323
},
2424
{
25-
command: 'MATCH',
25+
token: 'MATCH',
2626
name: 'pattern',
2727
type: 'pattern',
2828
optional: true,
2929
},
3030
{
31-
command: 'COUNT',
31+
token: 'COUNT',
3232
name: 'count',
3333
type: 'integer',
3434
optional: true,
3535
},
3636
{
37-
command: 'TYPE',
37+
token: 'TYPE',
3838
name: 'type',
3939
type: 'string',
4040
optional: true,
@@ -79,8 +79,42 @@ describe('CliAutocomplete', () => {
7979
expect(store.getActions().slice(-2)).toEqual(expectedActions)
8080
})
8181

82-
it('Autocomplete should be only with optional args for "scan" command with filled in required args ', () => {
82+
it('Autocomplete should be only with optional args for "scan" command with filled in required args (new realization)', () => {
8383
const autocompleteOptionalText = '[MATCH pattern] [COUNT count] [TYPE type]'
84+
const { queryByTestId } = render(
85+
<CliAutocomplete
86+
{...instance(mockedProps)}
87+
provider="main"
88+
commandName={scanCommand}
89+
arguments={scanArgs}
90+
wordsTyped={2}
91+
/>
92+
)
93+
94+
const autocompleteComponent = queryByTestId(CliAutocompleteTestId)
95+
96+
expect(autocompleteOptionalText).toEqual(autocompleteComponent?.textContent)
97+
})
98+
99+
it('Autocomplete should be only with optional args for "scan" command with filled in required args (old realization)', () => {
100+
const autocompleteOptionalText = '[pattern] [count] [type]'
101+
const { queryByTestId } = render(
102+
<CliAutocomplete
103+
{...instance(mockedProps)}
104+
provider="someprovider"
105+
commandName={scanCommand}
106+
arguments={scanArgs}
107+
wordsTyped={2}
108+
/>
109+
)
110+
111+
const autocompleteComponent = queryByTestId(CliAutocompleteTestId)
112+
113+
expect(autocompleteOptionalText).toEqual(autocompleteComponent?.textContent)
114+
})
115+
116+
it('Autocomplete should be only with optional args for "scan" command with filled in required args (old realization)', () => {
117+
const autocompleteOptionalText = '[pattern] [count] [type]'
84118
const { queryByTestId } = render(
85119
<CliAutocomplete
86120
{...instance(mockedProps)}
@@ -100,6 +134,7 @@ describe('CliAutocomplete', () => {
100134
const { queryByTestId } = render(
101135
<CliAutocomplete
102136
{...instance(mockedProps)}
137+
provider="main"
103138
commandName={scanCommand}
104139
arguments={scanArgs}
105140
wordsTyped={10}

redisinsight/ui/src/components/cli/components/cli-input/CliAutocomplete/CliAutocomplete.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import { setMatchedCommand, clearSearchingCommand } from 'uiSrc/slices/cli/cli-s
99
import styles from './styles.module.scss'
1010

1111
export interface Props {
12+
provider: string;
1213
commandName: string;
1314
wordsTyped: number;
1415
arguments?: ICommandArg[];
1516
}
1617

1718
const CliAutocomplete = (props: Props) => {
18-
const { commandName = '', arguments: args = [], wordsTyped } = props
19+
const { commandName = '', provider = '', arguments: args = [], wordsTyped } = props
1920

2021
const dispatch = useDispatch()
2122

@@ -47,7 +48,7 @@ const CliAutocomplete = (props: Props) => {
4748
}
4849

4950
if (args.length) {
50-
argsList = generateArgsNames(args)
51+
argsList = generateArgsNames(provider, args)
5152

5253
untypedArgs = argsList.slice(getUntypedArgs()).join(' ')
5354
argsList = argsList.join(' ')

redisinsight/ui/src/components/cli/components/cli-input/CliInputWrapper.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useSelector } from 'react-redux'
44
import { getCommandRepeat } from 'uiSrc/utils'
55
import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands'
66
import { outputSelector } from 'uiSrc/slices/cli/cli-output'
7+
import { CommandProvider } from 'uiSrc/constants'
78
import CliAutocomplete from './CliAutocomplete'
89

910
import CliInput from './CliInput'
@@ -26,7 +27,8 @@ const CliInputWrapper = (props: Props) => {
2627
const firstCommandMatch = firstCommand.toUpperCase()
2728
const secondCommandMatch = `${firstCommandMatch} ${secondCommand ? secondCommand.toUpperCase() : null}`
2829

29-
const matchedCmd = ALL_REDIS_COMMANDS[firstCommandMatch] || ALL_REDIS_COMMANDS[secondCommandMatch]
30+
const matchedCmd = ALL_REDIS_COMMANDS[secondCommandMatch] || ALL_REDIS_COMMANDS[firstCommandMatch]
31+
const provider = matchedCmd?.provider || CommandProvider.Unknown
3032
const commandName = !isUndefined(ALL_REDIS_COMMANDS[secondCommandMatch])
3133
? `${firstCommand} ${secondCommand}`
3234
: firstCommand
@@ -42,6 +44,7 @@ const CliInputWrapper = (props: Props) => {
4244
/>
4345
{matchedCmd && (
4446
<CliAutocomplete
47+
provider={provider}
4548
commandName={commandName}
4649
wordsTyped={repeatCommand === 1 ? wordsTyped : wordsTyped - 1}
4750
{...matchedCmd}

redisinsight/ui/src/components/command-helper/CommandHelperWrapper.spec.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ const mockedCommands: IMockedCommands[] = [
5151
{
5252
matchedCommand: 'xgroup',
5353
argStr:
54-
'XGROUP [CREATE key groupname ID|$ [MKSTREAM]] [SETID key groupname ID|$] [DESTROY key groupname] [CREATECONSUMER key groupname consumername] [DELCONSUMER key groupname consumername]',
55-
argListText:
56-
'Arguments:Optional[CREATE key groupname id [MKSTREAM]]Optional[SETID key groupname id]Optional[DESTROY key groupname]Optional[CREATECONSUMER key groupname consumername]Optional[DELCONSUMER key groupname consumername]',
54+
'XGROUP',
55+
argListText: '',
5756
},
5857
{
5958
matchedCommand: 'hset',
@@ -68,28 +67,28 @@ const mockedCommands: IMockedCommands[] = [
6867
{
6968
matchedCommand: 'bitfield',
7069
argStr:
71-
'BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]',
70+
'BITFIELD key [GET encoding offset | [OVERFLOW WRAP | SAT | FAIL] SET encoding offset value | INCRBY encoding offset increment [GET encoding offset | [OVERFLOW WRAP | SAT | FAIL] SET encoding offset value | INCRBY encoding offset increment ...]]',
7271
argListText:
73-
'Arguments:RequiredkeyOptional[GET type offset]Optional[SET type offset value]Optional[INCRBY type offset increment]Optional[OVERFLOW WRAP|SAT|FAIL]',
72+
'Arguments:RequiredkeyMultiple[GET encoding offset | [OVERFLOW WRAP | SAT | FAIL] SET encoding offset value | INCRBY encoding offset increment]',
7473
},
7574
{
7675
matchedCommand: 'client kill',
7776
argStr:
78-
'CLIENT KILL [ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [USER username] [ADDR ip:port] [LADDR ip:port] [SKIPME yes/no]',
77+
'CLIENT KILL ip:port | [ID client-id] | [TYPE NORMAL | MASTER | SLAVE | REPLICA | PUBSUB] | [USER username] | [ADDR ip:port] | [LADDR ip:port] | [SKIPME YES | NO] [[ID client-id] | [TYPE NORMAL | MASTER | SLAVE | REPLICA | PUBSUB] | [USER username] | [ADDR ip:port] | [LADDR ip:port] | [SKIPME YES | NO] ...]',
7978
argListText:
80-
'Arguments:Optional[ip:port]Optional[ID client-id]Optional[TYPE normal|master|slave|pubsub]Optional[USER username]Optional[ADDR ip:port]Optional[LADDR ip:port]Optional[SKIPME yes/no]',
79+
'Arguments:Requiredip:port | [ID client-id] | [TYPE NORMAL | MASTER | SLAVE | REPLICA | PUBSUB] | [USER username] | [ADDR ip:port] | [LADDR ip:port] | [SKIPME YES | NO] [[ID client-id] | [TYPE NORMAL | MASTER | SLAVE | REPLICA | PUBSUB] | [USER username] | [ADDR ip:port] | [LADDR ip:port] | [SKIPME YES | NO] ...]',
8180
},
8281
{
8382
matchedCommand: 'geoadd',
84-
argStr: 'GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]',
83+
argStr: 'GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]',
8584
argListText:
86-
'Arguments:RequiredkeyOptional[condition]Optional[change]Multiplelongitude latitude member',
85+
'Arguments:RequiredkeyOptional[NX | XX]Optional[CH]Multiplelongitude latitude member',
8786
},
8887
{
8988
matchedCommand: 'zadd',
90-
argStr: 'ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]',
89+
argStr: 'ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]',
9190
argListText:
92-
'Arguments:RequiredkeyOptional[condition]Optional[comparison]Optional[change]Optional[increment]Multiplescore member',
91+
'Arguments:RequiredkeyOptional[NX | XX]Optional[GT | LT]Optional[CH]Optional[INCR]Multiplescore member',
9392
},
9493
]
9594

@@ -127,8 +126,10 @@ describe('CliBodyWrapper', () => {
127126

128127
const { unmount } = render(<CommandHelperWrapper />)
129128

130-
expect(screen.getByTestId(cliHelperTestId)).toBeInTheDocument()
131-
expect(screen.getByTestId(argsId)).toHaveTextContent(argListText)
129+
if (argListText) {
130+
expect(screen.getByTestId(cliHelperTestId)).toBeInTheDocument()
131+
expect(screen.getByTestId(argsId)).toHaveTextContent(argListText)
132+
}
132133

133134
unmount()
134135
})

redisinsight/ui/src/components/command-helper/CommandHelperWrapper.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const CommandHelperWrapper = () => {
4949
group = CommandGroup.Generic,
5050
complexity = '',
5151
since = '',
52+
provider,
5253
}: ICommand = ALL_REDIS_COMMANDS[lastMatchedCommand.toUpperCase()] ?? {}
5354

5455
if (isSearching) {
@@ -61,9 +62,9 @@ const CommandHelperWrapper = () => {
6162
})
6263
}
6364

64-
const generatedArgs = generateArgs(args)
65+
const generatedArgs = generateArgs(provider, args)
6566
const complexityShort = getComplexityShortNotation(complexity)
66-
const argString = [lastMatchedCommand.toUpperCase(), ...generateArgsNames(args)].join(' ')
67+
const argString = [lastMatchedCommand.toUpperCase(), ...generateArgsNames(provider, args)].join(' ')
6768

6869
const generateArgData = (arg: ICommandArgGenerated, i: number): ReactElement => {
6970
const type = arg.multiple ? 'Multiple' : arg.optional ? 'Optional' : 'Required'

redisinsight/ui/src/components/command-helper/components/command-helper-search-output/CHSearchOutput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const CHSearchOutput = ({ searchedCommands }: Props) => {
3535
const renderDescription = (command: string) => {
3636
const args = ALL_REDIS_COMMANDS[command].arguments || []
3737
if (args.length) {
38-
const argString = generateArgsNames(args).join(' ')
38+
const argString = generateArgsNames(ALL_REDIS_COMMANDS[command]?.provider, args).join(' ')
3939
return (
4040
<EuiText
4141
size="s"

redisinsight/ui/src/components/command-helper/components/command-helper-search-output/CliSearchOutput.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ const mockedCommands: IMockedCommands[] = [
2727
},
2828
{
2929
matchedCommand: 'GEOADD',
30-
argStr: 'key [NX|XX] [CH] longitude latitude member [longitude latitude member ...]',
30+
argStr: 'key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]',
3131
},
3232
{
3333
matchedCommand: 'ZADD',
34-
argStr: 'key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]',
34+
argStr: 'key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]',
3535
},
3636
{
3737
matchedCommand: 'RESET',

redisinsight/ui/src/constants/commands.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ export interface ICommand {
99
arguments?: ICommandArg[];
1010
since: string;
1111
group: CommandGroup | string;
12+
provider?: string;
13+
}
14+
15+
export enum CommandProvider {
16+
Main = 'main',
17+
Unknown = 'unknown',
1218
}
1319

1420
export interface ICommandArg {

0 commit comments

Comments
 (0)