Skip to content

Commit

Permalink
Merge pull request #231 from RedisInsight/feature/bugfixing
Browse files Browse the repository at this point in the history
#RIVS-321, #RIVS-324, #RIVS-317, #RIVS-316, #RIVS-322, #RIVS-323
  • Loading branch information
vlad-dargel authored Dec 18, 2024
2 parents 503bca5 + 82e29cd commit be6f0c8
Show file tree
Hide file tree
Showing 22 changed files with 243 additions and 51 deletions.
8 changes: 4 additions & 4 deletions scripts/downloadBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ async function downloadRedisBackendArchive(
})
}

function getNormalizedString(string: string) {
return string?.startsWith('D:')
function getNormalizedCIString(string: string) {
return string?.startsWith('D:') && process.env.CI
? upath.normalize(string).replace('D:', '/d')
: string
}
Expand All @@ -96,9 +96,9 @@ function unzipRedisServer(redisInsideArchivePath: string, extractDir: string) {

cp.spawnSync('tar', [
'-xf',
getNormalizedString(redisInsideArchivePath),
getNormalizedCIString(redisInsideArchivePath),
'-C',
getNormalizedString(extractDir),
getNormalizedCIString(extractDir),
'--strip-components',
'1',
'api',
Expand Down
16 changes: 16 additions & 0 deletions src/webviews/src/actions/tests/processCliAction.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as useCliSettingsThunks from 'uiSrc/modules/cli/hooks/cli-settings/useCliSettingsThunks'
import { constants } from 'testSrc/helpers'
import { processCliAction } from 'uiSrc/actions'

vi.spyOn(useCliSettingsThunks, 'addCli')

beforeEach(() => {
vi.stubGlobal('ri', { })
})

describe('processCliAction', () => {
it('should call addCli', () => {
processCliAction(constants.VSCODE_CLI_ACTION)
expect(useCliSettingsThunks.addCli).toBeCalled()
})
})
23 changes: 23 additions & 0 deletions src/webviews/src/actions/tests/selectKeyAction.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as useSelectedKey from 'uiSrc/store/hooks/use-selected-key-store/useSelectedKeyStore'
import { selectKeyAction } from 'uiSrc/actions'
import { constants } from 'testSrc/helpers'


vi.spyOn(useSelectedKey, 'fetchKeyInfo')


beforeEach(() => {
vi.stubGlobal('ri', { })

useSelectedKey.useSelectedKeyStore.setState((state) => ({
...state,
data: constants.KEY_INFO,
}))
})

describe('selectKeyAction', () => {
it('should call fetchKeyInfo', () => {
selectKeyAction(constants.VSCODE_SELECT_KEY_ACTION)
expect(useSelectedKey.fetchKeyInfo).toBeCalled()
})
})
2 changes: 2 additions & 0 deletions src/webviews/src/components/auto-refresh/AutoRefresh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ const AutoRefresh = React.memo(({
</Tooltip>

<Popover
closeOnEscape
closeOnDocumentClick
repositionOnResize
keepTooltipInside={false}
open={isPopoverOpen}
Expand Down
3 changes: 1 addition & 2 deletions src/webviews/src/components/auto-refresh/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@


:global(.popover-auto-refresh-content) {
@apply max-w-[225px] w-[225px] #{!important};

@apply pr-[26px] #{!important};
}

.switch {
Expand Down
1 change: 1 addition & 0 deletions src/webviews/src/constants/core/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ enum StorageItem {
databaseId = 'databaseId',
openTreeNode = 'openTreeNode',
openTreeDatabase = 'openTreeDatabase',
keysTreeFilter = 'keysTreeFilter',
}

export { StorageItem }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const KeyDetailsHeader = ({
</div>
)}
</AutoSizer>
{(loading || refreshing) && <div className="table-loading" />}
{(loading || refreshing) && <div className="data-loading" />}
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const HashDetails = (props: Props) => {
),
children,
<AddItemsAction key={3} title={l10n.t('Add Fields')} openAddItemPanel={openAddItemPanel} />,
]), [])
]), [showTtl, isExpireFieldsAvailable])

return (
<div className="fluid flex-column relative">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const StringDetails = (props: Props) => {
setEditItem(!editItem)
}}
/>,
]), [])
]), [isStringEditable, isEditable])

return (
<div className="fluid flex-column relative">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { apiService, vscodeApi } from 'uiSrc/services'
import * as useContext from 'uiSrc/store/hooks/use-context/useContext'
import * as useSelectedKeyStore from 'uiSrc/store/hooks/use-selected-key-store/useSelectedKeyStore'
import { Database } from 'uiSrc/store'
import * as useDatabasesStore from 'uiSrc/store'
import { constants, fireEvent, render, waitForStack } from 'testSrc/helpers'
import { DatabaseWrapper, Props } from './DatabaseWrapper'
import * as useKeys from '../../hooks/useKeys'
Expand Down Expand Up @@ -39,12 +40,23 @@ const resetKeysTreeMock = vi.fn();
resetKeysTree: resetKeysTreeMock,
}))

vi.spyOn(useDatabasesStore, 'fetchDatabaseOverviewById')

describe('DatabaseWrapper', () => {
it('should render', () => {
expect(render(<DatabaseWrapper {...mockedProps} />)).toBeTruthy()
})

it('should call fetchPatternKeysAction action after click on refresh icon', async () => {
it('should call fetchDatabaseOverviewById action after click on refresh icon', async () => {
const { queryByTestId } = render(<DatabaseWrapper {...mockedProps} />)

fireEvent.click(queryByTestId('refresh-databases')!)
await waitForStack()

expect(useDatabasesStore.fetchDatabaseOverviewById).toBeCalled()
})

it('should call fetchPatternKeysAction action after click on logical database refresh icon', async () => {
const { queryByTestId } = render(<DatabaseWrapper {...mockedProps} />)

fireEvent.click(queryByTestId(`database-${mockDatabase.id}`)!)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'
import cx from 'classnames'
import { VscEdit } from 'react-icons/vsc'
import { isUndefined, toNumber } from 'lodash'
import { VscEdit, VscRefresh } from 'react-icons/vsc'
import { isUndefined, toNumber, isEqual } from 'lodash'
import * as l10n from '@vscode/l10n'
import { VSCodeButton } from '@vscode/webview-ui-toolkit/react'

Expand All @@ -11,7 +11,7 @@ import {
getRedisModulesSummary,
sendEventTelemetry,
} from 'uiSrc/utils'
import { ContextStoreProvider, Database, DatabaseOverview, checkConnectToDatabase, deleteDatabases } from 'uiSrc/store'
import { ContextStoreProvider, Database, DatabaseOverview, checkConnectToDatabase, deleteDatabases, fetchDatabaseOverviewById } from 'uiSrc/store'
import { Chevron, DatabaseIcon, Tooltip } from 'uiSrc/ui'
import { PopoverDelete } from 'uiSrc/components'
import { POPOVER_WINDOW_BORDER_WIDTH, StorageItem, VscodeMessageAction } from 'uiSrc/constants'
Expand All @@ -28,9 +28,29 @@ export interface Props {
database: Database
}

const LogicalDatabase = (
{ database, open, dbTotal }:
{ database: Database, open?: boolean, dbTotal?: number },
) => (
<ContextStoreProvider >
<KeysStoreProvider>
<LogicalDatabaseWrapper database={database}>
<KeysTreeHeader
database={database}
open={open}
dbTotal={dbTotal}
>
<KeysTree database={database} />
</KeysTreeHeader>
</LogicalDatabaseWrapper>
</KeysStoreProvider>
</ContextStoreProvider>
)

export const DatabaseWrapper = React.memo(({ database }: Props) => {
const { id, name } = database

const [loading, setLoading] = useState<boolean>(false)
const [showTree, setShowTree] = useState<boolean>(false)
const [totalKeysPerDb, setTotalKeysPerDb] = useState<Maybe<Record<string, number>>>(undefined)

Expand Down Expand Up @@ -82,6 +102,16 @@ export const DatabaseWrapper = React.memo(({ database }: Props) => {
vscodeApi.postMessage({ action: VscodeMessageAction.EditDatabase, data: { database } })
}

const refreshHandle = async () => {
setLoading(true)
const overview = await fetchDatabaseOverviewById(id)
setLoading(false)

if (!isEqual(totalKeysPerDb, overview?.totalKeysPerDb)) {
setTotalKeysPerDb(overview?.totalKeysPerDb)
}
}

const deleteDatabaseHandle = () => {
deleteDatabases([database])
}
Expand All @@ -95,25 +125,6 @@ export const DatabaseWrapper = React.memo(({ database }: Props) => {
})
}

const LogicalDatabase = (
{ database, open, dbTotal }:
{ database: Database, open?: boolean, dbTotal?: number },
) => (
<ContextStoreProvider>
<KeysStoreProvider>
<LogicalDatabaseWrapper database={database}>
<KeysTreeHeader
database={database}
open={open}
dbTotal={dbTotal}
>
<KeysTree database={database} />
</KeysTreeHeader>
</LogicalDatabaseWrapper>
</KeysStoreProvider>
</ContextStoreProvider>
)

return (
<div className={cx('flex w-full flex-col')}>
<div className={cx('flex justify-between flex-1 min-h-[22px] flex-row group')}>
Expand All @@ -138,6 +149,14 @@ export const DatabaseWrapper = React.memo(({ database }: Props) => {
</Tooltip>
</div>
<div className="flex pr-3.5">
<VSCodeButton
appearance="icon"
onClick={refreshHandle}
className={cx('hidden', 'group-hover:!flex', { '!flex': showTree })}
data-testid="refresh-databases"
>
<VscRefresh />
</VSCodeButton>
<VSCodeButton
appearance="icon"
onClick={editHandle}
Expand All @@ -160,6 +179,7 @@ export const DatabaseWrapper = React.memo(({ database }: Props) => {
/>
</div>
</div>
{loading && <div className="data-loading" />}
{showTree && (<>
{!isUndefined(totalKeysPerDb) && Object.keys(totalKeysPerDb).map((databaseIndex) => (
<LogicalDatabase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,12 @@ export const KeysSummary = (props: Props) => {
)} */}

<div className={cx('hidden', 'pr-3.5', 'group-hover:!flex', { '!flex': showTree })}>
<KeyTreeFilter />
<Tooltip
repositionOnResize
keepTooltipInside={false}
content={l10n.t('Sort by key names displayed')}
position="bottom right"
position="bottom center"
>
<VSCodeButton
appearance="icon"
Expand All @@ -172,7 +174,6 @@ export const KeysSummary = (props: Props) => {
{isSortingASC ? <BiSortDown /> : <BiSortUp />}
</VSCodeButton>
</Tooltip>
<KeyTreeFilter />
<VSCodeButton appearance="icon" onClick={addKeyClickHandle} data-testid="add-key-button">
<VscAdd />
</VSCodeButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Mock } from 'vitest'
import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/utils'
import * as utils from 'uiSrc/utils'
import * as moduleUtils from 'uiSrc/modules/keys-tree/utils'
import { apiService } from 'uiSrc/services'
import { apiService, sessionStorageService } from 'uiSrc/services'
import { StorageItem } from 'uiSrc/constants'
import {
constants,
fireEvent,
Expand All @@ -22,6 +23,8 @@ const TREE_FILTER_TRIGGER_BTN = 'key-tree-filter-trigger'
const FILTER_SELECT = 'tree-view-filter-select'
const SEARCH_INPUT = 'tree-view-search-input'

vi.spyOn(sessionStorageService, 'set')
vi.spyOn(sessionStorageService, 'get')
vi.spyOn(utils, 'sendEventTelemetry')
vi.spyOn(moduleUtils, 'parseKeysListResponse').mockImplementation(() => constants.KEYS_LIST)

Expand Down Expand Up @@ -107,4 +110,62 @@ describe('KeyTreeDelimiter', () => {

expect(setFilterAndSearchMock).toBeCalled()
})

it('"setFilterAndSearch" should be called with stored values from sessionStorage', async () => {
const useKeysInContextMock = vi.spyOn(useKeys, 'useKeysInContext')
const setFilterAndSearchMock = vi.fn()
const mockSearch = 'search'
const mockFilter = 'hash';

(sessionStorageService.get as Mock).mockImplementation(() => ({
search: mockSearch,
filter: mockFilter,
}))

useKeysInContextMock.mockImplementation(() => ({
dbId: constants.DATABASE_ID,
dbIndex: 1,
filter: ALL_KEY_TYPES_VALUE,
searchInit: '',
setFilterAndSearch: setFilterAndSearchMock,
}))

render(<KeyTreeFilter />)

expect(sessionStorageService.get).toBeCalledWith(`${StorageItem.keysTreeFilter + constants.DATABASE_ID + 1}`)
expect(setFilterAndSearchMock).toBeCalledWith(mockFilter, mockSearch)
})

it('should set values to sessionStorage on Apply', async () => {
const useKeysInContextMock = vi.spyOn(useKeys, 'useKeysInContext')
const setFilterAndSearchMock = vi.fn()

const mockSearch = 'search'
const mockFilter = 'Hash'

useKeysInContextMock.mockImplementation(() => ({
dbId: constants.DATABASE_ID,
dbIndex: 1,
setFilterAndSearch: setFilterAndSearchMock,
}))

render(<KeyTreeFilter />)

fireEvent.click(screen.getByTestId(TREE_FILTER_TRIGGER_BTN))

fireEvent.input(screen.getByTestId(SEARCH_INPUT), { target: { value: mockSearch } })

fireEvent.click(screen.getByTestId(FILTER_SELECT))

fireEvent.click(await screen.findByText(mockFilter))

await waitForStack()

fireEvent.click(screen.getByTestId(APPLY_BTN))

expect(sessionStorageService.set).toBeCalledWith(
`${StorageItem.keysTreeFilter + constants.DATABASE_ID + 1}`,
{ search: mockSearch, filter: mockFilter.toLowerCase() })
expect(setFilterAndSearchMock).toBeCalledWith(mockFilter.toLowerCase(), mockSearch)
})
})
Loading

0 comments on commit be6f0c8

Please sign in to comment.