Skip to content

Commit d674823

Browse files
authored
Merge pull request #1213 from RedisInsight/fe/feature/RI-3479_redis-auto-btn
#RI-3479 - add redis-auto button
2 parents d0b7ef4 + 7584bf9 commit d674823

File tree

20 files changed

+298
-57
lines changed

20 files changed

+298
-57
lines changed

redisinsight/ui/src/components/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useContext, useEffect, useRef, useState } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
33
import cx from 'classnames'
4+
import { v4 as uuidv4 } from 'uuid'
45
import { EuiFlexItem, EuiIcon, EuiLoadingContent, EuiTextColor } from '@elastic/eui'
56
import { pluginApi } from 'uiSrc/services/PluginAPI'
67
import { ThemeContext } from 'uiSrc/contexts/themeContext'
@@ -210,7 +211,7 @@ const QueryCardCliPlugin = (props: Props) => {
210211
useEffect(() => {
211212
const view = visualizations.find((visualization: IPluginVisualization) => visualization.uniqId === id)
212213
if (view) {
213-
generatedIframeNameRef.current = `${view.plugin.name}-${Date.now()}`
214+
generatedIframeNameRef.current = `${view.plugin.name}-${uuidv4()}`
214215
setCurrentView(view)
215216

216217
const { plugin } = view

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/EnablementArea.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useHistory, useLocation } from 'react-router-dom'
33
import { useSelector, useDispatch } from 'react-redux'
44
import cx from 'classnames'
55
import { EuiListGroup, EuiLoadingContent } from '@elastic/eui'
6+
import { CodeButtonParams, ExecuteButtonMode } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
67
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
78
import { EnablementAreaProvider, IInternalPage } from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
89
import { appContextWorkbenchEA, resetWorkbenchEAItem } from 'uiSrc/slices/app/context'
@@ -14,7 +15,7 @@ import {
1415
InternalLink,
1516
LazyCodeButton,
1617
LazyInternalPage,
17-
PlainText
18+
PlainText,
1819
} from './components'
1920

2021
import styles from './styles.module.scss'
@@ -25,7 +26,11 @@ export interface Props {
2526
guides: Record<string, IEnablementAreaItem>
2627
tutorials: Record<string, IEnablementAreaItem>
2728
loading: boolean
28-
openScript: (script: string, path?: string, name?: string) => void
29+
openScript: (
30+
script: string,
31+
execute?: { mode?: ExecuteButtonMode, params?: CodeButtonParams },
32+
file?: { path?: string, name?: string }
33+
) => void
2934
onOpenInternalPage: (page: IInternalPage) => void
3035
isCodeBtnDisabled?: boolean
3136
}

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/components/Code/Code.spec.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from 'react'
22
import { instance, mock } from 'ts-mockito'
3-
import { fireEvent, render } from 'uiSrc/utils/test-utils'
4-
import { EnablementAreaProvider, defaultValue } from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
53
import { MONACO_MANUAL } from 'uiSrc/constants'
4+
import { ExecuteButtonMode } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
5+
import { defaultValue, EnablementAreaProvider } from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
6+
import { fireEvent, render, screen } from 'uiSrc/utils/test-utils'
67

78
import Code, { Props } from './Code'
89

@@ -29,6 +30,21 @@ describe('Code', () => {
2930

3031
const link = queryByTestId(`preselect-${label}`)
3132
fireEvent.click(link as Element)
32-
expect(setScript).toBeCalledWith(MONACO_MANUAL)
33+
expect(setScript).toBeCalledWith(MONACO_MANUAL, {}, undefined)
34+
})
35+
36+
it('should correctly set script with auto execute', () => {
37+
const setScript = jest.fn()
38+
const label = 'Manual'
39+
40+
render(
41+
<EnablementAreaProvider value={{ ...defaultValue, setScript }}>
42+
<Code {...instance(mockedProps)} label={label} mode={ExecuteButtonMode.Auto}>{MONACO_MANUAL}</Code>
43+
</EnablementAreaProvider>
44+
)
45+
46+
screen.debug()
47+
fireEvent.click(screen.queryByTestId(`preselect-auto-${label}`) as Element)
48+
expect(setScript).toBeCalledWith(MONACO_MANUAL, { mode: ExecuteButtonMode.Auto }, undefined)
3349
})
3450
})

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/components/Code/Code.tsx

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
1-
import React, { useContext } from 'react'
21
import { startCase } from 'lodash'
2+
import React, { useContext } from 'react'
33
import { useLocation } from 'react-router-dom'
4-
4+
import { getFileInfo, parseParams } from 'uiSrc/pages/workbench/components/enablement-area/EnablementArea/utils'
5+
import { CodeButtonParams, ExecuteButtonMode } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
56
import EnablementAreaContext from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
6-
import { getFileInfo } from 'uiSrc/pages/workbench/components/enablement-area/EnablementArea/utils/getFileInfo'
7+
import { Maybe } from 'uiSrc/utils'
78

89
import CodeButton from '../CodeButton'
910

1011
export interface Props {
11-
label: string;
12-
children: string;
12+
label: string
13+
children: string
14+
params?: string
15+
mode?: ExecuteButtonMode
1316
}
1417

15-
const Code = ({ children, ...rest }: Props) => {
18+
const Code = ({ children, params, mode, ...rest }: Props) => {
1619
const { search } = useLocation()
1720
const { setScript, isCodeBtnDisabled } = useContext(EnablementAreaContext)
1821

19-
const loadContent = () => {
22+
const loadContent = (execute: { mode?: ExecuteButtonMode, params?: CodeButtonParams }) => {
2023
const pagePath = new URLSearchParams(search).get('item')
24+
let file: Maybe<{ path: string, name: string }>
25+
2126
if (pagePath) {
2227
const pageInfo = getFileInfo(pagePath)
23-
setScript(children, `${pageInfo.location}/${pageInfo.name}`, startCase(rest.label))
24-
} else {
25-
setScript(children)
28+
file = {
29+
path: `${pageInfo.location}/${pageInfo.name}`,
30+
name: startCase(rest.label)
31+
}
2632
}
33+
34+
setScript(children, execute, file)
2735
}
2836

2937
return (
30-
<CodeButton className="mb-s mt-s" onClick={loadContent} disabled={isCodeBtnDisabled} {...rest} />
38+
<CodeButton
39+
className="mb-s mt-s"
40+
onClick={loadContent}
41+
params={parseParams(params)}
42+
mode={mode}
43+
disabled={isCodeBtnDisabled}
44+
{...rest}
45+
/>
3146
)
3247
}
3348

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/components/CodeButton/CodeButton.spec.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { instance, mock } from 'ts-mockito'
3+
import { ExecuteButtonMode } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
34
import { fireEvent, render, screen } from 'uiSrc/utils/test-utils'
45
import CodeButton, { Props } from './CodeButton'
56

@@ -14,6 +15,14 @@ describe('CodeButton', () => {
1415
expect(component).toBeTruthy()
1516
expect(container).toHaveTextContent(label)
1617
})
18+
19+
it('should not render auto-execute button', () => {
20+
const label = 'Manual'
21+
render(<CodeButton {...instance(mockedProps)} label={label} />)
22+
23+
expect(screen.queryByTestId(`preselect-auto-${label}`)).not.toBeInTheDocument()
24+
})
25+
1726
it('should call onClick function', () => {
1827
const onClick = jest.fn()
1928
const label = 'Manual'
@@ -23,4 +32,22 @@ describe('CodeButton', () => {
2332

2433
expect(onClick).toBeCalled()
2534
})
35+
36+
it('should call onClick with auto execute param', () => {
37+
const onClick = jest.fn()
38+
const label = 'Auto'
39+
40+
render(
41+
<CodeButton
42+
{...instance(mockedProps)}
43+
label={label}
44+
onClick={onClick}
45+
mode={ExecuteButtonMode.Auto}
46+
params={{}}
47+
/>
48+
)
49+
fireEvent.click(screen.getByTestId(`preselect-auto-${label}`))
50+
51+
expect(onClick).toBeCalledWith({ mode: ExecuteButtonMode.Auto, params: {} })
52+
})
2653
})
Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,48 @@
1+
import { EuiButton, EuiIcon } from '@elastic/eui'
2+
import cx from 'classnames'
13
import React from 'react'
2-
import { EuiButton } from '@elastic/eui'
4+
import { CodeButtonParams, ExecuteButtonMode } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
35
import { truncateText } from 'uiSrc/utils'
46

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

79
export interface Props {
8-
onClick: () => void
10+
onClick: (execute: { mode?: ExecuteButtonMode, params?: CodeButtonParams }) => void
911
label: string
1012
isLoading?: boolean
1113
disabled?: boolean
1214
className?: string
15+
params?: CodeButtonParams
16+
mode?: ExecuteButtonMode
17+
}
18+
const CodeButton = ({ onClick, label, isLoading, className, disabled, params, mode, ...rest }: Props) => {
19+
const isAutoExecute = mode === ExecuteButtonMode.Auto
20+
21+
return (
22+
<EuiButton
23+
iconSide="right"
24+
isLoading={isLoading}
25+
size="s"
26+
onClick={() => onClick({ mode, params })}
27+
fullWidth
28+
color="secondary"
29+
className={cx(className, styles.button)}
30+
textProps={{ className: styles.buttonText }}
31+
data-testid={`preselect-${isAutoExecute ? 'auto-' : ''}${label}`}
32+
disabled={disabled}
33+
{...rest}
34+
>
35+
<>
36+
{truncateText(label, 86)}
37+
{isAutoExecute && (
38+
<EuiIcon
39+
className={styles.autoExecuteIcon}
40+
type="playFilled"
41+
/>
42+
)}
43+
</>
44+
</EuiButton>
45+
)
1346
}
14-
const CodeButton = ({ onClick, label, isLoading, className, disabled, ...rest }: Props) => (
15-
<EuiButton
16-
iconSide="right"
17-
isLoading={isLoading}
18-
size="s"
19-
onClick={onClick}
20-
fullWidth
21-
color="secondary"
22-
className={[className, styles.button].join(' ')}
23-
textProps={{ className: styles.buttonText }}
24-
data-testid={`preselect-${label}`}
25-
disabled={disabled}
26-
{...rest}
27-
>
28-
{truncateText(label, 86)}
29-
</EuiButton>
30-
)
3147

3248
export default CodeButton

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/components/CodeButton/styles.module.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
.button {
44
justify-content: space-between;
5+
position: relative;
56
&[class*='euiButton--secondary']:not([class*='isDisabled']) {
67
&:hover,
78
&:focus,
@@ -15,6 +16,20 @@
1516
color: var(--euiTextSubduedColor);
1617
}
1718
}
19+
20+
:global(.euiButton__content) {
21+
padding: 0 24px !important;
22+
}
23+
24+
.autoExecuteIcon {
25+
position: absolute;
26+
top: 50%;
27+
right: 4px;
28+
transform: translateY(-50%);
29+
30+
width: 16px;
31+
height: 16px;
32+
}
1833
}
1934

2035
.buttonText {

redisinsight/ui/src/pages/workbench/components/enablement-area/EnablementArea/components/LazyCodeButton/LazyCodeButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const LazyCodeButton = ({ path = '', ...rest }: Props) => {
2727
if (isStatusSuccessful(status)) {
2828
setLoading(false)
2929
const pageInfo = getFileInfo(path)
30-
setScript(data, pageInfo.location, startCase(pageInfo.name))
30+
setScript(data, {}, { path: pageInfo.location, name: startCase(pageInfo.name) })
3131
}
3232
} catch (error) {
3333
setLoading(false)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './parseParams'
2+
export * from './getFileInfo'
3+
export * from './remarkImage'
4+
export * from './rehypeLinks'
5+
export * from './remarkRedisCode'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { CodeButtonParams } from 'uiSrc/pages/workbench/components/enablement-area/interfaces'
2+
3+
export const parseParams = (params?: string): CodeButtonParams | undefined => {
4+
if (params?.match(/(^\[).+(]$)/g)) {
5+
return params
6+
?.replace(/^\[|]$/g, '')
7+
?.split(';')
8+
.reduce((prev: {}, next: string) => {
9+
const [key, value] = next.split('=')
10+
return {
11+
...prev,
12+
[key]: value
13+
}
14+
}, {})
15+
}
16+
return undefined
17+
}

0 commit comments

Comments
 (0)