Skip to content

Commit c61328c

Browse files
authored
RI-7196: add SavedQueriesScreen (#4803)
* RI-7196: add SavedQueriesScreen * fix border color * add SavedQueriesScreen tests * various style fixes, link saved queries * fix failing unit tests * fix manage indexes issue * update SavedQueriesScreen and tests * update HeaderActions tests
1 parent 5a6a10f commit c61328c

15 files changed

+603
-185
lines changed

redisinsight/ui/src/pages/vector-search/VectorSearchPage.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import React from 'react'
22
import { TelemetryPageView } from 'uiSrc/telemetry'
33
import { usePageViewTelemetry } from 'uiSrc/telemetry/usePageViewTelemetry'
44

5+
import { Loader } from 'uiSrc/components/base/display'
56
import { VectorSearchCreateIndex } from './create-index/VectorSearchCreateIndex'
67
import { VectorSearchQuery } from './query/VectorSearchQuery'
8+
import { VectorSearchPageWrapper } from './styles'
9+
import { useRedisearchListData } from './useRedisearchListData'
710

811
export const VectorSearchPage = () => {
9-
const hasIndexes = true
12+
const { data, loading } = useRedisearchListData()
13+
const hasIndexes = data?.length > 0
1014

1115
usePageViewTelemetry({
1216
page: TelemetryPageView.VECTOR_SEARCH_PAGE,
@@ -17,9 +21,10 @@ export const VectorSearchPage = () => {
1721
// `${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Vector Search`,
1822
// )
1923

20-
if (!hasIndexes) {
21-
return <VectorSearchCreateIndex />
22-
}
23-
24-
return <VectorSearchQuery />
24+
return (
25+
<VectorSearchPageWrapper>
26+
{loading && <Loader />}
27+
{hasIndexes ? <VectorSearchQuery /> : <VectorSearchCreateIndex />}
28+
</VectorSearchPageWrapper>
29+
)
2530
}

redisinsight/ui/src/pages/vector-search/create-index/VectorSearchCreateIndex.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ import { Button, SecondaryButton } from 'uiSrc/components/base/forms/buttons'
77
import { ChevronLeftIcon } from 'uiSrc/components/base/icons'
88

99
import { selectedBikesIndexFields, stepContents } from './steps'
10-
import {
11-
CreateIndexContent,
12-
CreateIndexFooter,
13-
CreateIndexHeader,
14-
CreateIndexWrapper,
15-
} from './styles'
1610
import {
1711
CreateSearchIndexParameters,
1812
PresetDataType,
@@ -21,6 +15,12 @@ import {
2115
SearchIndexType,
2216
} from './types'
2317
import { useCreateIndex } from './hooks/useCreateIndex'
18+
import {
19+
VectorSearchScreenContent,
20+
VectorSearchScreenFooter,
21+
VectorSearchScreenHeader,
22+
VectorSearchScreenWrapper,
23+
} from '../styles'
2424

2525
const stepNextButtonTexts = [
2626
'Proceed to adding data',
@@ -73,8 +73,8 @@ export const VectorSearchCreateIndex = ({
7373
}
7474

7575
return (
76-
<CreateIndexWrapper direction="column" justify="between">
77-
<CreateIndexHeader direction="row">
76+
<VectorSearchScreenWrapper direction="column" justify="between">
77+
<VectorSearchScreenHeader direction="row">
7878
<Title size="M" data-testid="title">
7979
New vector search
8080
</Title>
@@ -83,14 +83,14 @@ export const VectorSearchCreateIndex = ({
8383
<Stepper.Step>Adding data</Stepper.Step>
8484
<Stepper.Step>Create Index</Stepper.Step>
8585
</Stepper>
86-
</CreateIndexHeader>
87-
<CreateIndexContent direction="column" grow={1}>
86+
</VectorSearchScreenHeader>
87+
<VectorSearchScreenContent direction="column" grow={1}>
8888
<StepContent
8989
parameters={createSearchIndexParameters}
9090
setParameters={setParameters}
9191
/>
92-
</CreateIndexContent>
93-
<CreateIndexFooter direction="row">
92+
</VectorSearchScreenContent>
93+
<VectorSearchScreenFooter direction="row">
9494
{showBackButton && (
9595
<SecondaryButton
9696
iconSide="left"
@@ -101,8 +101,10 @@ export const VectorSearchCreateIndex = ({
101101
</SecondaryButton>
102102
)}
103103
<div />
104-
<Button loading={loading} onClick={onNextClick}>{stepNextButtonTexts[step]}</Button>
105-
</CreateIndexFooter>
106-
</CreateIndexWrapper>
104+
<Button loading={loading} onClick={onNextClick}>
105+
{stepNextButtonTexts[step]}
106+
</Button>
107+
</VectorSearchScreenFooter>
108+
</VectorSearchScreenWrapper>
107109
)
108110
}

redisinsight/ui/src/pages/vector-search/create-index/styles.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

redisinsight/ui/src/pages/vector-search/manage-indexes/ManageIndexesList.tsx

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
11
import { Loader } from '@redis-ui/components'
2-
import React, { useEffect } from 'react'
3-
import { useDispatch, useSelector } from 'react-redux'
4-
import {
5-
fetchRedisearchListAction,
6-
redisearchListSelector,
7-
} from 'uiSrc/slices/browser/redisearch'
8-
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
9-
import { bufferToString, isRedisearchAvailable } from 'uiSrc/utils'
2+
import React from 'react'
3+
4+
import { bufferToString } from 'uiSrc/utils'
105
import { StyledManageIndexesListAction } from './ManageIndexesList.styles'
116
import { IndexSection } from './IndexSection'
7+
import { useRedisearchListData } from '../useRedisearchListData'
128

139
export const ManageIndexesList = () => {
14-
const { loading, data } = useSelector(redisearchListSelector)
15-
const { modules, host: instanceHost } = useSelector(connectedInstanceSelector)
16-
17-
const dispatch = useDispatch()
18-
19-
useEffect(() => {
20-
if (!instanceHost) {
21-
return
22-
}
23-
24-
const moduleExists = isRedisearchAvailable(modules)
25-
if (moduleExists) {
26-
dispatch(fetchRedisearchListAction())
27-
}
28-
}, [instanceHost, modules])
10+
const { data, loading } = useRedisearchListData()
2911

3012
return (
3113
<StyledManageIndexesListAction data-testid="manage-indexes-list">

redisinsight/ui/src/pages/vector-search/query/HeaderActions.spec.tsx

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react'
22
import { cleanup, render, screen, userEvent } from 'uiSrc/utils/test-utils'
33

4-
import { HeaderActions } from './HeaderActions'
4+
import { HeaderActions, HeaderActionsProps } from './HeaderActions'
55

66
// Workaround for @redis-ui/components Title component issue with react-children-utilities
77
// TypeError: react_utils.childrenToString is not a function
@@ -10,11 +10,20 @@ jest.mock('uiSrc/components/base/layout/drawer', () => ({
1010
DrawerHeader: jest.fn().mockReturnValue(null),
1111
}))
1212

13-
const renderComponent = () => render(<HeaderActions />)
13+
const mockProps: HeaderActionsProps = {
14+
isManageIndexesDrawerOpen: false,
15+
setIsManageIndexesDrawerOpen: jest.fn(),
16+
isSavedQueriesOpen: false,
17+
setIsSavedQueriesOpen: jest.fn(),
18+
}
1419

15-
describe('ManageIndexesDrawer', () => {
20+
const renderComponent = (props = mockProps) =>
21+
render(<HeaderActions {...props} />)
22+
23+
describe('HeaderActions', () => {
1624
beforeEach(() => {
1725
cleanup()
26+
jest.clearAllMocks()
1827
})
1928

2029
it('should render', () => {
@@ -33,21 +42,63 @@ describe('ManageIndexesDrawer', () => {
3342
expect(manageIndexesButton).toBeInTheDocument()
3443
})
3544

36-
it('should open a drawer when "Manage indexes" is clicked', async () => {
37-
renderComponent()
45+
it('should call setIsSavedQueriesOpen when "Saved queries" is clicked', async () => {
46+
const mockSetIsSavedQueriesOpen = jest.fn()
47+
renderComponent({
48+
...mockProps,
49+
setIsSavedQueriesOpen: mockSetIsSavedQueriesOpen,
50+
})
3851

39-
const manageIndexesButton = screen.getByText('Manage indexes')
40-
expect(manageIndexesButton).toBeInTheDocument()
52+
const savedQueriesButton = screen.getByText('Saved queries')
53+
await userEvent.click(savedQueriesButton)
54+
55+
expect(mockSetIsSavedQueriesOpen).toHaveBeenCalledWith(true)
56+
})
57+
58+
it('should call setIsSavedQueriesOpen with false when "Saved queries" is clicked and isSavedQueriesOpen is true', async () => {
59+
const mockSetIsSavedQueriesOpen = jest.fn()
60+
renderComponent({
61+
...mockProps,
62+
isSavedQueriesOpen: true,
63+
setIsSavedQueriesOpen: mockSetIsSavedQueriesOpen,
64+
})
65+
66+
const savedQueriesButton = screen.getByText('Saved queries')
67+
await userEvent.click(savedQueriesButton)
4168

42-
// Simulate clicking the "Manage indexes" button
69+
expect(mockSetIsSavedQueriesOpen).toHaveBeenCalledWith(false)
70+
})
71+
72+
it('should call setIsManageIndexesDrawerOpen when "Manage indexes" is clicked', async () => {
73+
const mockSetIsManageIndexesDrawerOpen = jest.fn()
74+
renderComponent({
75+
...mockProps,
76+
setIsManageIndexesDrawerOpen: mockSetIsManageIndexesDrawerOpen,
77+
})
78+
79+
const manageIndexesButton = screen.getByText('Manage indexes')
4380
await userEvent.click(manageIndexesButton)
4481

45-
// Check if the drawer is opened
82+
expect(mockSetIsManageIndexesDrawerOpen).toHaveBeenCalledWith(true)
83+
})
84+
85+
it('should render ManageIndexesDrawer when isManageIndexesDrawerOpen is true', () => {
86+
renderComponent({
87+
...mockProps,
88+
isManageIndexesDrawerOpen: true,
89+
})
90+
4691
const drawer = screen.getByTestId('manage-indexes-drawer')
4792
expect(drawer).toBeInTheDocument()
93+
})
94+
95+
it('should not render ManageIndexesDrawer when isManageIndexesDrawerOpen is false', () => {
96+
renderComponent({
97+
...mockProps,
98+
isManageIndexesDrawerOpen: false,
99+
})
48100

49-
// Simulate clicking outside the drawer to close it
50-
await userEvent.click(document.body, { pointerEventsCheck: 0 })
101+
const drawer = screen.queryByTestId('manage-indexes-drawer')
51102
expect(drawer).not.toBeInTheDocument()
52103
})
53104
})

redisinsight/ui/src/pages/vector-search/query/HeaderActions.styles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const StyledHeaderAction = styled(FlexGroup)`
66
display: flex;
77
flex-direction: row;
88
justify-content: flex-end;
9+
margin-bottom: ${({ theme }) => theme.core.space.space200};
910
`
1011

1112
export const StyledTextButton = styled(TextButton)`
Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
import React, { useState } from 'react'
1+
import React from 'react'
22
import { StyledHeaderAction, StyledTextButton } from './HeaderActions.styles'
33
import { ManageIndexesDrawer } from '../manage-indexes/ManageIndexesDrawer'
44

5-
export const HeaderActions = () => {
6-
const [isManageIndexesDrawerOpen, setIsManageIndexesDrawerOpen] =
7-
useState<boolean>(false)
5+
export type HeaderActionsProps = {
6+
isManageIndexesDrawerOpen: boolean
7+
setIsManageIndexesDrawerOpen: (value: boolean) => void
8+
isSavedQueriesOpen: boolean
9+
setIsSavedQueriesOpen: (value: boolean) => void
10+
}
811

9-
return (
10-
<>
11-
<StyledHeaderAction data-testid="vector-search-header-actions">
12-
<StyledTextButton>Saved queries</StyledTextButton>
13-
<StyledTextButton onClick={() => setIsManageIndexesDrawerOpen(true)}>
14-
Manage indexes
15-
</StyledTextButton>
16-
</StyledHeaderAction>
12+
export const HeaderActions = ({
13+
isManageIndexesDrawerOpen,
14+
setIsManageIndexesDrawerOpen,
15+
isSavedQueriesOpen,
16+
setIsSavedQueriesOpen,
17+
}: HeaderActionsProps) => (
18+
<>
19+
<StyledHeaderAction data-testid="vector-search-header-actions">
20+
<StyledTextButton
21+
variant="primary"
22+
onClick={() => setIsSavedQueriesOpen(!isSavedQueriesOpen)}
23+
>
24+
Saved queries
25+
</StyledTextButton>
26+
<StyledTextButton onClick={() => setIsManageIndexesDrawerOpen(true)}>
27+
Manage indexes
28+
</StyledTextButton>
29+
</StyledHeaderAction>
1730

18-
<ManageIndexesDrawer
19-
open={isManageIndexesDrawerOpen}
20-
onOpenChange={setIsManageIndexesDrawerOpen}
21-
/>
22-
</>
23-
)
24-
}
31+
<ManageIndexesDrawer
32+
open={isManageIndexesDrawerOpen}
33+
onOpenChange={setIsManageIndexesDrawerOpen}
34+
/>
35+
</>
36+
)

redisinsight/ui/src/pages/vector-search/query/VectorSearchQuery.styles.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
import styled from 'styled-components'
2-
import { ResizableContainer } from 'uiSrc/components/base/layout'
3-
4-
export const StyledResizableContainer = styled(ResizableContainer)`
5-
padding: 10px;
6-
`
72

83
export const StyledNoResultsWrapper = styled.div`
94
display: flex;

0 commit comments

Comments
 (0)