Skip to content

Commit e80426c

Browse files
authored
Merge pull request #3402 from RedisInsight/fe/feature/RI-5759
#RI-5759 - open tutorials after load sample data, add links to tutorial
2 parents 6b19e23 + cd45f98 commit e80426c

File tree

14 files changed

+226
-56
lines changed

14 files changed

+226
-56
lines changed

redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.spec.tsx

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { apiService } from 'uiSrc/services'
2424
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
2525
import { RedisDefaultModules } from 'uiSrc/slices/interfaces'
2626
import { loadList } from 'uiSrc/slices/browser/redisearch'
27+
import { changeSelectedTab, changeSidePanel, resetExplorePanelSearch } from 'uiSrc/slices/panels/sidePanels'
28+
import { InsightsPanelTabs, SidePanels } from 'uiSrc/slices/interfaces/insights'
2729
import ExpertChat from './ExpertChat'
2830

2931
jest.mock('uiSrc/telemetry', () => ({
@@ -98,7 +100,7 @@ describe('ExpertChat', () => {
98100
messages: [],
99101
agreements: []
100102
});
101-
(connectedInstanceSelector as jest.Mock).mockImplementation(() => ({
103+
(connectedInstanceSelector as jest.Mock).mockImplementationOnce(() => ({
102104
modules: [{ name: RedisDefaultModules.FT }, { name: RedisDefaultModules.ReJSON }]
103105
}))
104106

@@ -111,7 +113,7 @@ describe('ExpertChat', () => {
111113
const sendEventTelemetryMock = jest.fn();
112114
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock);
113115

114-
(aiExpertChatSelector as jest.Mock).mockReturnValue({
116+
(aiExpertChatSelector as jest.Mock).mockReturnValueOnce({
115117
loading: false,
116118
messages: [],
117119
agreements: ['instanceId']
@@ -230,4 +232,37 @@ describe('ExpertChat', () => {
230232
});
231233
(sendEventTelemetry as jest.Mock).mockRestore()
232234
})
235+
236+
it('should call proper actions after click tutorial in the initial message', async () => {
237+
const sendEventTelemetryMock = jest.fn();
238+
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock);
239+
240+
(aiExpertChatSelector as jest.Mock).mockReturnValue({
241+
loading: false,
242+
messages: [],
243+
agreements: ['instanceId']
244+
})
245+
246+
render(<ExpertChat />, { store })
247+
248+
const afterRenderActions = [...store.getActions()]
249+
250+
fireEvent.click(screen.getByTestId('tutorial-initial-message-link'))
251+
252+
expect(store.getActions()).toEqual([
253+
...afterRenderActions,
254+
changeSelectedTab(InsightsPanelTabs.Explore),
255+
changeSidePanel(SidePanels.Insights),
256+
resetExplorePanelSearch()
257+
])
258+
259+
expect(sendEventTelemetry).toBeCalledWith({
260+
event: TelemetryEvent.EXPLORE_PANEL_TUTORIAL_OPENED,
261+
eventData: {
262+
databaseId: 'instanceId',
263+
source: 'sample_data'
264+
}
265+
});
266+
(sendEventTelemetry as jest.Mock).mockRestore()
267+
})
233268
})

redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { Ref, useCallback, useEffect, useRef, useState } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
3-
import { useParams } from 'react-router-dom'
3+
import { useHistory, useParams } from 'react-router-dom'
44
import { EuiIcon } from '@elastic/eui'
55
import {
66
aiExpertChatSelector,
@@ -9,20 +9,23 @@ import {
99
removeExpertChatHistoryAction,
1010
updateExpertChatAgreements,
1111
} from 'uiSrc/slices/panels/aiAssistant'
12-
import { getCommandsFromQuery, isRedisearchAvailable, Nullable, scrollIntoView } from 'uiSrc/utils'
12+
import { findTutorialPath, getCommandsFromQuery, isRedisearchAvailable, Nullable, scrollIntoView } from 'uiSrc/utils'
1313
import { connectedInstanceSelector, freeInstancesSelector } from 'uiSrc/slices/instances/instances'
1414

15-
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
15+
import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry'
1616
import { AiChatMessage, AiChatType } from 'uiSrc/slices/interfaces/aiAssistant'
1717
import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands'
1818
import { oauthCloudUserSelector } from 'uiSrc/slices/oauth/cloud'
1919
import { fetchRedisearchListAction } from 'uiSrc/slices/browser/redisearch'
2020
import TelescopeImg from 'uiSrc/assets/img/telescope-dark.svg?react'
21+
import { openTutorialByPath } from 'uiSrc/slices/panels/sidePanels'
22+
import { SAMPLE_DATA_TUTORIAL } from 'uiSrc/constants'
2123
import NoIndexesInitialMessage from './components/no-indexes-initial-message'
2224
import ExpertChatHeader from './components/expert-chat-header'
25+
import InitialMessage from './components/initial-message'
2326

2427
import { EXPERT_CHAT_AGREEMENTS } from '../texts'
25-
import { ChatForm, ChatHistory, ExpertChatInitialMessage } from '../shared'
28+
import { ChatForm, ChatHistory } from '../shared'
2629

2730
import styles from './styles.module.scss'
2831

@@ -44,6 +47,7 @@ const ExpertChat = () => {
4447
const isAgreementsAccepted = agreements.includes(instanceId) || messages.length > 0
4548

4649
const dispatch = useDispatch()
50+
const history = useHistory()
4751

4852
useEffect(() => {
4953
if (!instanceId) {
@@ -164,6 +168,19 @@ const ExpertChat = () => {
164168
})
165169
}, [])
166170

171+
const handleClickTutorial = () => {
172+
const tutorialPath = findTutorialPath({ id: SAMPLE_DATA_TUTORIAL })
173+
dispatch(openTutorialByPath(tutorialPath, history, true))
174+
175+
sendEventTelemetry({
176+
event: TelemetryEvent.EXPLORE_PANEL_TUTORIAL_OPENED,
177+
eventData: {
178+
databaseId: instanceId || TELEMETRY_EMPTY_VALUE,
179+
source: 'sample_data',
180+
}
181+
})
182+
}
183+
167184
const scrollToBottom = (behavior: ScrollBehavior = 'smooth') => {
168185
setTimeout(() => {
169186
scrollIntoView(scrollDivRef?.current, {
@@ -213,8 +230,8 @@ const ExpertChat = () => {
213230
isLoading={loading || isLoading}
214231
modules={modules}
215232
initialMessage={isNoIndexes
216-
? <NoIndexesInitialMessage onSuccess={getIndexes} />
217-
: ExpertChatInitialMessage}
233+
? <NoIndexesInitialMessage onClickTutorial={handleClickTutorial} onSuccess={getIndexes} />
234+
: <InitialMessage onClickTutorial={handleClickTutorial} />}
218235
inProgressMessage={inProgressMessage}
219236
history={messages}
220237
scrollDivRef={scrollDivRef}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react'
2+
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'
3+
4+
export interface Props {
5+
onClickTutorial: () => void
6+
}
7+
8+
const InitialMessage = (props: Props) => {
9+
const { onClickTutorial } = props
10+
11+
return (
12+
<>
13+
<EuiText size="xs">Welcome!</EuiText>
14+
<EuiText size="xs">I am here to help you get started with data querying.</EuiText>
15+
<EuiText size="xs">Type <b>/help</b> to get more info on what questions I can answer.</EuiText>
16+
<EuiSpacer />
17+
<EuiText size="xs">With <span style={{ color: 'red' }}>&hearts;</span>, your Redis Copilot!</EuiText>
18+
<EuiSpacer />
19+
<EuiText size="xs">
20+
Explore several common Redis use cases with our
21+
{' '}
22+
<EuiLink
23+
color="subdued"
24+
external={false}
25+
className="defaultLink"
26+
onClick={onClickTutorial}
27+
data-testid="tutorial-initial-message-link"
28+
>
29+
tutorial
30+
</EuiLink>
31+
, utilizing the provided sample data.
32+
</EuiText>
33+
</>
34+
)
35+
}
36+
37+
export default InitialMessage
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import InitialMessage from './InitialMessage'
2+
3+
export default InitialMessage

redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/components/no-indexes-initial-message/NoIndexesInitialMessage.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React, { useEffect } from 'react'
2-
import { EuiSpacer, EuiText } from '@elastic/eui'
3-
import LoadSampleData from 'uiSrc/pages/browser/components/load-sample-data'
2+
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'
43

54
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
5+
import LoadSampleData from 'uiSrc/pages/browser/components/load-sample-data'
66
import styles from './styles.module.scss'
77

88
export interface Props {
99
onSuccess?: () => void
10+
onClickTutorial: () => void
1011
}
1112

1213
const NoIndexesInitialMessage = (props: Props) => {
13-
const { onSuccess } = props
14+
const { onSuccess, onClickTutorial } = props
1415

1516
useEffect(() => {
1617
sendEventTelemetry({
@@ -21,13 +22,26 @@ const NoIndexesInitialMessage = (props: Props) => {
2122
return (
2223
<div data-testid="no-indexes-chat-message">
2324
<EuiText size="xs">Hi!</EuiText>
24-
<EuiText size="xs">I am here to help you get started with data querying.</EuiText>
25-
<EuiText size="xs">I noticed that you have no indexes created.</EuiText>
25+
<EuiText size="xs">I am here to help you get started with data querying. I noticed that you have no indexes created.</EuiText>
2626
<EuiSpacer />
2727
<EuiText size="xs">Would you like to load the sample data to see what Redis Copilot can help you do?</EuiText>
2828
<EuiSpacer />
2929
<LoadSampleData anchorClassName={styles.anchorClassName} onSuccess={onSuccess} />
30-
<EuiSpacer size="xs" />
30+
<EuiSpacer />
31+
<EuiText size="xs">
32+
Explore several common Redis use cases with our
33+
{' '}
34+
<EuiLink
35+
color="subdued"
36+
external={false}
37+
className="defaultLink"
38+
onClick={onClickTutorial}
39+
data-testid="tutorial-initial-message-link"
40+
>
41+
tutorial
42+
</EuiLink>
43+
, utilizing the provided sample data.
44+
</EuiText>
3145
</div>
3246
)
3347
}

redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/styles.module.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333
}
3434
}
3535
}
36+
37+
:global {
38+
.defaultLink {
39+
color: var(--externalLinkColor) !important;
40+
}
41+
}
3642
}
3743

3844
.iconTelescope {

redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/chat-history/texts.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,3 @@ export const AssistanceChatInitialMessage = (
1111
<EuiText size="xs">With <span style={{ color: 'red' }}>&hearts;</span>, your Redis Copilot!</EuiText>
1212
</>
1313
)
14-
15-
export const ExpertChatInitialMessage = (
16-
<>
17-
<EuiText size="xs">Welcome!</EuiText>
18-
<EuiText size="xs">I am here to help you get started with data querying.</EuiText>
19-
<EuiText size="xs">Type <b>/help</b> to get more info on what questions I can answer.</EuiText>
20-
<EuiSpacer />
21-
<EuiText size="xs">With <span style={{ color: 'red' }}>&hearts;</span>, your Redis Copilot!</EuiText>
22-
</>
23-
)

redisinsight/ui/src/constants/browser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { KeyValueFormat, SortOrder } from './keys'
22

3+
export const SAMPLE_DATA_TUTORIAL = 'redis_use_cases'
4+
35
export const DEFAULT_DELIMITER = ':'
46
export const DEFAULT_TREE_SORTING = SortOrder.ASC
57
export const DEFAULT_SHOW_HIDDEN_RECOMMENDATIONS = false

redisinsight/ui/src/pages/browser/components/load-sample-data/LoadSampleData.spec.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ import {
1212

1313
import { bulkImportDefaultData, bulkImportDefaultDataSuccess } from 'uiSrc/slices/browser/bulkActions'
1414
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
15-
import { changeKeyViewType, loadKeys } from 'uiSrc/slices/browser/keys'
1615
import { apiService } from 'uiSrc/services'
17-
import { KeyViewType } from 'uiSrc/slices/interfaces/keys'
1816
import { addMessageNotification } from 'uiSrc/slices/app/notifications'
1917
import successMessages from 'uiSrc/components/notifications/success-messages'
2018
import LoadSampleData from './LoadSampleData'
@@ -63,8 +61,6 @@ describe('LoadSampleData', () => {
6361
addMessageNotification(
6462
successMessages.UPLOAD_DATA_BULK()
6563
),
66-
changeKeyViewType(KeyViewType.Tree),
67-
loadKeys(),
6864
]
6965

7066
expect(store.getActions().slice(0, expectedActions.length)).toEqual(expectedActions)

redisinsight/ui/src/pages/browser/components/load-sample-data/LoadSampleData.tsx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ import { useDispatch, useSelector } from 'react-redux'
55

66
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
77
import { bulkActionsSelector, bulkImportDefaultDataAction } from 'uiSrc/slices/browser/bulkActions'
8-
import { changeKeyViewType, fetchKeys, keysSelector } from 'uiSrc/slices/browser/keys'
9-
import { KeyViewType, SearchMode } from 'uiSrc/slices/interfaces/keys'
10-
import { SCAN_TREE_COUNT_DEFAULT } from 'uiSrc/constants/api'
118

129
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
1310
import styles from './styles.module.scss'
@@ -23,30 +20,12 @@ const LoadSampleData = (props: Props) => {
2320

2421
const { id } = useSelector(connectedInstanceSelector)
2522
const { loading } = useSelector(bulkActionsSelector)
26-
const { viewType } = useSelector(keysSelector)
2723

2824
const dispatch = useDispatch()
2925

30-
const onSuccessImport = () => {
31-
if (onSuccess) {
32-
onSuccess()
33-
return
34-
}
35-
36-
if (viewType === KeyViewType.Browser) {
37-
dispatch(changeKeyViewType(KeyViewType.Tree))
38-
}
39-
40-
dispatch(fetchKeys({
41-
searchMode: SearchMode.Pattern,
42-
cursor: '0',
43-
count: SCAN_TREE_COUNT_DEFAULT
44-
}))
45-
}
46-
4726
const handleSampleData = () => {
4827
setIsConfirmationOpen(false)
49-
dispatch(bulkImportDefaultDataAction(id, onSuccessImport))
28+
dispatch(bulkImportDefaultDataAction(id, onSuccess))
5029

5130
sendEventTelemetry({
5231
event: TelemetryEvent.IMPORT_SAMPLES_CLICKED,

0 commit comments

Comments
 (0)