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
6 changes: 5 additions & 1 deletion redisinsight/ui/src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ enum ApiEndpoints {
WORKBENCH_COMMAND_EXECUTIONS = 'workbench/command-executions',

REDIS_COMMANDS = 'commands',
ENABLEMENT_AREA = 'static/workbench/enablement-area.json',
GUIDES = 'static/guides/guides.json',
// TODO double check it, when tutorials will be completed
TUTORIALS = 'static/tutorials/tutorials.json',
PLUGINS = 'plugins',
STATE = 'state',
CONTENT_CREATE_DATABASE = 'static/content/create-redis.json',
GUIDES_PATH = 'static/guides',
TUTORIALS_PATH = 'static/tutorials',
}

export const DEFAULT_SEARCH_MATCH = '*'
Expand Down
3 changes: 2 additions & 1 deletion redisinsight/ui/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export * from './workbenchResults'
export * from './monitorEvents'
export * from './socketEvents'
export * from './mocks/mock-redis-commands'
export * from './mocks/mock-enablement-area'
export * from './mocks/mock-guides'
export * from './mocks/mock-tutorials'
export * from './socketErrors'
export * from './browser'
export { ApiEndpoints, BrowserStorageItem, ApiStatusCode, apiErrors }
59 changes: 59 additions & 0 deletions redisinsight/ui/src/constants/mocks/mock-guides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'

export const MOCK_GUIDES_ITEMS: Record<string, IEnablementAreaItem> = {
'quick-guides': {
type: EnablementAreaComponent.Group,
id: 'quick-guides',
label: 'Quick Guides',
children: {
'document-capabilities': {
type: EnablementAreaComponent.InternalLink,
id: 'document-capabilities',
label: 'Document Capabilities',
args: {
path: '/static/workbench/quick-guides/document/learn-more.md',
},
},
'working-with-json': {
type: EnablementAreaComponent.InternalLink,
id: 'working-with-json',
label: 'Working with JSON',
args: {
path: 'quick-guides/working-with-json.html',
},
},
'working-with-hash': {
type: EnablementAreaComponent.InternalLink,
id: 'working-with-hash',
label: 'Working with HASH',
args: {
path: 'quick-guides/working-with-hash.html',
},
}
}
},
'internal-page': {
type: EnablementAreaComponent.InternalLink,
id: 'internal-page',
label: 'Internal Page',
args: {
path: 'quick-guides/document-capabilities.html'
},
},
'second-internal-page': {
type: EnablementAreaComponent.InternalLink,
id: 'second-internal-page',
label: 'Second Internal Page',
args: {
path: 'quick-guides/document-capabilities.html'
},
},
manual: {
type: EnablementAreaComponent.CodeButton,
id: 'manual',
label: 'Manual',
args: {
path: '_scripts/manual.txt'
},
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'

export const MOCK_ENABLEMENT_AREA_ITEMS: Record<string, IEnablementAreaItem> = {
export const MOCK_TUTORIALS_ITEMS: Record<string, IEnablementAreaItem> = {
'quick-guides': {
type: EnablementAreaComponent.Group,
id: 'quick-guides',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { cloneDeep } from 'lodash'
import { instance, mock } from 'ts-mockito'
import { cleanup, mockedStore, render } from 'uiSrc/utils/test-utils'
import { MOCK_ENABLEMENT_AREA_ITEMS } from 'uiSrc/constants'
import { MOCK_GUIDES_ITEMS, MOCK_TUTORIALS_ITEMS } from 'uiSrc/constants'
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'

import EnablementArea, { Props } from './EnablementArea'
Expand All @@ -17,19 +17,23 @@ beforeEach(() => {
store.clearActions()
})

jest.mock('uiSrc/slices/workbench/wb-enablement-area', () => {
const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-enablement-area').initialState
jest.mock('uiSrc/slices/workbench/wb-guides', () => {
const defaultState = jest.requireActual('uiSrc/slices/workbench/wb-guides').initialState
return {
...jest.requireActual('uiSrc/slices/workbench/wb-enablement-area'),
workbenchEnablementAreaSelector: jest.fn().mockReturnValue({
...jest.requireActual('uiSrc/slices/workbench/wb-guides'),
workbenchGuidesSelector: jest.fn().mockReturnValue({
...defaultState,
}),
}
})

describe('EnablementArea', () => {
it('should render', () => {
expect(render(<EnablementArea {...instance(mockedProps)} items={MOCK_ENABLEMENT_AREA_ITEMS} />))
expect(render(<EnablementArea
{...instance(mockedProps)}
guides={MOCK_GUIDES_ITEMS}
tutorials={MOCK_TUTORIALS_ITEMS}
/>))
.toBeTruthy()
})

Expand All @@ -46,15 +50,15 @@ describe('EnablementArea', () => {
const { queryByTestId } = render(
<EnablementArea
{...instance(mockedProps)}
items={MOCK_ENABLEMENT_AREA_ITEMS}
guides={MOCK_GUIDES_ITEMS}
/>
)
const loaderEl = queryByTestId('enablementArea-loader')
const treeViewEl = queryByTestId('enablementArea-treeView')

expect(loaderEl).not.toBeInTheDocument()
expect(treeViewEl).toBeInTheDocument()
expect(treeViewEl?.childNodes.length).toEqual(Object.values(MOCK_ENABLEMENT_AREA_ITEMS).length)
expect(treeViewEl?.childNodes.length).toEqual(Object.values(MOCK_GUIDES_ITEMS).length)
})
it('should render Group component', () => {
const item: IEnablementAreaItem = {
Expand All @@ -76,7 +80,7 @@ describe('EnablementArea', () => {
const { queryByTestId } = render(
<EnablementArea
{...instance(mockedProps)}
items={{ 'quick-guides': item }}
guides={{ 'quick-guides': item }}
/>
)

Expand All @@ -96,7 +100,7 @@ describe('EnablementArea', () => {
const { queryByTestId } = render(
<EnablementArea
{...instance(mockedProps)}
items={{ manual: item }}
guides={{ manual: item }}
/>
)
const codeButtonEl = queryByTestId(`preselect-${item.label}`)
Expand All @@ -115,7 +119,7 @@ describe('EnablementArea', () => {
const { queryByTestId } = render(
<EnablementArea
{...instance(mockedProps)}
items={{ 'internal-page': item }}
guides={{ 'internal-page': item }}
/>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import cx from 'classnames'
import { EuiListGroup, EuiLoadingContent } from '@elastic/eui'
import { EnablementAreaComponent, IEnablementAreaItem } from 'uiSrc/slices/interfaces'
import { EnablementAreaProvider, IInternalPage } from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
import { appContextWorkbenchEA, resetWorkbenchEAGuide } from 'uiSrc/slices/app/context'
import { appContextWorkbenchEA, resetWorkbenchEAItem } from 'uiSrc/slices/app/context'
import { ApiEndpoints } from 'uiSrc/constants'
import {
CodeButton,
Group,
Expand All @@ -20,71 +21,79 @@ import styles from './styles.module.scss'
const padding = parseInt(styles.paddingHorizontal)

export interface Props {
items: Record<string, IEnablementAreaItem>
guides: Record<string, IEnablementAreaItem>
tutorials: Record<string, IEnablementAreaItem>
loading: boolean
openScript: (script: string, path?: string, name?: string) => void
onOpenInternalPage: (page: IInternalPage) => void
isCodeBtnDisabled?: boolean
}

const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCodeBtnDisabled }: Props) => {
const EnablementArea = ({
guides = {}, tutorials = {}, openScript, loading, onOpenInternalPage, isCodeBtnDisabled
}: Props) => {
const { search } = useLocation()
const history = useHistory()
const dispatch = useDispatch()
const { guidePath: guideFromContext } = useSelector(appContextWorkbenchEA)
const { itemPath: itemFromContext } = useSelector(appContextWorkbenchEA)
const [isInternalPageVisible, setIsInternalPageVisible] = useState(false)
const [internalPage, setInternalPage] = useState<IInternalPage>({ path: '' })

useEffect(() => {
const pagePath = new URLSearchParams(search).get('guide')
const pagePath = new URLSearchParams(search).get('item')
if (pagePath) {
setIsInternalPageVisible(true)
setInternalPage({ path: pagePath })

return
}
if (guideFromContext) {
handleOpenInternalPage({ path: guideFromContext })
if (itemFromContext) {
handleOpenInternalPage({ path: itemFromContext })
return
}
setIsInternalPageVisible(false)
}, [search])

const handleOpenInternalPage = (page: IInternalPage) => {
history.push({
search: `?guide=${page.path}`
search: `?item=${page.path}`
})
onOpenInternalPage(page)
}

const handleCloseInternalPage = () => {
dispatch(resetWorkbenchEAGuide())
dispatch(resetWorkbenchEAItem())
history.push({
// TODO: better to use query-string parser and update only one parameter (instead of replacing all)
search: ''
})
}

const renderSwitch = (item: IEnablementAreaItem, level: number) => {
const renderSwitch = (item: IEnablementAreaItem, sourcePath: string, level: number) => {
const { label, type, children, id, args } = item
const paddingsStyle = { paddingLeft: `${padding + level * 8}px`, paddingRight: `${padding}px` }
switch (type) {
case EnablementAreaComponent.Group:
return (
<Group triggerStyle={paddingsStyle} testId={id} label={label} {...args}>
{renderTreeView(Object.values(children || {}) || [], level + 1)}
{renderTreeView(Object.values(children || {}) || [], sourcePath, level + 1)}
</Group>
)
case EnablementAreaComponent.CodeButton:
return (
<div style={{ marginTop: '12px', ...paddingsStyle }}>
{args?.path
? <LazyCodeButton label={label} {...args} />
: <CodeButton onClick={() => openScript(args?.content || '')} label={label} {...args} />}
</div>
<>
<div style={paddingsStyle} className="divider"><hr /></div>
<div style={{ marginTop: '24px', ...paddingsStyle }}>
{args?.path
? <LazyCodeButton label={label} {...args} />
: <CodeButton onClick={() => openScript(args?.content || '')} label={label} {...args} />}
</div>
</>

)
case EnablementAreaComponent.InternalLink:
return (
<InternalLink style={paddingsStyle} testId={id || label} label={label} {...args}>
<InternalLink sourcePath={sourcePath} style={paddingsStyle} testId={id || label} label={label} {...args}>
{args?.content || label}
</InternalLink>
)
Expand All @@ -93,10 +102,10 @@ const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCode
}
}

const renderTreeView = (elements: IEnablementAreaItem[], level: number = 0) => (
const renderTreeView = (elements: IEnablementAreaItem[], sourcePath: string, level: number = 0) => (
elements?.map((item) => (
<div className="fluid" key={item.id}>
{renderSwitch(item, level)}
{renderSwitch(item, sourcePath, level)}
</div>
)))

Expand All @@ -116,7 +125,8 @@ const EnablementArea = ({ items, openScript, loading, onOpenInternalPage, isCode
flush
className={cx(styles.innerContainer)}
>
{renderTreeView(Object.values(items))}
{renderTreeView(Object.values(guides), ApiEndpoints.GUIDES_PATH)}
{renderTreeView(Object.values(tutorials), ApiEndpoints.TUTORIALS_PATH)}
</EuiListGroup>
)}
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Code = ({ children, ...rest }: Props) => {
const { setScript, isCodeBtnDisabled } = useContext(EnablementAreaContext)

const loadContent = () => {
const pagePath = new URLSearchParams(search).get('guide')
const pagePath = new URLSearchParams(search).get('item')
if (pagePath) {
const pageInfo = getFileInfo(pagePath)
setScript(children, `${pageInfo.location}/${pageInfo.name}`, startCase(rest.label))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@ const Group = (props: Props) => {
style={{ whiteSpace: 'nowrap', width: 'auto' }}
className={[withBorder ? 'withBorder' : ''].join(' ')}
>
<>
{children}
{withBorder && <div style={triggerStyle} className="divider"><hr /></div> }
</>
{children}
</EuiAccordion>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ export interface Props {
iconPosition?: 'left' | 'right';
toolTip?: string;
style?: any;
sourcePath: string;
}
const InternalLink = (props: Props) => {
const { label, testId, children, path = '', size = 's', iconType, iconPosition = 'left', toolTip, ...rest } = props
const { label, testId, children, path = '', size = 's', iconType, iconPosition = 'left', toolTip, sourcePath, ...rest } = props
const { openPage } = useContext(EnablementAreaContext)
const handleOpenPage = () => {
if (path) {
openPage({ path, label })
openPage({ path: sourcePath + path, label })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getApiErrorMessage, isStatusSuccessful } from 'uiSrc/utils'
import { resourcesService } from 'uiSrc/services'
import EnablementAreaContext from 'uiSrc/pages/workbench/contexts/enablementAreaContext'
import { getFileInfo } from 'uiSrc/pages/workbench/components/enablement-area/EnablementArea/utils/getFileInfo'
import { ApiEndpoints } from 'uiSrc/constants'

import CodeButton from '../CodeButton'

Expand All @@ -22,7 +23,7 @@ const LazyCodeButton = ({ path = '', ...rest }: Props) => {
setLoading(true)
setError('')
try {
const { data, status } = await resourcesService.get<string>(path)
const { data, status } = await resourcesService.get<string>(`${ApiEndpoints.TUTORIALS_PATH}${path}`)
if (isStatusSuccessful(status)) {
setLoading(false)
const pageInfo = getFileInfo(path)
Expand Down
Loading