PLG: extract Cody Pro routes to a separate file (#63003)

This commit is contained in:
Taras Yemets 2024-06-03 15:42:54 +03:00 committed by GitHub
parent df0c59ed12
commit 88d71af290
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 103 additions and 126 deletions

View File

@ -203,6 +203,7 @@ ts_project(
"src/cody/chat/CodyChatPage.tsx",
"src/cody/chat/CodyPageIcon.tsx",
"src/cody/chat/index.tsx",
"src/cody/codyProRoutes.tsx",
"src/cody/components/ChatUI/ChatUi.tsx",
"src/cody/components/ChatUI/index.tsx",
"src/cody/components/CodeMirrorEditor.ts",

View File

@ -2,7 +2,7 @@ import React from 'react'
import { Navigate, useLocation } from 'react-router-dom'
import { PageRoutes } from '../routes.constants'
import { CodyProRoutes } from '../cody/codyProRoutes'
import { getReturnTo } from './SignInSignUpCommon'
@ -14,7 +14,7 @@ export const PostSignUpPage: React.FunctionComponent = () => {
const params = new URLSearchParams()
params.set('returnTo', returnTo)
const navigateTo = PageRoutes.CodyManagement + '?' + params.toString()
const navigateTo = CodyProRoutes.Manage + '?' + params.toString()
return <Navigate to={navigateTo.toString()} replace={true} />
}

View File

@ -0,0 +1,84 @@
import type { RouteObject } from 'react-router-dom'
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
import { type LegacyLayoutRouteContext, LegacyRoute } from '../LegacyRouteContext'
import { isEmbeddedCodyProUIEnabled } from './util'
export enum CodyProRoutes {
// The checkout form for a new Cody Pro subscription.
NewProSubscription = '/cody/manage/subscription/new',
// The Manage page is labeled as the "Dashboard" page.
Manage = '/cody/manage',
// The Subscriptions page is a comparison of different Cody product tiers.
Subscription = '/cody/subscription',
SubscriptionManage = '/cody/subscription/manage',
ManageTeam = '/cody/team/manage',
// Accepts an invite to join a Cody team, then redirects to the Cody team page.
AcceptInvite = '/cody/invites/accept',
}
/**
* Generally available Cody Pro routes.
*/
const stableRoutes = new Set([CodyProRoutes.Manage, CodyProRoutes.Subscription])
/**
* Determines if a given Cody Pro route should be rendered.
* If the embedded Cody Pro UI is enabled, all routes including experimental are rendered.
* Otherwise, only the generally available routes are rendered.
*/
const isRouteEnabled = (path: CodyProRoutes): boolean => (isEmbeddedCodyProUIEnabled() ? true : stableRoutes.has(path))
export const codyProRoutes: RouteObject[] = Object.values(CodyProRoutes).map(path => ({
path,
element: (
<LegacyRoute
render={props => (
<CodyProPage
path={path}
authenticatedUser={props.authenticatedUser}
telemetryRecorder={props.platformContext.telemetryRecorder}
/>
)}
condition={({ isSourcegraphDotCom, licenseFeatures }) =>
isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isRouteEnabled(path)
}
/>
),
}))
const routeComponents = {
[CodyProRoutes.NewProSubscription]: lazyComponent(
() => import('./management/subscription/new/NewCodyProSubscriptionPage'),
'NewCodyProSubscriptionPage'
),
[CodyProRoutes.Manage]: lazyComponent(() => import('./management/CodyManagementPage'), 'CodyManagementPage'),
[CodyProRoutes.Subscription]: lazyComponent(
() => import('./subscription/CodySubscriptionPage'),
'CodySubscriptionPage'
),
[CodyProRoutes.SubscriptionManage]: lazyComponent(
() => import('./management/subscription/manage/CodySubscriptionManagePage'),
'CodySubscriptionManagePage'
),
[CodyProRoutes.ManageTeam]: lazyComponent(() => import('./team/CodyManageTeamPage'), 'CodyManageTeamPage'),
[CodyProRoutes.AcceptInvite]: lazyComponent(() => import('./invites/AcceptInvitePage'), 'CodyAcceptInvitePage'),
}
interface CodyProPageProps extends Pick<LegacyLayoutRouteContext, 'authenticatedUser' | 'telemetryRecorder'> {
path: CodyProRoutes
}
/**
* Renders the appropriate Cody Pro page component for the given route path.
*
* This is to more easily isolate the Cody Pro-specific functionality (which
* only applies to non-Enterprise users) from the rest of the Sourcegraph UI.
*/
const CodyProPage: React.FC<CodyProPageProps> = props => {
const Component = routeComponents[props.path]
return <Component authenticatedUser={props.authenticatedUser} telemetryRecorder={props.telemetryRecorder} />
}

View File

@ -31,7 +31,6 @@ import { UseCodyInEditorSection } from './UseCodyInEditorSection'
import styles from './CodyManagementPage.module.scss'
interface CodyManagementPageProps extends TelemetryV2Props {
isSourcegraphDotCom: boolean
authenticatedUser: AuthenticatedUser | null
}
@ -41,7 +40,6 @@ export enum EditorStep {
}
export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps> = ({
isSourcegraphDotCom,
authenticatedUser,
telemetryRecorder,
}) => {
@ -96,7 +94,7 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
throw dataError || usageDateError
}
if (!isCodyEnabled() || !isSourcegraphDotCom || !subscription) {
if (!isCodyEnabled() || !subscription) {
return null
}

View File

@ -17,7 +17,7 @@ import {
type UserCodyPlanVariables,
} from '../../../../graphql-operations'
import type { LegacyLayoutRouteContext } from '../../../../LegacyRouteContext'
import { PageRoutes } from '../../../../routes.constants'
import { CodyProRoutes } from '../../../codyProRoutes'
import { USER_CODY_PLAN } from '../../../subscription/queries'
import { Client } from '../../api/client'
import { useApiCaller } from '../../api/hooks/useApiClient'
@ -119,7 +119,7 @@ const PageContent: React.FC = () => {
</PageHeader>
<div className="my-3">
<Link to={PageRoutes.CodyManagement} className="d-flex align-items-center">
<Link to={CodyProRoutes.Manage} className="d-flex align-items-center">
<BackIcon className="mr-2" />
Back to Cody Dashboard
</Link>

View File

@ -34,12 +34,10 @@ import { USER_CODY_PLAN } from './queries'
import styles from './CodySubscriptionPage.module.scss'
interface CodySubscriptionPageProps extends TelemetryV2Props {
isSourcegraphDotCom: boolean
authenticatedUser?: AuthenticatedUser | null
}
export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageProps> = ({
isSourcegraphDotCom,
authenticatedUser,
telemetryRecorder,
}) => {
@ -65,7 +63,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
throw dataError
}
if (!isCodyEnabled() || !isSourcegraphDotCom || !data?.currentUser || !authenticatedUser) {
if (!isCodyEnabled() || !data?.currentUser || !authenticatedUser) {
return null
}

View File

@ -11,7 +11,7 @@ import { Button, ButtonLink, Card, AnchorLink, Text } from '@sourcegraph/wildcar
import type { AuthenticatedUser } from '../../auth'
import { Page } from '../../components/Page'
import { PageTitle } from '../../components/PageTitle'
import { PageRoutes } from '../../routes.constants'
import { CodyProRoutes } from '../codyProRoutes'
import styles from './CodySwitchAccountPage.module.scss'
@ -33,7 +33,7 @@ export const CodySwitchAccountPage: React.FunctionComponent<CodySwitchAccountPag
const accountSwitchNotRequired = !username || !authenticatedUser || authenticatedUser.username === username
useEffect(() => {
if (accountSwitchNotRequired) {
navigate(PageRoutes.CodyManagement)
navigate(CodyProRoutes.Manage)
}
}, [accountSwitchNotRequired, navigate])
@ -72,7 +72,7 @@ export const CodySwitchAccountPage: React.FunctionComponent<CodySwitchAccountPag
<Text className="mb-0 text-muted">{authenticatedUser.emails[0].email}</Text>
</div>
</div>
<ButtonLink to={PageRoutes.CodyManagement} variant="secondary">
<ButtonLink to={CodyProRoutes.Manage} variant="secondary">
Continue
</ButtonLink>
</Card>

View File

@ -1,7 +1,7 @@
// The URL to direct users in order to manage their Cody Pro subscription.
import { useState, useEffect } from 'react'
import { PageRoutes } from '../routes.constants'
import { CodyProRoutes } from './codyProRoutes'
// URL the user needs to navigate to in order to modify their Cody Pro subscription.
export const manageSubscriptionRedirectURL = `${
@ -24,7 +24,7 @@ export function isEmbeddedCodyProUIEnabled(): boolean {
* getManageSubscriptionPageURL returns the URL to direct the user to in order to manage their Cody Pro subscription.
*/
export function getManageSubscriptionPageURL(): string {
return isEmbeddedCodyProUIEnabled() ? PageRoutes.CodySubscriptionManage : manageSubscriptionRedirectURL
return isEmbeddedCodyProUIEnabled() ? CodyProRoutes.SubscriptionManage : manageSubscriptionRedirectURL
}
/**

View File

@ -13,6 +13,7 @@ import { Checkbox, Form, H3, Modal, Text, Button, Icon, AnchorLink } from '@sour
import type { AuthenticatedUser } from '../../auth'
import { getReturnTo } from '../../auth/SignInSignUpCommon'
import { CodyColorIcon } from '../../cody/chat/CodyPageIcon'
import { CodyProRoutes } from '../../cody/codyProRoutes'
import { LoaderButton } from '../../components/LoaderButton'
import type {
SubmitCodySurveyResult,
@ -20,7 +21,6 @@ import type {
SetCompletedPostSignupVariables,
SetCompletedPostSignupResult,
} from '../../graphql-operations'
import { PageRoutes } from '../../routes.constants'
import { resendVerificationEmail } from '../../user/settings/emails/UserEmail'
import { HubSpotForm } from '../components/HubSpotForm'
@ -341,7 +341,7 @@ export const CodySurveyToast: React.FC<
const handleSubmitEnd = (): void => {
// Redirects once user submits the post-sign-up form
const returnTo = getReturnTo(location, PageRoutes.CodyManagement)
const returnTo = getReturnTo(location, CodyProRoutes.Manage)
window.location.replace(returnTo)
}

View File

@ -29,6 +29,7 @@ import type { AuthenticatedUser } from '../auth'
import type { BatchChangesProps } from '../batches'
import { BatchChangesNavItem } from '../batches/BatchChangesNavItem'
import type { CodeMonitoringProps } from '../codeMonitoring'
import { CodyProRoutes } from '../cody/codyProRoutes'
import { CodyLogo } from '../cody/components/CodyLogo'
import { BrandLogo } from '../components/branding/BrandLogo'
import { useFuzzyFinderFeatureFlags } from '../components/fuzzyFinder/FuzzyFinderFeatureFlag'
@ -373,7 +374,7 @@ export const InlineNavigationPanel: FC<InlineNavigationPanelProps> = props => {
<NavDropdown
key="cody"
toggleItem={{
path: isSourcegraphDotCom ? PageRoutes.CodyManagement : PageRoutes.Cody,
path: isSourcegraphDotCom ? CodyProRoutes.Manage : PageRoutes.Cody,
icon: () => <CodyLogoWrapper />,
content: 'Cody AI',
variant: navLinkVariant,
@ -381,7 +382,7 @@ export const InlineNavigationPanel: FC<InlineNavigationPanelProps> = props => {
routeMatch={routeMatch}
items={[
{
path: isSourcegraphDotCom ? PageRoutes.CodyManagement : PageRoutes.Cody,
path: isSourcegraphDotCom ? CodyProRoutes.Manage : PageRoutes.Cody,
content: 'Dashboard',
},
{

View File

@ -39,19 +39,6 @@ export enum PageRoutes {
CodySearch = '/search/cody',
Cody = '/cody',
CodyChat = '/cody/chat',
// The checkout form for a new Cody Pro subscription.
CodyNewProSubscription = '/cody/manage/subscription/new',
// The CodyManagement page is labeled as the "Dashboard" page.
CodyManagement = '/cody/manage',
// The CodySubscriptions page is a comparison of different Cody product tiers.
CodySubscription = '/cody/subscription',
CodySubscriptionManage = '/cody/subscription/manage',
CodyManageTeam = '/cody/team/manage',
// Accepts an invite to join a Cody team, then redirects to the Cody team page.
CodyAcceptInvite = '/cody/invites/accept',
CodySwitchAccount = '/cody/switch-account/:username',
Own = '/own',
}

View File

@ -5,7 +5,7 @@ import { Navigate, useNavigate, type RouteObject } from 'react-router-dom'
import { useExperimentalFeatures } from '@sourcegraph/shared/src/settings/settings'
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
import { isEmbeddedCodyProUIEnabled } from './cody/util'
import { codyProRoutes } from './cody/codyProRoutes'
import { communitySearchContextsRoutes } from './communitySearchContexts/routes'
import { type LegacyLayoutRouteContext, LegacyRoute } from './LegacyRouteContext'
import { PageRoutes } from './routes.constants'
@ -65,25 +65,10 @@ const SearchUpsellPage = lazyComponent(() => import('./search/upsell/SearchUpsel
const SearchPageWrapper = lazyComponent(() => import('./search/SearchPageWrapper'), 'SearchPageWrapper')
const CodySearchPage = lazyComponent(() => import('./cody/search/CodySearchPage'), 'CodySearchPage')
const CodyChatPage = lazyComponent(() => import('./cody/chat/CodyChatPage'), 'CodyChatPage')
const CodyManagementPage = lazyComponent(() => import('./cody/management/CodyManagementPage'), 'CodyManagementPage')
const CodyManageTeamPage = lazyComponent(() => import('./cody/team/CodyManageTeamPage'), 'CodyManageTeamPage')
const CodyAcceptInvitePage = lazyComponent(() => import('./cody/invites/AcceptInvitePage'), 'CodyAcceptInvitePage')
const CodySwitchAccountPage = lazyComponent(
() => import('./cody/switch-account/CodySwitchAccountPage'),
'CodySwitchAccountPage'
)
const NewCodyProSubscriptionPage = lazyComponent(
() => import('./cody/management/subscription/new/NewCodyProSubscriptionPage'),
'NewCodyProSubscriptionPage'
)
const CodySubscriptionPage = lazyComponent(
() => import('./cody/subscription/CodySubscriptionPage'),
'CodySubscriptionPage'
)
const CodySubscriptionManagePage = lazyComponent(
() => import('./cody/management/subscription/manage/CodySubscriptionManagePage'),
'CodySubscriptionManagePage'
)
const CodyUpsellPage = lazyComponent(() => import('./cody/upsell/CodyUpsellPage'), 'CodyUpsellPage')
const CodyDashboardPage = lazyComponent(() => import('./cody/dashboard/CodyDashboardPage'), 'CodyDashboardPage')
const SearchJob = lazyComponent(() => import('./enterprise/search-jobs/SearchJobsPage'), 'SearchJobsPage')
@ -423,84 +408,7 @@ export const routes: RouteObject[] = [
/>
),
},
{
path: PageRoutes.CodyManagement,
element: (
<LegacyRoute
render={props => (
<CodyManagementPage {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />
)}
condition={({ licenseFeatures }) => licenseFeatures.isCodyEnabled}
/>
),
},
{
path: PageRoutes.CodyManageTeam,
element: (
<LegacyRoute
render={props => (
<CodyManageTeamPage {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />
)}
condition={({ isSourcegraphDotCom, licenseFeatures }) =>
isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled()
}
/>
),
},
{
path: PageRoutes.CodyAcceptInvite,
element: (
<LegacyRoute
render={props => (
<CodyAcceptInvitePage {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />
)}
condition={({ isSourcegraphDotCom, licenseFeatures }) =>
isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled()
}
/>
),
},
{
path: PageRoutes.CodyNewProSubscription,
element: (
<LegacyRoute
render={props => (
<NewCodyProSubscriptionPage
authenticatedUser={props.authenticatedUser}
telemetryRecorder={props.platformContext.telemetryRecorder}
/>
)}
condition={({ isSourcegraphDotCom, licenseFeatures }) =>
isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled()
}
/>
),
},
{
path: PageRoutes.CodySubscription,
element: (
<LegacyRoute
render={props => (
<CodySubscriptionPage {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />
)}
condition={({ licenseFeatures }) => licenseFeatures.isCodyEnabled}
/>
),
},
{
path: PageRoutes.CodySubscriptionManage,
element: (
<LegacyRoute
render={props => (
<CodySubscriptionManagePage
authenticatedUser={props.authenticatedUser}
telemetryRecorder={props.platformContext.telemetryRecorder}
/>
)}
condition={({ isSourcegraphDotCom }) => isSourcegraphDotCom && isEmbeddedCodyProUIEnabled()}
/>
),
},
...codyProRoutes,
...communitySearchContextsRoutes,
{
path: PageRoutes.Cody,