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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { InsightsPanelTabs } from 'uiSrc/slices/interfaces/insights'
import { recommendationsSelector } from 'uiSrc/slices/recommendations/recommendations'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
import { ONBOARDING_FEATURES } from 'uiSrc/components/onboarding-features'
import { OnboardingTour } from 'uiSrc/components'
import LiveTimeRecommendations from './panels/live-time-recommendations'
import EnablementAreaWrapper from './panels/enablement-area'

Expand Down Expand Up @@ -71,6 +73,8 @@ const DatabaseSidePanels = (props: Props) => {
}

const handleChangeTab = (name: string) => {
if (tabSelected === name) return

dispatch(changeSelectedTab(name))

sendEventTelemetry({
Expand Down Expand Up @@ -105,7 +109,14 @@ const DatabaseSidePanels = (props: Props) => {
className={styles.tab}
data-testid="explore-tab"
>
<span className={styles.tabName}>Explore Redis</span>
<OnboardingTour
options={ONBOARDING_FEATURES.EXPLORE_REDIS}
anchorPosition={isFullScreen ? 'rightUp' : 'leftUp'}
anchorWrapperClassName={styles.onboardingAnchorWrapper}
fullSize
>
<span className={styles.tabName}>Explore Redis</span>
</OnboardingTour>
</EuiTab>
<EuiTab
isSelected={tabSelected === InsightsPanelTabs.Recommendations}
Expand All @@ -126,7 +137,7 @@ const DatabaseSidePanels = (props: Props) => {
</>
</EuiTab>
</EuiTabs>
), [tabSelected, totalUnread])
), [tabSelected, totalUnread, isFullScreen])

return (
<div className={styles.wrapper}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const Group = (props: Props) => {
<>
{actions?.includes(EAItemActions.Create) && (
<OnboardingTour
options={ONBOARDING_FEATURES.WORKBENCH_CUSTOM_TUTORIALS}
options={ONBOARDING_FEATURES.EXPLORE_CUSTOM_TUTORIALS}
anchorPosition="downLeft"
anchorWrapperClassName="onboardingPopoverAnchor"
panelClassName={cx({ hide: isPageOpened })}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,7 @@ $animation-duration: 300ms;
}
}

.onboardingAnchorWrapper {
display: flex;
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { DatabaseAnalysisViewTab } from 'uiSrc/slices/interfaces/analytics'
import { fetchRedisearchListAction, loadList } from 'uiSrc/slices/browser/redisearch'
import { stringToBuffer } from 'uiSrc/utils'
import { RedisResponseBuffer } from 'uiSrc/slices/interfaces'
import { changeSelectedTab, toggleInsightsPanel } from 'uiSrc/slices/panels/insights'
import { InsightsPanelTabs } from 'uiSrc/slices/interfaces/insights'
import { ONBOARDING_FEATURES } from './OnboardingFeatures'

jest.mock('uiSrc/slices/app/features', () => ({
Expand Down Expand Up @@ -445,52 +447,76 @@ describe('ONBOARDING_FEATURES', () => {
fireEvent.click(screen.getByTestId('back-btn'))
expect(pushMock).toHaveBeenCalledWith(Pages.browser(''))
})

it('should call proper actions on next', () => {
render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_PAGE}><span /></OnboardingTour>)
fireEvent.click(screen.getByTestId('next-btn'))

const expectedActions = [
changeSelectedTab(InsightsPanelTabs.Explore),
toggleInsightsPanel(true),
setOnboardNextStep()
]
expect(clearStoreActions(store.getActions().slice(-3)))
.toEqual(clearStoreActions(expectedActions))
})
})

describe('WORKBENCH_ENABLEMENT_GUIDE', () => {
describe('EXPLORE_REDIS', () => {
beforeEach(() => {
(appFeatureOnboardingSelector as jest.Mock).mockReturnValue({
currentStep: OnboardingSteps.WorkbenchEnablementGuide,
currentStep: OnboardingSteps.Tutorials,
isActive: true,
totalSteps: Object.keys(ONBOARDING_FEATURES).length
})
})

it('should render', () => {
expect(
render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_ENABLEMENT_GUIDE}><span /></OnboardingTour>)
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_REDIS}><span /></OnboardingTour>)
).toBeTruthy()
expect(screen.getByTestId('step-content')).toHaveTextContent('Learn more about how Redis can solve your use cases using Guides and Tutorials.')
expect(screen.getByTestId('step-content')).toHaveTextContent('Learn more about how Redis can solve your use cases using interactive Tutorials.')
})

it('should call proper telemetry events', () => {
const sendEventTelemetryMock = jest.fn();
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)

render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_ENABLEMENT_GUIDE}><span /></OnboardingTour>)
checkAllTelemetryButtons(OnboardingStepName.WorkbenchGuides, sendEventTelemetry as jest.Mock)
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_REDIS}><span /></OnboardingTour>)
checkAllTelemetryButtons(OnboardingStepName.ExploreTutorials, sendEventTelemetry as jest.Mock)
})

it('should call proper actions init', () => {
render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_ENABLEMENT_GUIDE}><span /></OnboardingTour>)
it('should properly push history on back', () => {
const pushMock = jest.fn()
reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock })

const expectedActions = []
expect(clearStoreActions(store.getActions())).toEqual(clearStoreActions(expectedActions))
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_REDIS}><span /></OnboardingTour>)
fireEvent.click(screen.getByTestId('back-btn'))
expect(pushMock).toHaveBeenCalledWith(Pages.workbench(''))
})

it('should call proper actions on back', () => {
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_REDIS}><span /></OnboardingTour>)
fireEvent.click(screen.getByTestId('back-btn'))

const expectedActions = [toggleInsightsPanel(false), setOnboardPrevStep()]
expect(clearStoreActions(store.getActions().slice(-2)))
.toEqual(clearStoreActions(expectedActions))
})
})

describe('WORKBENCH_CUSTOM_TUTORIALS', () => {
beforeEach(() => {
(appFeatureOnboardingSelector as jest.Mock).mockReturnValue({
currentStep: OnboardingSteps.WorkbenchCustomTutorials,
currentStep: OnboardingSteps.CustomTutorials,
isActive: true,
totalSteps: Object.keys(ONBOARDING_FEATURES).length
})
})

it('should render', () => {
expect(
render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
).toBeTruthy()
expect(screen.getByTestId('step-content')).toHaveTextContent('Share your Redis expertise with your team and the wider community by building custom RedisInsight tutorials.')
})
Expand All @@ -499,22 +525,24 @@ describe('ONBOARDING_FEATURES', () => {
const sendEventTelemetryMock = jest.fn();
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)

render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
checkAllTelemetryButtons(OnboardingStepName.WorkbenchCustomTutorials, sendEventTelemetry as jest.Mock)
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
checkAllTelemetryButtons(OnboardingStepName.ExploreCustomTutorials, sendEventTelemetry as jest.Mock)
})

it('should call proper actions init', () => {
render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
it('should call proper actions on next', () => {
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
fireEvent.click(screen.getByTestId('next-btn'))

const expectedActions = []
expect(clearStoreActions(store.getActions())).toEqual(clearStoreActions(expectedActions))
const expectedActions = [toggleInsightsPanel(false), setOnboardNextStep()]
expect(clearStoreActions(store.getActions().slice(-2)))
.toEqual(clearStoreActions(expectedActions))
})

it('should properly push history on next', () => {
const pushMock = jest.fn()
reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock })

render(<OnboardingTour options={ONBOARDING_FEATURES.WORKBENCH_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
render(<OnboardingTour options={ONBOARDING_FEATURES.EXPLORE_CUSTOM_TUTORIALS}><span /></OnboardingTour>)
fireEvent.click(screen.getByTestId('next-btn'))
expect(pushMock).toHaveBeenCalledWith(Pages.clusterDetails(''))
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { fetchRedisearchListAction } from 'uiSrc/slices/browser/redisearch'
import { bufferToString, Nullable } from 'uiSrc/utils'
import { CodeBlock } from 'uiSrc/components'

import { changeSelectedTab, toggleInsightsPanel } from 'uiSrc/slices/panels/insights'
import { InsightsPanelTabs } from 'uiSrc/slices/interfaces/insights'
import styles from './styles.module.scss'

const sendTelemetry = (databaseId: string, step: string, action: string) => sendEventTelemetry({
Expand Down Expand Up @@ -199,7 +201,7 @@ const ONBOARDING_FEATURES = {
(indexes) => {
setFirstIndex(indexes?.length ? bufferToString(indexes[0]) : '')
},
undefined,
() => setFirstIndex(''),
false
))
}, [])
Expand Down Expand Up @@ -253,47 +255,44 @@ const ONBOARDING_FEATURES = {
dispatch(showMonitor())
sendBackTelemetryEvent(...telemetryArgs)
},
onNext: () => sendNextTelemetryEvent(...telemetryArgs),
onNext: () => {
dispatch(changeSelectedTab(InsightsPanelTabs.Explore))
dispatch(toggleInsightsPanel(true))
sendNextTelemetryEvent(...telemetryArgs)
},
}
}
},
WORKBENCH_ENABLEMENT_GUIDE: {
step: OnboardingSteps.WorkbenchEnablementGuide,
EXPLORE_REDIS: {
step: OnboardingSteps.Tutorials,
title: 'Explore and learn more',
Inner: () => {
const { id: connectedInstanceId = '' } = useSelector(connectedInstanceSelector)
const dispatch = useDispatch()
const telemetryArgs: TelemetryArgs = [connectedInstanceId, OnboardingStepName.WorkbenchGuides]
const telemetryArgs: TelemetryArgs = [connectedInstanceId, OnboardingStepName.ExploreTutorials]

useEffect(() => {
// here we can use it on mount, because enablement area always rendered on workbench
// dispatch(setWorkbenchEAOpened(false))
}, [])
const history = useHistory()
const dispatch = useDispatch()

return {
content: 'Learn more about how Redis can solve your use cases using Guides and Tutorials.',
content: 'Learn more about how Redis can solve your use cases using interactive Tutorials.',
onSkip: () => sendClosedTelemetryEvent(...telemetryArgs),
onBack: () => sendBackTelemetryEvent(...telemetryArgs),
onBack: () => {
history.push(Pages.workbench(connectedInstanceId))
dispatch(toggleInsightsPanel(false))
sendBackTelemetryEvent(...telemetryArgs)
},
onNext: () => sendNextTelemetryEvent(...telemetryArgs)
}
}
},
WORKBENCH_CUSTOM_TUTORIALS: {
step: OnboardingSteps.WorkbenchCustomTutorials,
EXPLORE_CUSTOM_TUTORIALS: {
step: OnboardingSteps.CustomTutorials,
title: 'Upload your tutorials',
Inner: () => {
const { id: connectedInstanceId = '' } = useSelector(connectedInstanceSelector)
const history = useHistory()
const dispatch = useDispatch()
const telemetryArgs: TelemetryArgs = [connectedInstanceId, OnboardingStepName.WorkbenchCustomTutorials]

useEffect(() => {
// here we can use it on mount, because enablement area always rendered on workbench
// dispatch(setWorkbenchEAOpened(false))
// close opened page
// dispatch(resetExplorePanelSearchContext())
history.push(Pages.workbench(connectedInstanceId))
}, [])
const telemetryArgs: TelemetryArgs = [connectedInstanceId, OnboardingStepName.ExploreCustomTutorials]

return {
content: (
Expand All @@ -308,6 +307,7 @@ const ONBOARDING_FEATURES = {
onSkip: () => sendClosedTelemetryEvent(...telemetryArgs),
onBack: () => sendBackTelemetryEvent(...telemetryArgs),
onNext: () => {
dispatch(toggleInsightsPanel(false))
history.push(Pages.clusterDetails(connectedInstanceId))
sendNextTelemetryEvent(...telemetryArgs)
}
Expand All @@ -320,6 +320,7 @@ const ONBOARDING_FEATURES = {
Inner: () => {
const { id: connectedInstanceId = '' } = useSelector(connectedInstanceSelector)
const history = useHistory()
const dispatch = useDispatch()
const telemetryArgs: TelemetryArgs = [connectedInstanceId, OnboardingStepName.ClusterOverview]

return {
Expand All @@ -331,6 +332,8 @@ const ONBOARDING_FEATURES = {
),
onSkip: () => sendClosedTelemetryEvent(...telemetryArgs),
onBack: () => {
dispatch(changeSelectedTab(InsightsPanelTabs.Explore))
dispatch(toggleInsightsPanel(true))
history.push(Pages.workbench(connectedInstanceId))
sendBackTelemetryEvent(...telemetryArgs)
},
Expand Down Expand Up @@ -364,6 +367,8 @@ const ONBOARDING_FEATURES = {
onSkip: () => sendClosedTelemetryEvent(...telemetryArgs),
onBack: () => {
if (connectionType !== ConnectionType.Cluster) {
dispatch(changeSelectedTab(InsightsPanelTabs.Explore))
dispatch(toggleInsightsPanel(true))
dispatch(setOnboardPrevStep())
history.push(Pages.workbench(connectedInstanceId))
}
Expand Down
7 changes: 6 additions & 1 deletion redisinsight/ui/src/components/query/Query/Query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const Query = (props: Props) => {
const { items: execHistoryItems, loading, processing } = useSelector(workbenchResultsSelector)
const { theme } = useContext(ThemeContext)
const monacoObjects = useRef<Nullable<IEditorMount>>(null)
const runTooltipRef = useRef<EuiToolTip>(null)

const { instanceId = '' } = useParams<{ instanceId: string }>()

Expand Down Expand Up @@ -492,6 +493,7 @@ const Query = (props: Props) => {
</EuiButton>
</EuiToolTip>
<EuiToolTip
ref={runTooltipRef}
position="left"
content={
isLoading
Expand All @@ -514,7 +516,10 @@ const Query = (props: Props) => {
<EuiLoadingSpinner size="l" data-testid="loading-spinner" />
)}
<EuiButtonIcon
onClick={() => handleSubmit()}
onClick={() => {
handleSubmit()
setTimeout(() => runTooltipRef?.current?.hideToolTip?.(), 0)
}}
disabled={isLoading}
iconType="playFilled"
className={cx(styles.submitButton, { [styles.submitButtonLoading]: isLoading })}
Expand Down
8 changes: 4 additions & 4 deletions redisinsight/ui/src/constants/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ enum OnboardingSteps {
BrowserProfiler,
// BrowserInsights,
WorkbenchPage,
WorkbenchEnablementGuide,
WorkbenchCustomTutorials,
Tutorials,
CustomTutorials,
AnalyticsOverview,
AnalyticsDatabaseAnalysis,
AnalyticsRecommendations,
Expand All @@ -30,8 +30,8 @@ enum OnboardingStepName {
BrowserProfiler = 'browser_profiler',
BrowserInsights = 'browser_insights',
WorkbenchIntro = 'workbench_intro',
WorkbenchGuides = 'workbench_guides',
WorkbenchCustomTutorials = 'workbench_custom_tutorials',
ExploreTutorials = 'insights_explore_tutorials',
ExploreCustomTutorials = 'insights_explore_custom_tutorials',
ClusterOverview = 'cluster_overview',
DatabaseAnalysisOverview = 'database_analysis_overview',
DatabaseAnalysisRecommendations = 'database_analysis_recommendations',
Expand Down
Loading