Skip to content

Commit 986f91a

Browse files
Merge pull request #398 from RedisInsight/feature/RI-2450_update_workbench
Feature/ri 2450 update workbench
2 parents 5a94334 + b3efdd5 commit 986f91a

File tree

28 files changed

+507
-176
lines changed

28 files changed

+507
-176
lines changed

redisinsight/ui/src/constants/api.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,14 @@ enum ApiEndpoints {
4545
WORKBENCH_COMMAND_EXECUTIONS = 'workbench/command-executions',
4646

4747
REDIS_COMMANDS = 'commands',
48-
ENABLEMENT_AREA = 'static/workbench/enablement-area.json',
48+
GUIDES = 'static/guides/guides.json',
49+
// TODO double check it, when tutorials will be completed
50+
TUTORIALS = 'static/tutorials/tutorials.json',
4951
PLUGINS = 'plugins',
5052
STATE = 'state',
5153
CONTENT_CREATE_DATABASE = 'static/content/create-redis.json',
54+
GUIDES_PATH = 'static/guides',
55+
TUTORIALS_PATH = 'static/tutorials',
5256
}
5357

5458
export const DEFAULT_SEARCH_MATCH = '*'

redisinsight/ui/src/constants/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export * from './workbenchResults'
1616
export * from './monitorEvents'
1717
export * from './socketEvents'
1818
export * from './mocks/mock-redis-commands'
19-
export * from './mocks/mock-enablement-area'
19+
export * from './mocks/mock-guides'
20+
export * from './mocks/mock-tutorials'
2021
export * from './socketErrors'
2122
export * from './browser'
2223
export { ApiEndpoints, BrowserStorageItem, ApiStatusCode, apiErrors }
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
2+
3+
export const MOCK_GUIDES_ITEMS: Record<string, IEnablementAreaItem> = {
4+
'quick-guides': {
5+
type: EnablementAreaComponent.Group,
6+
id: 'quick-guides',
7+
label: 'Quick Guides',
8+
children: {
9+
'document-capabilities': {
10+
type: EnablementAreaComponent.InternalLink,
11+
id: 'document-capabilities',
12+
label: 'Document Capabilities',
13+
args: {
14+
path: '/static/workbench/quick-guides/document/learn-more.md',
15+
},
16+
},
17+
'working-with-json': {
18+
type: EnablementAreaComponent.InternalLink,
19+
id: 'working-with-json',
20+
label: 'Working with JSON',
21+
args: {
22+
path: 'quick-guides/working-with-json.html',
23+
},
24+
},
25+
'working-with-hash': {
26+
type: EnablementAreaComponent.InternalLink,
27+
id: 'working-with-hash',
28+
label: 'Working with HASH',
29+
args: {
30+
path: 'quick-guides/working-with-hash.html',
31+
},
32+
}
33+
}
34+
},
35+
'internal-page': {
36+
type: EnablementAreaComponent.InternalLink,
37+
id: 'internal-page',
38+
label: 'Internal Page',
39+
args: {
40+
path: 'quick-guides/document-capabilities.html'
41+
},
42+
},
43+
'second-internal-page': {
44+
type: EnablementAreaComponent.InternalLink,
45+
id: 'second-internal-page',
46+
label: 'Second Internal Page',
47+
args: {
48+
path: 'quick-guides/document-capabilities.html'
49+
},
50+
},
51+
manual: {
52+
type: EnablementAreaComponent.CodeButton,
53+
id: 'manual',
54+
label: 'Manual',
55+
args: {
56+
path: '_scripts/manual.txt'
57+
},
58+
}
59+
}

redisinsight/ui/src/constants/mocks/mock-enablement-area.ts renamed to redisinsight/ui/src/constants/mocks/mock-tutorials.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
22

3-
export const MOCK_ENABLEMENT_AREA_ITEMS: Record<string, IEnablementAreaItem> = {
3+
export const MOCK_TUTORIALS_ITEMS: Record<string, IEnablementAreaItem> = {
44
'quick-guides': {
55
type: EnablementAreaComponent.Group,
66
id: 'quick-guides',

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22
import { cloneDeep } from 'lodash'
33
import { instance, mock } from 'ts-mockito'
44
import { cleanup, mockedStore, render } from 'uiSrc/utils/test-utils'
5-
import { MOCK_ENABLEMENT_AREA_ITEMS } from 'uiSrc/constants'
5+
import { MOCK_GUIDES_ITEMS, MOCK_TUTORIALS_ITEMS } from 'uiSrc/constants'
66
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
77

88
import EnablementArea, { Props } from './EnablementArea'
@@ -17,19 +17,23 @@ beforeEach(() => {
1717
store.clearActions()
1818
})
1919

20-
jest.mock('uiSrc/slices/workbench/wb-enablement-area', () => {
21-
const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-enablement-area').initialState
20+
jest.mock('uiSrc/slices/workbench/wb-guides', () => {
21+
const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-guides').initialState
2222
return {
23-
...jest.requireActual('uiSrc/slices/workbench/wb-enablement-area'),
24-
workbenchEnablementAreaSelector: jest.fn().mockReturnValue({
23+
...jest.requireActual('uiSrc/slices/workbench/wb-guides'),
24+
workbenchGuidesSelector: jest.fn().mockReturnValue({
2525
...defaultState,
2626
}),
2727
}
2828
})
2929

3030
describe('EnablementArea', () => {
3131
it('should render', () => {
32-
expect(render(<EnablementArea {...instance(mockedProps)} items={MOCK_ENABLEMENT_AREA_ITEMS} />))
32+
expect(render(<EnablementArea
33+
{...instance(mockedProps)}
34+
guides={MOCK_GUIDES_ITEMS}
35+
tutorials={MOCK_TUTORIALS_ITEMS}
36+
/>))
3337
.toBeTruthy()
3438
})
3539

@@ -46,15 +50,15 @@ describe('EnablementArea', () => {
4650
const { queryByTestId } = render(
4751
<EnablementArea
4852
{...instance(mockedProps)}
49-
items={MOCK_ENABLEMENT_AREA_ITEMS}
53+
guides={MOCK_GUIDES_ITEMS}
5054
/>
5155
)
5256
const loaderEl = queryByTestId('enablementArea-loader')
5357
const treeViewEl = queryByTestId('enablementArea-treeView')
5458

5559
expect(loaderEl).not.toBeInTheDocument()
5660
expect(treeViewEl).toBeInTheDocument()
57-
expect(treeViewEl?.childNodes.length).toEqual(Object.values(MOCK_ENABLEMENT_AREA_ITEMS).length)
61+
expect(treeViewEl?.childNodes.length).toEqual(Object.values(MOCK_GUIDES_ITEMS).length)
5862
})
5963
it('should render Group component', () => {
6064
const item: IEnablementAreaItem = {
@@ -76,7 +80,7 @@ describe('EnablementArea', () => {
7680
const { queryByTestId } = render(
7781
<EnablementArea
7882
{...instance(mockedProps)}
79-
items={{ 'quick-guides': item }}
83+
guides={{ 'quick-guides': item }}
8084
/>
8185
)
8286

@@ -96,7 +100,7 @@ describe('EnablementArea', () => {
96100
const { queryByTestId } = render(
97101
<EnablementArea
98102
{...instance(mockedProps)}
99-
items={{ manual: item }}
103+
guides={{ manual: item }}
100104
/>
101105
)
102106
const codeButtonEl = queryByTestId(`preselect-${item.label}`)
@@ -115,7 +119,7 @@ describe('EnablementArea', () => {
115119
const { queryByTestId } = render(
116120
<EnablementArea
117121
{...instance(mockedProps)}
118-
items={{ 'internal-page': item }}
122+
guides={{ 'internal-page': item }}
119123
/>
120124
)
121125

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

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import cx from 'classnames'
55
import { EuiListGroup, EuiLoadingContent } from '@elastic/eui'
66
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
77
import { EnablementAreaProvider, IInternalPage } from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
8-
import { appContextWorkbenchEA, resetWorkbenchEAGuide } from 'uiSrc/slices/app/context'
8+
import { appContextWorkbenchEA, resetWorkbenchEAItem } from 'uiSrc/slices/app/context'
9+
import { ApiEndpoints } from 'uiSrc/constants'
910
import {
1011
CodeButton,
1112
Group,
@@ -20,71 +21,79 @@ import styles from './styles.module.scss'
2021
const padding = parseInt(styles.paddingHorizontal)
2122

2223
export interface Props {
23-
items: Record<string, IEnablementAreaItem>
24+
guides: Record<string, IEnablementAreaItem>
25+
tutorials: Record<string, IEnablementAreaItem>
2426
loading: boolean
2527
openScript: (script: string, path?: string, name?: string) => void
2628
onOpenInternalPage: (page: IInternalPage) => void
2729
isCodeBtnDisabled?: boolean
2830
}
2931

30-
const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCodeBtnDisabled }: Props) => {
32+
const EnablementArea = ({
33+
guides = {}, tutorials = {}, openScript, loading, onOpenInternalPage, isCodeBtnDisabled
34+
}: Props) => {
3135
const { search } = useLocation()
3236
const history = useHistory()
3337
const dispatch = useDispatch()
34-
const { guidePath: guideFromContext } = useSelector(appContextWorkbenchEA)
38+
const { itemPath: itemFromContext } = useSelector(appContextWorkbenchEA)
3539
const [isInternalPageVisible, setIsInternalPageVisible] = useState(false)
3640
const [internalPage, setInternalPage] = useState<IInternalPage>({ path: '' })
3741

3842
useEffect(() => {
39-
const pagePath = new URLSearchParams(search).get('guide')
43+
const pagePath = new URLSearchParams(search).get('item')
4044
if (pagePath) {
4145
setIsInternalPageVisible(true)
4246
setInternalPage({ path: pagePath })
47+
4348
return
4449
}
45-
if (guideFromContext) {
46-
handleOpenInternalPage({ path: guideFromContext })
50+
if (itemFromContext) {
51+
handleOpenInternalPage({ path: itemFromContext })
4752
return
4853
}
4954
setIsInternalPageVisible(false)
5055
}, [search])
5156

5257
const handleOpenInternalPage = (page: IInternalPage) => {
5358
history.push({
54-
search: `?guide=${page.path}`
59+
search: `?item=${page.path}`
5560
})
5661
onOpenInternalPage(page)
5762
}
5863

5964
const handleCloseInternalPage = () => {
60-
dispatch(resetWorkbenchEAGuide())
65+
dispatch(resetWorkbenchEAItem())
6166
history.push({
6267
// TODO: better to use query-string parser and update only one parameter (instead of replacing all)
6368
search: ''
6469
})
6570
}
6671

67-
const renderSwitch = (item: IEnablementAreaItem, level: number) => {
72+
const renderSwitch = (item: IEnablementAreaItem, sourcePath: string, level: number) => {
6873
const { label, type, children, id, args } = item
6974
const paddingsStyle = { paddingLeft: `${padding + level * 8}px`, paddingRight: `${padding}px` }
7075
switch (type) {
7176
case EnablementAreaComponent.Group:
7277
return (
7378
<Group triggerStyle={paddingsStyle} testId={id} label={label} {...args}>
74-
{renderTreeView(Object.values(children || {}) || [], level + 1)}
79+
{renderTreeView(Object.values(children || {}) || [], sourcePath, level + 1)}
7580
</Group>
7681
)
7782
case EnablementAreaComponent.CodeButton:
7883
return (
79-
<div style={{ marginTop: '12px', ...paddingsStyle }}>
80-
{args?.path
81-
? <LazyCodeButton label={label} {...args} />
82-
: <CodeButton onClick={() => openScript(args?.content || '')} label={label} {...args} />}
83-
</div>
84+
<>
85+
<div style={paddingsStyle} className="divider"><hr /></div>
86+
<div style={{ marginTop: '24px', ...paddingsStyle }}>
87+
{args?.path
88+
? <LazyCodeButton label={label} {...args} />
89+
: <CodeButton onClick={() => openScript(args?.content || '')} label={label} {...args} />}
90+
</div>
91+
</>
92+
8493
)
8594
case EnablementAreaComponent.InternalLink:
8695
return (
87-
<InternalLink style={paddingsStyle} testId={id || label} label={label} {...args}>
96+
<InternalLink sourcePath={sourcePath} style={paddingsStyle} testId={id || label} label={label} {...args}>
8897
{args?.content || label}
8998
</InternalLink>
9099
)
@@ -93,10 +102,10 @@ const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCode
93102
}
94103
}
95104

96-
const renderTreeView = (elements: IEnablementAreaItem[], level: number = 0) => (
105+
const renderTreeView = (elements: IEnablementAreaItem[], sourcePath: string, level: number = 0) => (
97106
elements?.map((item) => (
98107
<div className="fluid" key={item.id}>
99-
{renderSwitch(item, level)}
108+
{renderSwitch(item, sourcePath, level)}
100109
</div>
101110
)))
102111

@@ -116,7 +125,8 @@ const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCode
116125
flush
117126
className={cx(styles.innerContainer)}
118127
>
119-
{renderTreeView(Object.values(items))}
128+
{renderTreeView(Object.values(guides), ApiEndpoints.GUIDES_PATH)}
129+
{renderTreeView(Object.values(tutorials), ApiEndpoints.TUTORIALS_PATH)}
120130
</EuiListGroup>
121131
)}
122132
<div

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const Code = ({ children, ...rest }: Props) => {
1717
const { setScript, isCodeBtnDisabled } = useContext(EnablementAreaContext)
1818

1919
const loadContent = () => {
20-
const pagePath = new URLSearchParams(search).get('guide')
20+
const pagePath = new URLSearchParams(search).get('item')
2121
if (pagePath) {
2222
const pageInfo = getFileInfo(pagePath)
2323
setScript(children, `${pageInfo.location}/${pageInfo.name}`, startCase(rest.label))

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ const Group = (props: Props) => {
4949
style={{ whiteSpace: 'nowrap', width: 'auto' }}
5050
className={[withBorder ? 'withBorder' : ''].join(' ')}
5151
>
52-
<>
53-
{children}
54-
{withBorder && <div style={triggerStyle} className="divider"><hr /></div> }
55-
</>
52+
{children}
5653
</EuiAccordion>
5754
)
5855
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ export interface Props {
1616
iconPosition?: 'left' | 'right';
1717
toolTip?: string;
1818
style?: any;
19+
sourcePath: string;
1920
}
2021
const InternalLink = (props: Props) => {
21-
const { label, testId, children, path = '', size = 's', iconType, iconPosition = 'left', toolTip, ...rest } = props
22+
const { label, testId, children, path = '', size = 's', iconType, iconPosition = 'left', toolTip, sourcePath, ...rest } = props
2223
const { openPage } = useContext(EnablementAreaContext)
2324
const handleOpenPage = () => {
2425
if (path) {
25-
openPage({ path, label })
26+
openPage({ path: sourcePath + path, label })
2627
}
2728
}
2829

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getApiErrorMessage, isStatusSuccessful } from 'uiSrc/utils'
55
import { resourcesService } from 'uiSrc/services'
66
import EnablementAreaContext from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
77
import { getFileInfo } from 'uiSrc/pages/workbench/components/enablement-area/EnablementArea/utils/getFileInfo'
8+
import { ApiEndpoints } from 'uiSrc/constants'
89

910
import CodeButton from '../CodeButton'
1011

@@ -22,7 +23,7 @@ const LazyCodeButton = ({ path = '', ...rest }: Props) => {
2223
setLoading(true)
2324
setError('')
2425
try {
25-
const { data, status } = await resourcesService.get<string>(path)
26+
const { data, status } = await resourcesService.get<string>(`${ApiEndpoints.TUTORIALS_PATH}${path}`)
2627
if (isStatusSuccessful(status)) {
2728
setLoading(false)
2829
const pageInfo = getFileInfo(path)

0 commit comments

Comments
 (0)