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
1 change: 1 addition & 0 deletions redisinsight/ui/src/constants/monaco/monaco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export enum MonacoLanguage {
JMESPath = 'jmespathLanguage',
SQLiteFunctions = 'sqliteFunctions',
Text = 'text',
RediSearch = 'redisearch',
}

export const defaultMonacoOptions: monacoEditor.editor.IStandaloneEditorConstructionOptions = {
Expand Down
5 changes: 3 additions & 2 deletions redisinsight/ui/src/pages/search/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import {
appContextSearchAndQuery,
setSQVerticalPanelSizes,
} from 'uiSrc/slices/app/context'
import { Query, ResultsHistory } from 'uiSrc/pages/search/components'
import { QueryWrapper, ResultsHistory } from 'uiSrc/pages/search/components'

import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results'
import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils'

import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry'
import { CodeButtonParams } from 'uiSrc/constants'

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

const verticalPanelIds = {
Expand Down Expand Up @@ -88,7 +89,7 @@ const SearchPage = () => {
initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20}
style={{ minHeight: '240px', zIndex: '8' }}
>
<Query onSubmit={handleSubmit} />
<QueryWrapper onSubmit={handleSubmit} />
</EuiResizablePanel>

<EuiResizableButton
Expand Down
4 changes: 2 additions & 2 deletions redisinsight/ui/src/pages/search/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Query from './query'
import QueryWrapper from './query-wrapper'
import ResultsHistory from './results-history'

export {
Query,
QueryWrapper,
ResultsHistory,
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react'
import { render, screen } from 'uiSrc/utils/test-utils'

import Query from './Query'
import QueryWrapper from './QueryWrapper'

describe('Query', () => {
it('should render', () => {
expect(render(<Query onSubmit={jest.fn()} />)).toBeTruthy()
expect(render(<QueryWrapper onSubmit={jest.fn()} />)).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useParams } from 'react-router-dom'
import { QueryActions, QueryTutorials } from 'uiSrc/components/query'

import { RunQueryMode } from 'uiSrc/slices/interfaces'
import { CodeButtonParams } from 'uiSrc/constants'

import { Nullable } from 'uiSrc/utils'
import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery'
import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch'
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
import { TUTORIALS } from './constants'

import Query from '../query'

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

export interface Props {
onSubmit: (
commandInit: string,
commandId?: Nullable<string>,
executeParams?: CodeButtonParams
) => void
}

const QueryWrapper = (props: Props) => {
const { onSubmit } = props

const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector)
const { script: scriptContext } = useSelector(appContextSearchAndQuery)
const { activeRunQueryMode } = useSelector(searchAndQuerySelector)
const { data: indexes = [] } = useSelector(redisearchListSelector)
const [value, setValue] = useState(scriptContext)

const input = useRef<HTMLDivElement>(null)
const scriptRef = useRef('')

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

const dispatch = useDispatch()

useEffect(() => () => {
dispatch(setSQVerticalScript(scriptRef.current))
}, [])

useEffect(() => {
if (!connectedIndstanceId) return

// fetch indexes
dispatch(fetchRedisearchListAction())
}, [connectedIndstanceId])

useEffect(() => {
scriptRef.current = value
}, [value])

const handleChangeQueryRunMode = () => {
dispatch(changeSQActiveRunQueryMode(
activeRunQueryMode === RunQueryMode.ASCII
? RunQueryMode.Raw
: RunQueryMode.ASCII
))
}

const handleSubmit = () => {
onSubmit(value.split('\n').join(' '), undefined, { mode: activeRunQueryMode })
sendEventTelemetry({
event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED,
eventData: {
databaseId: instanceId,
mode: activeRunQueryMode,
// TODO sanitize user query
command: value
}
})
}

const handleChange = (val: string) => {
setValue(val)
}

return (
<div className={styles.wrapper}>
<div
className={styles.container}
onKeyDown={() => {}}
role="textbox"
tabIndex={0}
data-testid="main-input-container-area"
>
<div className={styles.input} data-testid="query-input-container" ref={input}>
<Query indexes={indexes} value={value} onChange={handleChange} />
</div>
<div className={styles.queryFooter}>
<QueryTutorials tutorials={TUTORIALS} source="search_tab" />
<QueryActions
isLoading={false}
activeMode={activeRunQueryMode}
onChangeMode={handleChangeQueryRunMode}
onSubmit={handleSubmit}
/>
</div>
</div>
</div>
)
}

export default React.memo(QueryWrapper)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TutorialsIds } from 'uiSrc/constants'

export const TUTORIALS = [
{
id: TutorialsIds.ExactMatch,
title: 'Exact match'
},
{
id: TutorialsIds.FullTextSearch,
title: 'Full-text search'
},
{
id: TutorialsIds.IntroVectorSearch,
title: 'Intro to vector search'
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import QueryWrapper from './QueryWrapper'

export default QueryWrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
.wrapper {
position: relative;
height: 100%;

:global(.editorBounder) {
bottom: 6px;
left: 18px;
right: 46px;
}
}

.container {
display: flex;
flex-direction: column;
padding: 8px 16px;
width: 100%;
height: 100%;
word-break: break-word;
text-align: left;
letter-spacing: 0;
background-color: var(--rsInputWrapperColor);
color: var(--euiTextSubduedColor) !important;
border: 1px solid var(--euiColorLightShade);
}

.disabled {
opacity: 0.8;
}

.disabledActions {
pointer-events: none;
user-select: none;
}

.containerPlaceholder {
display: flex;
padding: 8px 16px 8px 16px;
width: 100%;
height: 100%;
background-color: var(--rsInputWrapperColor);
color: var(--euiTextSubduedColor) !important;
border: 1px solid var(--euiColorLightShade);
> div {
border: 1px solid var(--euiColorLightShade);
background-color: var(--euiColorEmptyShade);
padding: 8px 20px;
width: 100%;
}
}

.input {
// cannot use overflow since suggestions are absolute
max-height: calc(100% - 32px);
flex-grow: 1;
width: 100%;
border: 1px solid var(--euiColorLightShade);
background-color: var(--rsInputColor);
}

.queryFooter {
display: flex;
align-items: center;
justify-content: space-between;

margin-top: 8px;
flex-shrink: 0;
}

#script {
font: normal normal bold 14px/17px Inconsolata !important;
color: var(--textColorShade);
caret-color: var(--euiColorFullShade);
min-width: 5px;
display: inline;
}

Loading