Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 3424ebb

Browse files
committed
feat(plg): add Cody Pro routes to the user nav dropdown
1 parent ebef38f commit 3424ebb

File tree

3 files changed

+103
-34
lines changed

3 files changed

+103
-34
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useMemo } from 'react'
2+
3+
import { CodyProRoutes } from './codyProRoutes'
4+
import { useSubscriptionSummary } from './management/api/react-query/subscriptions'
5+
import { getManageSubscriptionPageURL, isEmbeddedCodyProUIEnabled } from './util'
6+
7+
export const useCodyProNavLinks = (): { to: string; label: string }[] => {
8+
const { data } = useSubscriptionSummary()
9+
10+
return useMemo(() => {
11+
if (!data || data.userRole !== 'admin') {
12+
return []
13+
}
14+
const items = [{ to: getManageSubscriptionPageURL(), label: 'Manage subscription' }]
15+
16+
if (isEmbeddedCodyProUIEnabled()) {
17+
items.push({ to: CodyProRoutes.ManageTeam, label: 'Manage team' })
18+
}
19+
20+
return items
21+
}, [data])
22+
}

client/web/src/nav/UserNavItem.test.tsx

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { render, screen } from '@testing-library/react'
22
import userEvent from '@testing-library/user-event'
33
import { MemoryRouter } from 'react-router-dom'
44
import sinon from 'sinon'
5-
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest'
5+
import { afterAll, beforeAll, afterEach, describe, expect, test, vi, beforeEach } from 'vitest'
66

77
import { NOOP_TELEMETRY_SERVICE } from '@sourcegraph/shared/src/telemetry/telemetryService'
88
import { MockedTestProvider } from '@sourcegraph/shared/src/testing/apollo'
99
import { AnchorLink, RouterLink, setLinkComponent } from '@sourcegraph/wildcard'
1010
import { renderWithBrandedContext } from '@sourcegraph/wildcard/src/testing'
1111

12-
import { CodyProApiProvider } from '../cody/management/api/react-query/CodyProApiProvider'
12+
import * as codyProHooks from '../cody/useCodyProNavLinks'
1313

1414
import { UserNavItem, type UserNavItemProps } from './UserNavItem'
1515

@@ -28,6 +28,14 @@ describe('UserNavItem', () => {
2828
setLinkComponent(AnchorLink)
2929
})
3030

31+
const useCodyProNavLinksMock = vi.spyOn(codyProHooks, 'useCodyProNavLinks')
32+
beforeEach(() => {
33+
useCodyProNavLinksMock.mockReturnValue([])
34+
})
35+
afterEach(() => {
36+
useCodyProNavLinksMock.mockReset()
37+
})
38+
3139
const USER: UserNavItemProps['authenticatedUser'] = {
3240
username: 'alice',
3341
displayName: 'alice doe',
@@ -58,22 +66,18 @@ describe('UserNavItem', () => {
5866
emails: [],
5967
}
6068

61-
const isSourcegraphDotCom = true
62-
6369
test('simple', () => {
6470
expect(
6571
render(
6672
<MemoryRouter>
6773
<MockedTestProvider>
68-
<CodyProApiProvider isSourcegraphDotCom={isSourcegraphDotCom}>
69-
<UserNavItem
70-
showKeyboardShortcutsHelp={() => undefined}
71-
authenticatedUser={USER}
72-
isSourcegraphDotCom={true}
73-
showFeedbackModal={() => undefined}
74-
telemetryService={NOOP_TELEMETRY_SERVICE}
75-
/>
76-
</CodyProApiProvider>
74+
<UserNavItem
75+
showKeyboardShortcutsHelp={() => undefined}
76+
authenticatedUser={USER}
77+
isSourcegraphDotCom={true}
78+
showFeedbackModal={() => undefined}
79+
telemetryService={NOOP_TELEMETRY_SERVICE}
80+
/>
7781
</MockedTestProvider>
7882
</MemoryRouter>
7983
).asFragment()
@@ -83,15 +87,13 @@ describe('UserNavItem', () => {
8387
test('logout click triggers page refresh instead of performing client-side only navigation', async () => {
8488
const result = renderWithBrandedContext(
8589
<MockedTestProvider>
86-
<CodyProApiProvider isSourcegraphDotCom={isSourcegraphDotCom}>
87-
<UserNavItem
88-
showKeyboardShortcutsHelp={() => undefined}
89-
authenticatedUser={USER}
90-
isSourcegraphDotCom={isSourcegraphDotCom}
91-
showFeedbackModal={() => undefined}
92-
telemetryService={NOOP_TELEMETRY_SERVICE}
93-
/>
94-
</CodyProApiProvider>
90+
<UserNavItem
91+
showKeyboardShortcutsHelp={() => undefined}
92+
authenticatedUser={USER}
93+
isSourcegraphDotCom={true}
94+
showFeedbackModal={() => undefined}
95+
telemetryService={NOOP_TELEMETRY_SERVICE}
96+
/>
9597
</MockedTestProvider>
9698
)
9799

@@ -104,4 +106,54 @@ describe('UserNavItem', () => {
104106
expect(result.locationRef.entries.length).toBe(1)
105107
expect(result.locationRef.entries.find(({ pathname }) => pathname.includes('sign-out'))).toBe(undefined)
106108
})
109+
110+
describe('Cody Pro section', () => {
111+
const setup = (isSourcegraphDotCom: boolean) => {
112+
renderWithBrandedContext(
113+
<MockedTestProvider>
114+
<UserNavItem
115+
showKeyboardShortcutsHelp={() => undefined}
116+
authenticatedUser={USER}
117+
isSourcegraphDotCom={isSourcegraphDotCom}
118+
showFeedbackModal={() => undefined}
119+
telemetryService={NOOP_TELEMETRY_SERVICE}
120+
/>
121+
</MockedTestProvider>
122+
)
123+
userEvent.click(screen.getByRole('button'))
124+
}
125+
126+
describe('dotcom', () => {
127+
test('renders provided links', () => {
128+
const links = [
129+
{ to: '/foo', label: 'Foo' },
130+
{ to: '/bar', label: 'Bar' },
131+
]
132+
useCodyProNavLinksMock.mockReturnValue(links)
133+
setup(true)
134+
135+
for (const link of links) {
136+
const el = screen.getByText(link.label)
137+
expect(el).toHaveAttribute('href', link.to)
138+
}
139+
})
140+
141+
test('is not rendered if no links provided', () => {
142+
useCodyProNavLinksMock.mockReturnValue([])
143+
setup(true)
144+
145+
expect(useCodyProNavLinksMock).toHaveBeenCalled()
146+
expect(screen.queryByText('Cody Pro')).not.toBeInTheDocument()
147+
})
148+
})
149+
150+
describe('enterprise', () => {
151+
test('is not rendered', () => {
152+
setup(false)
153+
154+
// Cody Pro section is not rendered thus useCodyProNavLinks hook is not called
155+
expect(useCodyProNavLinksMock).not.toHaveBeenCalled()
156+
})
157+
})
158+
})
107159
})

client/web/src/nav/UserNavItem.tsx

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ import {
2626
} from '@sourcegraph/wildcard'
2727

2828
import type { AuthenticatedUser } from '../auth'
29-
import { CodyProRoutes } from '../cody/codyProRoutes'
30-
import { useSubscriptionSummary } from '../cody/management/api/react-query/subscriptions'
29+
import { useCodyProNavLinks } from '../cody/useCodyProNavLinks'
3130
import { enableDevSettings, isSourcegraphDev, useDeveloperSettings } from '../stores'
3231

3332
import { useNewSearchNavigation } from './new-global-navigation'
@@ -246,26 +245,22 @@ export const UserNavItem: FC<UserNavItemProps> = props => {
246245
}
247246

248247
const CodyProSection: React.FC = () => {
249-
const { data } = useSubscriptionSummary()
248+
const links = useCodyProNavLinks()
250249

251-
if (!data) {
250+
if (!links.length) {
252251
return null
253252
}
254253

255254
return (
256255
<>
257256
<MenuDivider className={styles.dropdownDivider} />
258257
<MenuHeader className={styles.dropdownHeader}>Cody PRO</MenuHeader>
259-
<MenuLink as={Link} to={CodyProRoutes.ManageTeam}>
260-
Manage team
261-
</MenuLink>
262258

263-
{/* only team admins can manage subscription */}
264-
{data.userRole === 'admin' && (
265-
<MenuLink as={Link} to={CodyProRoutes.SubscriptionManage}>
266-
Manage subscription
259+
{links.map(({ to, label }) => (
260+
<MenuLink as={Link} key={to} to={to}>
261+
{label}
267262
</MenuLink>
268-
)}
263+
))}
269264
</>
270265
)
271266
}

0 commit comments

Comments
 (0)