Skip to content

Commit 658639a

Browse files
Fe/feature/ri 7687 rdi page navigation (#5125)
* RI-7687: use tabs for navigation in RDI (poc) * RI-7687: add tests and remove navigation from the left bar
1 parent 2723218 commit 658639a

File tree

7 files changed

+104
-89
lines changed

7 files changed

+104
-89
lines changed

redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,6 @@ describe('NavigationMenu', () => {
186186
})
187187
})
188188

189-
it('should render private routes with connectedRdiInstanceId', () => {
190-
;(appContextSelector as jest.Mock).mockImplementation(() => ({
191-
...appContextSelector,
192-
workspace: 'redisDataIntegration',
193-
}))
194-
195-
render(<NavigationMenu />)
196-
197-
expect(screen.getByTestId('pipeline-status-page-btn')).toBeTruthy()
198-
expect(screen.getByTestId('pipeline-management-page-btn')).toBeTruthy()
199-
})
200-
201189
describe('feature flags tests', () => {
202190
it('should show feature dependent items when feature flag is on', async () => {
203191
const initialStoreState = set(

redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import React from 'react'
44
import { FeatureFlags } from 'uiSrc/constants'
55
import { EXTERNAL_LINKS } from 'uiSrc/constants/links'
66

7-
import { renderOnboardingTourWithChild } from 'uiSrc/utils/onboarding'
87
import { FeatureFlagComponent } from 'uiSrc/components'
98

10-
import { RiBadge } from 'uiSrc/components/base/display/badge/RiBadge'
119
import {
1210
SideBar,
1311
SideBarContainer,
@@ -29,63 +27,11 @@ import styles from './styles.module.scss'
2927

3028
const NavigationMenu = () => {
3129
const {
32-
privateRdiRoutes,
3330
isRdiWorkspace,
3431
publicRoutes,
35-
getAdditionPropsForHighlighting,
3632
highlightedPages,
37-
connectedRdiInstanceId,
3833
} = useNavigation()
3934

40-
const renderNavItem = (nav: INavigations) => {
41-
const fragment = (
42-
<React.Fragment key={nav.tooltipText}>
43-
{renderOnboardingTourWithChild(
44-
<HighlightedFeature
45-
{...getAdditionPropsForHighlighting(nav.pageName)}
46-
key={nav.tooltipText}
47-
isHighlight={!!highlightedPages[nav.pageName]?.length}
48-
dotClassName={styles.highlightDot}
49-
tooltipPosition="right"
50-
transformOnHover
51-
>
52-
<div className={styles.navigationButtonWrapper}>
53-
<SideBarItem
54-
isActive={nav.isActivePage}
55-
onClick={nav.onClick}
56-
tooltipProps={{ text: nav.tooltipText, placement: 'right' }}
57-
>
58-
<SideBarItemIcon
59-
icon={nav.iconType}
60-
aria-label={nav.ariaLabel}
61-
data-testid={nav.dataTestId}
62-
/>
63-
</SideBarItem>
64-
{nav.isBeta && (
65-
<RiBadge className={styles.betaLabel} label="BETA" />
66-
)}
67-
</div>
68-
</HighlightedFeature>,
69-
{ options: nav.onboard },
70-
nav.isActivePage,
71-
`ob-${nav.tooltipText}`,
72-
)}
73-
</React.Fragment>
74-
)
75-
76-
return nav.featureFlag ? (
77-
<FeatureFlagComponent
78-
name={nav.featureFlag}
79-
key={nav.tooltipText}
80-
enabledByDefault
81-
>
82-
{fragment}
83-
</FeatureFlagComponent>
84-
) : (
85-
fragment
86-
)
87-
}
88-
8935
const renderPublicNavItem = (nav: INavigations) => {
9036
const fragment = (
9137
<HighlightedFeature
@@ -131,9 +77,6 @@ const NavigationMenu = () => {
13177
>
13278
<SideBarContainer>
13379
<RedisLogo isRdiWorkspace={isRdiWorkspace} />
134-
{connectedRdiInstanceId &&
135-
isRdiWorkspace &&
136-
privateRdiRoutes.map(renderNavItem)}
13780
</SideBarContainer>
13881
<SideBarFooter className={styles.footer}>
13982
<FeatureFlagComponent name={FeatureFlags.envDependent} enabledByDefault>

redisinsight/ui/src/components/navigation-menu/app-navigation/AppNavigation.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import {
55
StyledAppNavigation,
66
StyledAppNavigationContainer,
77
} from './AppNavigation.styles'
8-
import { useNavigation } from '../hooks/useNavigation'
98
import FeatureFlagComponent from 'uiSrc/components/feature-flag-component/FeatureFlagComponent'
109
import { FeatureFlags } from 'uiSrc/constants'
1110
import { OnboardingTourOptions } from 'uiSrc/components/onboarding-tour'
1211
import NavigationTabTrigger from './AppNavigationTabTrigger'
12+
import { INavigations } from 'uiSrc/components/navigation-menu/navigation.types'
1313

1414
type AppNavigationContainerProps = {
1515
children?: ReactNode
@@ -41,18 +41,18 @@ const AppNavigationContainer = ({
4141
)
4242

4343
export type AppNavigationProps = {
44+
routes: INavigations[]
4445
actions?: ReactNode
4546
onChange?: (tabValue: string) => void
4647
}
4748

48-
const AppNavigation = ({ actions, onChange }: AppNavigationProps) => {
49-
const { privateRoutes } = useNavigation()
50-
const activeTab = privateRoutes.find((route) => route.isActivePage)
49+
const AppNavigation = ({ actions, onChange, routes }: AppNavigationProps) => {
50+
const activeTab = routes.find((route) => route.isActivePage)
5151
const navTabs: (TabInfo & {
5252
isActivePage: boolean
5353
featureFlag?: FeatureFlags
5454
onboard?: OnboardingTourOptions
55-
})[] = privateRoutes.map((route) => ({
55+
})[] = routes.map((route) => ({
5656
label: route.tooltipText,
5757
content: '',
5858
value: route.pageName,
@@ -73,7 +73,7 @@ const AppNavigation = ({ actions, onChange }: AppNavigationProps) => {
7373
<Tabs.Compose
7474
value={activeTab?.pageName}
7575
onChange={(tabValue) => {
76-
const tabNavItem = privateRoutes.find(
76+
const tabNavItem = routes.find(
7777
(route) => route.pageName === tabValue,
7878
)
7979
if (tabNavItem) {

redisinsight/ui/src/components/navigation-menu/hooks/useNavigation.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,7 @@ export function useNavigation() {
147147

148148
const privateRdiRoutes: INavigations[] = [
149149
{
150-
tooltipText: 'Pipeline Status',
151-
pageName: PageNames.rdiStatistics,
152-
ariaLabel: 'Pipeline Status page button',
153-
onClick: () => handleGoPage(Pages.rdiStatistics(connectedRdiInstanceId)),
154-
dataTestId: 'pipeline-status-page-btn',
155-
isActivePage: activePage === `/${PageNames.rdiStatistics}`,
156-
iconType: PipelineStatisticsIcon,
157-
},
158-
{
159-
tooltipText: 'Pipeline Management',
150+
tooltipText: 'Pipeline',
160151
pageName: PageNames.rdiPipelineManagement,
161152
ariaLabel: 'Pipeline Management page button',
162153
onClick: () =>
@@ -165,6 +156,15 @@ export function useNavigation() {
165156
isActivePage: isPipelineManagementPath(),
166157
iconType: PipelineManagementIcon,
167158
},
159+
{
160+
tooltipText: 'Analytics',
161+
pageName: PageNames.rdiStatistics,
162+
ariaLabel: 'Pipeline Status page button',
163+
onClick: () => handleGoPage(Pages.rdiStatistics(connectedRdiInstanceId)),
164+
dataTestId: 'pipeline-status-page-btn',
165+
isActivePage: activePage === `/${PageNames.rdiStatistics}`,
166+
iconType: PipelineStatisticsIcon,
167+
},
168168
]
169169

170170
const publicRoutes: INavigations[] = [

redisinsight/ui/src/pages/rdi/instance/InstancePage.spec.tsx

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import React from 'react'
33
import reactRouterDom, { BrowserRouter } from 'react-router-dom'
44
import { instance, mock } from 'ts-mockito'
55

6-
import { act, cleanup, mockedStore, render } from 'uiSrc/utils/test-utils'
6+
import {
7+
act,
8+
cleanup,
9+
mockedStore,
10+
render,
11+
userEvent,
12+
} from 'uiSrc/utils/test-utils'
713
import { resetKeys, resetPatternKeysData } from 'uiSrc/slices/browser/keys'
814
import { setMonitorInitialState } from 'uiSrc/slices/cli/monitor'
915
import { setInitialPubSubState } from 'uiSrc/slices/pubsub/pubsub'
@@ -203,6 +209,35 @@ describe('InstancePage', () => {
203209
)
204210
})
205211

212+
it('should navigate to rdi pipeline management page via clicking on navigation', async () => {
213+
const pushMock = jest.fn()
214+
reactRouterDom.useHistory = jest.fn().mockReturnValue({
215+
push: pushMock,
216+
block: jest.fn(() => jest.fn()),
217+
})
218+
219+
reactRouterDom.useLocation = jest
220+
.fn()
221+
.mockReturnValue({ pathname: Pages.rdiStatistics(RDI_INSTANCE_ID_MOCK) })
222+
223+
const { getByRole } = render(
224+
<BrowserRouter>
225+
<InstancePage {...instance(mockedProps)} />
226+
</BrowserRouter>,
227+
)
228+
expect(pushMock).not.toHaveBeenCalledWith(
229+
Pages.rdiPipelineManagement(RDI_INSTANCE_ID_MOCK),
230+
)
231+
const analyticsTab = getByRole('tab', { name: 'Analytics' })
232+
expect(analyticsTab).toBeInTheDocument()
233+
234+
await userEvent.click(analyticsTab)
235+
236+
expect(pushMock).not.toHaveBeenCalledWith(
237+
Pages.rdiPipelineManagement(RDI_INSTANCE_ID_MOCK),
238+
)
239+
})
240+
206241
it('should redirect to rdi pipeline statistics page', async () => {
207242
;(appContextSelector as jest.Mock).mockReturnValue({
208243
contextRdiInstanceId: RDI_INSTANCE_ID_MOCK,
@@ -230,4 +265,35 @@ describe('InstancePage', () => {
230265
Pages.rdiStatistics(RDI_INSTANCE_ID_MOCK),
231266
)
232267
})
268+
269+
it('should navigate to rdi pipeline analytics page via clicking on navigation', async () => {
270+
const pushMock = jest.fn()
271+
reactRouterDom.useHistory = jest.fn().mockReturnValue({
272+
push: pushMock,
273+
block: jest.fn(() => jest.fn()),
274+
})
275+
276+
reactRouterDom.useLocation = jest
277+
.fn()
278+
.mockReturnValue({
279+
pathname: Pages.rdiPipelineManagement(RDI_INSTANCE_ID_MOCK),
280+
})
281+
282+
const { getByRole } = render(
283+
<BrowserRouter>
284+
<InstancePage {...instance(mockedProps)} />
285+
</BrowserRouter>,
286+
)
287+
expect(pushMock).not.toHaveBeenCalledWith(
288+
Pages.rdiStatistics(RDI_INSTANCE_ID_MOCK),
289+
)
290+
const pipelineTab = getByRole('tab', { name: 'Pipeline' })
291+
expect(pipelineTab).toBeInTheDocument()
292+
293+
await userEvent.click(pipelineTab)
294+
295+
expect(pushMock).not.toHaveBeenCalledWith(
296+
Pages.rdiStatistics(RDI_INSTANCE_ID_MOCK),
297+
)
298+
})
233299
})

redisinsight/ui/src/pages/rdi/instance/InstancePage.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from 'react'
1+
import React, { useEffect, useState } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
33
import { useHistory, useLocation, useParams } from 'react-router-dom'
44
import {
@@ -20,11 +20,13 @@ import {
2020
} from 'uiSrc/slices/instances/instances'
2121

2222
import { RdiInstancePageTemplate } from 'uiSrc/templates'
23-
import { RdiInstanceHeader } from 'uiSrc/components'
23+
import { AppNavigation, RdiInstanceHeader } from 'uiSrc/components'
2424
import { Col, FlexItem } from 'uiSrc/components/base/layout/flex'
2525
import InstancePageRouter from './InstancePageRouter'
2626
import { RdiPipelineHeader } from './components'
2727
import styles from './styles.module.scss'
28+
import { Nullable } from 'uiSrc/utils'
29+
import { useNavigation } from 'uiSrc/components/navigation-menu/hooks/useNavigation'
2830

2931
export interface Props {
3032
routes: IRoute[]
@@ -34,12 +36,15 @@ const RdiInstancePage = ({ routes = [] }: Props) => {
3436
const dispatch = useDispatch()
3537
const history = useHistory()
3638
const { pathname } = useLocation()
39+
const { privateRdiRoutes } = useNavigation()
3740

3841
const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>()
3942
const { lastPage, contextRdiInstanceId } = useSelector(appContextSelector)
4043
const { data: rdiInstances } = useSelector(rdiInstancesSelector)
4144
const { data: dbInstances } = useSelector(dbInstancesSelector)
4245

46+
const [actions, setActions] = useState<Nullable<React.ReactNode>>(null)
47+
4348
useEffect(() => {
4449
if (!dbInstances?.length) {
4550
dispatch(fetchInstancesAction())
@@ -80,6 +85,13 @@ const RdiInstancePage = ({ routes = [] }: Props) => {
8085
<FlexItem>
8186
<RdiInstanceHeader />
8287
</FlexItem>
88+
<FlexItem>
89+
<AppNavigation
90+
actions={actions}
91+
onChange={() => setActions(null)}
92+
routes={privateRdiRoutes}
93+
/>
94+
</FlexItem>
8395
<FlexItem grow={false}>
8496
<RdiPipelineHeader />
8597
</FlexItem>

redisinsight/ui/src/templates/instance-page-template/InstancePageTemplate.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ImperativePanelGroupHandle } from 'uiSrc/components/base/layout/resize'
2020
import { AppNavigation } from 'uiSrc/components'
2121
import { AppNavigationActionsProvider } from 'uiSrc/contexts/AppNavigationActionsProvider'
2222
import { Nullable } from 'uiSrc/utils'
23+
import { useNavigation } from 'uiSrc/components/navigation-menu/hooks/useNavigation'
2324

2425
export const firstPanelId = 'main-component'
2526
export const secondPanelId = 'cli'
@@ -51,6 +52,7 @@ const InstancePageTemplate = (props: Props) => {
5152

5253
const { isShowCli, isShowHelper } = useSelector(cliSettingsSelector)
5354
const { isShowMonitor } = useSelector(monitorSelector)
55+
const { privateRoutes } = useNavigation()
5456

5557
const ref = useRef<ImperativePanelGroupHandle>(null)
5658

@@ -92,7 +94,11 @@ const InstancePageTemplate = (props: Props) => {
9294
return (
9395
<>
9496
<InstanceHeader />
95-
<AppNavigation actions={actions} onChange={() => setActions(null)} />
97+
<AppNavigation
98+
actions={actions}
99+
onChange={() => setActions(null)}
100+
routes={privateRoutes}
101+
/>
96102
<Spacer size="m" />
97103
<ResizableContainer
98104
ref={ref}

0 commit comments

Comments
 (0)