Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions redisinsight/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export default class MenuBuilder {
{
label: 'License Terms',
click() {
shell.openExternal('https://github.com/RedisInsight/RedisInsight/blob/master/LICENSE');
shell.openExternal('https://github.com/RedisInsight/RedisInsight/blob/main/LICENSE');
},
},
{
Expand Down Expand Up @@ -256,7 +256,7 @@ export default class MenuBuilder {
{
label: 'License Terms',
click() {
shell.openExternal('https://github.com/RedisInsight/RedisInsight/blob/master/LICENSE');
shell.openExternal('https://github.com/RedisInsight/RedisInsight/blob/main/LICENSE');
},
},
{
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/src/assets/img/play_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 44 additions & 46 deletions redisinsight/ui/src/components/query/Query/Query.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { useContext, useEffect } from 'react'
import React, { useContext, useEffect, useRef } from 'react'
import { useSelector } from 'react-redux'
import { findIndex } from 'lodash'
import { decode } from 'html-entities'
import { compact, findIndex } from 'lodash'
import cx from 'classnames'
import { EuiButtonIcon, EuiText, EuiToolTip } from '@elastic/eui'
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'
import MonacoEditor from 'react-monaco-editor'
import { useParams } from 'react-router-dom'

import {
Theme,
Expand All @@ -15,17 +13,17 @@ import {
KEYBOARD_SHORTCUTS,
} from 'uiSrc/constants'
import {
getMultiCommands,
decoration,
geMonacoAction,
getRedisCompletionProvider,
getRedisMonarchTokensProvider,
removeMonacoComments,
splitMonacoValuePerLines
MonacoAction,
Nullable,
toModelDeltaDecoration
} from 'uiSrc/utils'
import { ThemeContext } from 'uiSrc/contexts/themeContext'
import { WBQueryType } from 'uiSrc/pages/workbench/constants'
import { KeyboardShortcut } from 'uiSrc/components'
import { ThemeContext } from 'uiSrc/contexts/themeContext'
import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'

import styles from './styles.module.scss'

Expand All @@ -34,20 +32,26 @@ export interface Props {
loading: boolean;
setQueryEl: Function;
setQuery: (script: string) => void;
onSubmit: (query?: string, historyId?: number, type?: WBQueryType) => void;
onSubmit: (query?: string) => void;
onKeyDown?: (e: React.KeyboardEvent, script: string) => void;
}

interface IEditorMount {
editor: monacoEditor.editor.IStandaloneCodeEditor
monaco: typeof monacoEditor
}

let decorations: string[] = []

const Query = (props: Props) => {
const { query = '', setQuery, onKeyDown, onSubmit, setQueryEl } = props
const { instanceId = '' } = useParams<{ instanceId: string }>()

const {
commandsArray: REDIS_COMMANDS_ARRAY,
spec: REDIS_COMMANDS_SPEC
} = useSelector(appRedisCommandsSelector)
const editorRef = React.createRef<MonacoEditor>()
const { theme } = useContext(ThemeContext)
const monacoObjects = useRef<Nullable<IEditorMount>>(null)
let disposeCompletionItemProvider = () => {}

useEffect(() =>
Expand All @@ -57,6 +61,27 @@ const Query = (props: Props) => {
},
[])

useEffect(() => {
if (!monacoObjects.current) return
const commands = query.split('\n')
const { monaco, editor } = monacoObjects.current
const notCommandRegEx = /^[\s|//]/

const newDecorations = compact(commands.map((command, index) => {
if (!command || notCommandRegEx.test(command)) return null
const lineNumber = index + 1

return toModelDeltaDecoration(
decoration(monaco, `decoration_${lineNumber}`, lineNumber, 1, lineNumber, 1)
)
}))

decorations = editor.deltaDecorations(
decorations,
newDecorations
)
}, [query])

const onChange = (value: string = '') => {
setQuery(value)
}
Expand All @@ -65,50 +90,21 @@ const Query = (props: Props) => {
onKeyDown?.(e, query)
}

const sendEventSubmitTelemetry = (commandInit = query) => {
const eventData = (() => {
const commands = splitMonacoValuePerLines(commandInit)

const [commandLine, ...rest] = commands.map((command = '') => {
const matchedCommand = REDIS_COMMANDS_ARRAY.find((commandName) =>
command.toUpperCase().startsWith(commandName))
return matchedCommand ?? command.split(' ')?.[0]
})
const multiCommands = getMultiCommands(rest)

const command = removeMonacoComments(decode([commandLine, multiCommands].join('\n')).trim())

return {
command,
databaseId: instanceId,
multiple: multiCommands ? 'Multiple' : 'Single'
}
})()

sendEventTelemetry({
event: TelemetryEvent.WORKBENCH_COMMAND_SUBMITTED,
eventData
})
}

const handleSubmit = (value?: string) => {
sendEventSubmitTelemetry(value)

onSubmit(value)
}

const editorDidMount = (
editor: monacoEditor.editor.IStandaloneCodeEditor,
monaco: typeof monacoEditor
) => {
monacoObjects.current = { editor, monaco }

editor.focus()
setQueryEl(editor)

setupMonacoRedisLang(monaco)
editor.addCommand(
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
() => handleSubmit(editor.getValue())
)
editor.addAction(geMonacoAction(MonacoAction.Submit, (editor) => handleSubmit(editor.getValue()), monaco))
}

const setupMonacoRedisLang = (monaco: typeof monacoEditor) => {
Expand All @@ -134,6 +130,8 @@ const Query = (props: Props) => {
padding: { top: 10 },
automaticLayout: true,
formatOnPaste: false,
glyphMargin: true,
lineNumbersMinChars: 4
// fontFamily: 'Inconsolata',
// fontSize: 16,
// minimap: {
Expand All @@ -145,11 +143,11 @@ const Query = (props: Props) => {
<div className={styles.container} onKeyDown={handleKeyDown} role="textbox" tabIndex={0}>
<div className={styles.input} data-testid="query-input-container">
<MonacoEditor
ref={editorRef}
language={MonacoLanguage.Redis}
theme={theme === Theme.Dark ? 'vs-dark' : 'vs-light'}
value={query}
options={options}
className={`${MonacoLanguage.Redis}-editor`}
onChange={onChange}
editorDidMount={editorDidMount}
/>
Expand Down
47 changes: 43 additions & 4 deletions redisinsight/ui/src/components/query/QueryWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react'
import { useSelector } from 'react-redux'
import { EuiLoadingContent } from '@elastic/eui'
import { decode } from 'html-entities'
import { useParams } from 'react-router-dom'

import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands'
import { getMultiCommands, removeMonacoComments, splitMonacoValuePerLines } from 'uiSrc/utils'
import Query from './Query'

import styles from './Query/styles.module.scss'

export interface Props {
Expand All @@ -12,11 +16,46 @@ export interface Props {
setQuery: (script: string) => void;
setQueryEl: Function;
onKeyDown?: (e: React.KeyboardEvent, script: string) => void;
onSubmit: () => void;
onSubmit: (value?: string) => void;
}
const QueryWrapper = (props: Props) => {
const { query = '', loading, setQuery, setQueryEl, onKeyDown, onSubmit } = props
const { loading: isCommandsLoading } = useSelector(appRedisCommandsSelector)
const { instanceId = '' } = useParams<{ instanceId: string }>()
const {
loading: isCommandsLoading,
commandsArray: REDIS_COMMANDS_ARRAY,
} = useSelector(appRedisCommandsSelector)

const sendEventSubmitTelemetry = (commandInit = query) => {
const eventData = (() => {
const commands = splitMonacoValuePerLines(commandInit)

const [commandLine, ...rest] = commands.map((command = '') => {
const matchedCommand = REDIS_COMMANDS_ARRAY.find((commandName) =>
command.toUpperCase().startsWith(commandName))
return matchedCommand ?? command.split(' ')?.[0]
})
const multiCommands = getMultiCommands(rest)

const command = removeMonacoComments(decode([commandLine, multiCommands].join('\n')).trim())

return {
command,
databaseId: instanceId,
multiple: multiCommands ? 'Multiple' : 'Single'
}
})()

sendEventTelemetry({
event: TelemetryEvent.WORKBENCH_COMMAND_SUBMITTED,
eventData
})
}

const handleSubmit = (value?: string) => {
sendEventSubmitTelemetry(value)
onSubmit(value)
}

const Placeholder = (
<div className={styles.containerPlaceholder}>
Expand All @@ -34,7 +73,7 @@ const QueryWrapper = (props: Props) => {
setQuery={setQuery}
setQueryEl={setQueryEl}
onKeyDown={onKeyDown}
onSubmit={onSubmit}
onSubmit={handleSubmit}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
Direction,
Criteria,
EuiBasicTableColumn,
EuiButton,
EuiFlexGroup,
Expand Down Expand Up @@ -44,7 +46,6 @@ function DatabasesList({
}: Props) {
const [columns, setColumns] = useState(first(columnVariations))
const [selection, setSelection] = useState<Instance[]>([])

const [isPopoverOpen, setIsPopoverOpen] = useState(false)

const { loading, data: instances } = useSelector(instancesSelector)
Expand Down Expand Up @@ -112,6 +113,19 @@ function DatabasesList({
}),
})

const onTableChange = ({ sort, page }: Criteria<Instance>) => {
// calls also with page changing
if (sort && !page) {
sendEventSortedTelemetry(sort)
}
}

const sendEventSortedTelemetry = (sort: { field: keyof Instance; direction: Direction }) =>
sendEventTelemetry({
event: TelemetryEvent.CONFIG_DATABASES_DATABASE_LIST_SORTED,
eventData: sort
})

const deleteBtn = (
<EuiButton
onClick={onButtonClick}
Expand Down Expand Up @@ -197,6 +211,7 @@ function DatabasesList({
sorting={{ sort }}
selection={selectionValue}
onWheel={onWheel}
onTableChange={onTableChange}
isSelectable
/>

Expand Down
20 changes: 20 additions & 0 deletions redisinsight/ui/src/styles/base/_monaco.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,23 @@
font-size: 1.6em;
}
}

.monaco-editor.redisLanguage-editor .suggest-icon {
display: none !important;
}

.monaco-glyph-run-command {
color: var(--rsSubmitBtn);
opacity: .5 !important;
margin-left: 10px;

&::before {
content: '';
width: 12px;
height: 12px;
background-image: url('uiSrc/assets/img/play_icon.svg');
background-size: contain;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
}
1 change: 1 addition & 0 deletions redisinsight/ui/src/telemetry/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum TelemetryEvent {
CONFIG_DATABASES_MULTIPLE_DATABASES_DELETE_CLICKED = 'CONFIG_DATABASES_MULTIPLE_DATABASES_DELETE_CLICKED',
CONFIG_DATABASES_DATABASE_EDIT_CLICKED = 'CONFIG_DATABASES_DATABASE_EDIT_CLICKED',
CONFIG_DATABASES_DATABASE_EDIT_CANCELLED_CLICKED = 'CONFIG_DATABASES_DATABASE_EDIT_CANCELLED_CLICKED',
CONFIG_DATABASES_DATABASE_LIST_SORTED = 'CONFIG_DATABASES_DATABASE_LIST_SORTED',
CONFIG_DATABASES_OPEN_DATABASE_BUTTON_CLICKED = 'CONFIG_DATABASES_OPEN_DATABASE_BUTTON_CLICKED',

CONFIG_DATABASES_HOST_PORT_COPIED = 'CONFIG_DATABASES_HOST_PORT_COPIED',
Expand Down
2 changes: 2 additions & 0 deletions redisinsight/ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export * from './formatBytes'
export * from './instanceModules'
export * from './monacoRedisComplitionProvider'
export * from './monacoRedisMonarchTokensProvider'
export * from './monacoActions'
export * from './monacoDecorations'
export * from './handlePlatforms'
export * from './plugins'

Expand Down
22 changes: 22 additions & 0 deletions redisinsight/ui/src/utils/monacoActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as monacoEditor from 'monaco-editor'

export enum MonacoAction {
Submit = 'submit'
}

export const geMonacoAction = (
actionId: MonacoAction,
action: (editor: monacoEditor.editor.IStandaloneCodeEditor, ...args: any[]) => void | Promise<void>,
monaco: typeof monacoEditor,
): monacoEditor.editor.IActionDescriptor => {
if (actionId === MonacoAction.Submit) {
return {
id: 'submit',
label: 'Run Commands',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
run: action
}
}

return { id: '', label: '', run: () => {} }
}
Loading