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
2 changes: 2 additions & 0 deletions redisinsight/ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { createRoot } from 'react-dom/client'
import App from 'uiSrc/App'
import Router from 'uiSrc/Router'
import { listenPluginsEvents } from 'uiSrc/plugins/pluginEvents'
import { migrateLocalStorageData } from 'uiSrc/services'
import 'uiSrc/styles/base/_fonts.scss'
import 'uiSrc/styles/main.scss'

migrateLocalStorageData()
listenPluginsEvents()

const rootEl = document.getElementById('root')
Expand Down
2 changes: 2 additions & 0 deletions redisinsight/ui/indexElectron.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import React from 'react'
import { createRoot } from 'react-dom/client'
import AppElectron from 'uiSrc/electron/AppElectron'
import { listenPluginsEvents } from 'uiSrc/plugins/pluginEvents'
import { migrateLocalStorageData } from 'uiSrc/services'
import 'uiSrc/styles/base/_fonts.scss'
import 'uiSrc/styles/main.scss'

window.app.sendWindowId((_e: any, windowId: string = '') => {
window.windowId = windowId || window.windowId

migrateLocalStorageData()
listenPluginsEvents()

const rootEl = document.getElementById('root')
Expand Down
3 changes: 2 additions & 1 deletion redisinsight/ui/src/constants/browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EuiComboBoxOptionOption } from '@elastic/eui'
import { KeyValueFormat, SortOrder } from './keys'

export const DEFAULT_DELIMITER = ':'
export const DEFAULT_DELIMITER: EuiComboBoxOptionOption = { label: ':' }
export const DEFAULT_TREE_SORTING = SortOrder.ASC
export const DEFAULT_SHOW_HIDDEN_RECOMMENDATIONS = false

Expand Down
18 changes: 10 additions & 8 deletions redisinsight/ui/src/helpers/constructKeysToTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys'

interface Props {
items: IKeyPropTypes[]
delimiter?: string
delimiterPattern?: string
delimiters?: string[]
sorting?: SortOrder
}

export const constructKeysToTree = (props: Props): any[] => {
const { items: keys, delimiter = ':', sorting = 'ASC' } = props
const keysSymbol = `keys${delimiter}keys`
const { items: keys, delimiterPattern = ':', delimiters = [], sorting = 'ASC' } = props
const keysSymbol = `keys${delimiterPattern}keys`
const tree: any = {}

keys.forEach((key: any) => {
// eslint-disable-next-line prefer-object-spread
let currentNode: any = tree
const { nameString: name = '' } = key
const nameSplitted = name.split(delimiter)
const nameSplitted = name.split(new RegExp(delimiterPattern, 'g'))
const lastIndex = nameSplitted.length - 1

nameSplitted.forEach((value:any, index: number) => {
Expand Down Expand Up @@ -78,33 +79,34 @@ export const constructKeysToTree = (props: Props): any[] => {
return treeNodes.map((key, index) => {
const name = key?.toString()
const node: any = { nameString: name }
const tillNowKeyName = previousKey + name + delimiter
const path = prevIndex ? `${prevIndex}.${index}` : `${index}`

// populate node with children nodes
if (!tree[key].isLeaf && Object.keys(tree[key]).length > 0) {
const delimiterView = delimiters.length === 1 ? delimiters[0] : '-'
node.children = formatTreeData(
tree[key],
tillNowKeyName,
`${previousKey + name + delimiterView}`,
delimiter,
path,
)
node.keyCount = node.children.reduce((a: any, b:any) => a + (b.keyCount || 1), 0)
node.keyApproximate = (node.keyCount / keys.length) * 100
node.fullName = previousKey + name
} else {
// populate leaf
node.isLeaf = true
node.children = []
node.nameString = name.slice(0, -keysSymbol.length)
node.nameBuffer = tree[key]?.name
node.fullName = previousKey + name + delimiter
}

node.path = path
node.fullName = tillNowKeyName
node.id = getUniqueId()
return node
})
}

return formatTreeData(tree, '', delimiter)
return formatTreeData(tree, '', delimiterPattern)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { DEFAULT_DELIMITER } from 'uiSrc/constants'
import { constructKeysToTreeMockResult } from './constructKeysToTreeMockResult'
import { constructKeysToTreeMockResult, delimiterMock } from './constructKeysToTreeMockResult'
import { constructKeysToTree } from '../constructKeysToTree'

const constructKeysToTreeTests: any[] = [
[{
items: [
{ nameString: 'keys:1:2', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'keys2', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'keys:1:1', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'empty::test', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'test1', type: 'hash', ttl: -1, size: 71 },
Expand All @@ -15,8 +13,9 @@ const constructKeysToTreeTests: any[] = [
{ nameString: 'keys1', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'keys:3', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'keys:2', type: 'hash', ttl: -1, size: 71 },
{ nameString: 'keys_2', type: 'hash', ttl: -1, size: 71 },
],
delimiter: DEFAULT_DELIMITER
delimiterPattern: delimiterMock
},
constructKeysToTreeMockResult
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const delimiterMock = ':|_'
export const constructKeysToTreeMockResult = [
{
nameString: 'empty',
Expand All @@ -10,19 +11,19 @@ export const constructKeysToTreeMockResult = [
isLeaf: true,
children: [],
path: '0.0.0',
fullName: 'empty::empty::testkeys:keys:',
fullName: `empty--empty::testkeys${delimiterMock}keys${delimiterMock}`,
}
],
keyCount: 1,
keyApproximate: 10,
path: '0.0',
fullName: 'empty::',
fullName: 'empty-',
}
],
keyCount: 1,
keyApproximate: 10,
path: '0',
fullName: 'empty:',
fullName: 'empty',
},
{
nameString: 'keys',
Expand All @@ -35,74 +36,74 @@ export const constructKeysToTreeMockResult = [
isLeaf: true,
children: [],
path: '1.0.0',
fullName: 'keys:1:keys:1:1keys:keys:',
fullName: `keys-1-keys:1:1keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'keys:1:2',
isLeaf: true,
children: [],
path: '1.0.1',
fullName: 'keys:1:keys:1:2keys:keys:',
fullName: `keys-1-keys:1:2keys${delimiterMock}keys${delimiterMock}`,
}
],
keyCount: 2,
keyApproximate: 20,
path: '1.0',
fullName: 'keys:1:',
fullName: 'keys-1',
},
{
nameString: 'keys:1',
nameString: 'keys_2',
isLeaf: true,
children: [],
path: '1.1',
fullName: 'keys:keys:1keys:keys:',
fullName: `keys-keys_2keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'keys:2',
nameString: 'keys:1',
isLeaf: true,
children: [],
path: '1.2',
fullName: 'keys:keys:2keys:keys:',
fullName: `keys-keys:1keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'keys:3',
nameString: 'keys:2',
isLeaf: true,
children: [],
path: '1.3',
fullName: 'keys:keys:3keys:keys:',
fullName: `keys-keys:2keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'keys:3',
isLeaf: true,
children: [],
path: '1.4',
fullName: `keys-keys:3keys${delimiterMock}keys${delimiterMock}`,
}
],
keyCount: 5,
keyApproximate: 50,
keyCount: 6,
keyApproximate: 60,
path: '1',
fullName: 'keys:',
fullName: 'keys',
},
{
nameString: 'keys1',
isLeaf: true,
children: [],
path: '2',
fullName: 'keys1keys:keys:',
},
{
nameString: 'keys2',
isLeaf: true,
children: [],
path: '3',
fullName: 'keys2keys:keys:',
fullName: `keys1keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'test1',
isLeaf: true,
children: [],
path: '4',
fullName: 'test1keys:keys:',
path: '3',
fullName: `test1keys${delimiterMock}keys${delimiterMock}`,
},
{
nameString: 'test2',
isLeaf: true,
children: [],
path: '5',
fullName: 'test2keys:keys:',
path: '4',
fullName: `test2keys${delimiterMock}keys${delimiterMock}`,
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ const KeyList = forwardRef((props: Props, ref) => {
minWidth: 94,
truncateText: true,
render: (cellData: string) => (
<KeyRowName nameString={cellData} />
<KeyRowName nameString={cellData} shortName={cellData} />
)
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ describe('KeyRowName', () => {
expect(render(<KeyRowName {...instance(mockedProps)} />)).toBeTruthy()
})

it('should render Loading if no nameString', () => {
const { queryByTestId } = render(<KeyRowName nameString={undefined} />)
it('should render Loading if no nameString and shortName', () => {
const { queryByTestId } = render(<KeyRowName nameString={undefined} shortName={undefined} />)

expect(queryByTestId(loadingTestId)).toBeInTheDocument()
})

it('content should be no more than 200 symbols', () => {
const longName = Array.from({ length: 250 }, () => '1').join('')
const { queryByTestId } = render(<KeyRowName nameString={longName} />)
const { queryByTestId } = render(<KeyRowName nameString={longName} shortName={longName} />)

expect(queryByTestId(loadingTestId)).not.toBeInTheDocument()
expect(queryByTestId(`key-${longName}`)).toHaveTextContent(longName.slice(0, 200))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import styles from './styles.module.scss'

export interface Props {
nameString: Maybe<string>
shortName: Maybe<string>
}

const KeyRowName = (props: Props) => {
const { nameString } = props
const { nameString, shortName } = props

if (isUndefined(nameString)) {
if (isUndefined(shortName)) {
return (
<EuiLoadingContent
lines={1}
Expand All @@ -27,13 +28,13 @@ const KeyRowName = (props: Props) => {
}

// Better to cut the long string, because it could affect virtual scroll performance
const nameContent = replaceSpaces(nameString?.substring?.(0, 200))
const nameContent = replaceSpaces(shortName?.substring?.(0, 200))
const nameTooltipContent = formatLongName(nameString)

return (
<div className={styles.keyName}>
<EuiText color="subdued" size="s" style={{ maxWidth: '100%', display: 'flex' }}>
<div style={{ display: 'flex' }} className="truncateText" data-testid={`key-${nameString}`}>
<div style={{ display: 'flex' }} className="truncateText" data-testid={`key-${shortName}`}>
<EuiToolTip
title="Key Name"
className={styles.tooltip}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import cx from 'classnames'

import { useParams } from 'react-router-dom'
import { escapeRegExp } from 'lodash'

import {
appContextBrowserTree,
resetBrowserTree,
Expand All @@ -13,7 +14,7 @@ import { constructKeysToTree } from 'uiSrc/helpers'
import VirtualTree from 'uiSrc/pages/browser/components/virtual-tree'
import TreeViewSVG from 'uiSrc/assets/img/icons/treeview.svg'
import { KeysStoreData } from 'uiSrc/slices/interfaces/keys'
import { Nullable, bufferToString } from 'uiSrc/utils'
import { Nullable, bufferToString, comboBoxToArray } from 'uiSrc/utils'
import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys'
import { KeyTypes, ModulesKeyTypes } from 'uiSrc/constants'
import { RedisResponseBuffer, RedisString } from 'uiSrc/slices/interfaces'
Expand Down Expand Up @@ -59,14 +60,20 @@ const KeyTree = forwardRef((props: Props, ref) => {

const { instanceId } = useParams<{ instanceId: string }>()
const { openNodes } = useSelector(appContextBrowserTree)
const { treeViewDelimiter: delimiter = '', treeViewSort: sorting } = useSelector(appContextDbConfig)
const { treeViewDelimiter, treeViewSort: sorting } = useSelector(appContextDbConfig)
const { nameString: selectedKeyName = null } = useSelector(selectedKeyDataSelector) ?? {}

const [statusOpen, setStatusOpen] = useState(openNodes)
const [constructingTree, setConstructingTree] = useState(false)
const [firstDataLoaded, setFirstDataLoaded] = useState<boolean>(!!keysState.keys.length)
const [items, setItems] = useState<IKeyPropTypes[]>(parseKeyNames(keysState.keys ?? []))

// escape regexp symbols and join and transform to regexp
const delimiters = comboBoxToArray(treeViewDelimiter)
const delimiterPattern = delimiters
.map(escapeRegExp)
.join('|')

const dispatch = useDispatch()

useImperativeHandle(ref, () => ({
Expand All @@ -86,8 +93,8 @@ const KeyTree = forwardRef((props: Props, ref) => {
// open all parents for selected key
const openSelectedKey = (selectedKeyName: Nullable<string> = '') => {
if (selectedKeyName) {
const parts = selectedKeyName.split(delimiter)
const parents = parts.map((_, index) => parts.slice(0, index + 1).join(delimiter) + delimiter)
const parts = selectedKeyName.split(delimiterPattern)
const parents = parts.map((_, index) => parts.slice(0, index + 1).join(delimiterPattern) + delimiterPattern)

// remove key name from parents
parents.pop()
Expand All @@ -110,7 +117,7 @@ const KeyTree = forwardRef((props: Props, ref) => {
}

setItems(parseKeyNames(keysState.keys))
}, [keysState.lastRefreshTime, delimiter, sorting])
}, [keysState.lastRefreshTime, delimiterPattern, sorting])

useEffect(() => {
openSelectedKey(selectedKeyName)
Expand Down Expand Up @@ -188,7 +195,8 @@ const KeyTree = forwardRef((props: Props, ref) => {
<VirtualTree
items={items}
loadingIcon={TreeViewSVG}
delimiter={delimiter}
delimiters={delimiters}
delimiterPattern={delimiterPattern}
sorting={sorting}
deleting={deleting}
statusSelected={selectedKeyName}
Expand Down
Loading
Loading