From 88d71af290e2d8ef563eb324f9986fe11050897e Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Mon, 3 Jun 2024 15:42:54 +0300 Subject: [PATCH] PLG: extract Cody Pro routes to a separate file (#63003) --- client/web/BUILD.bazel | 1 + client/web/src/auth/PostSignUpPage.tsx | 4 +- client/web/src/cody/codyProRoutes.tsx | 84 ++++++++++++++++ .../cody/management/CodyManagementPage.tsx | 4 +- .../manage/CodySubscriptionManagePage.tsx | 4 +- .../subscription/CodySubscriptionPage.tsx | 4 +- .../switch-account/CodySwitchAccountPage.tsx | 6 +- client/web/src/cody/util.ts | 4 +- .../src/marketing/toast/CodySurveyToast.tsx | 4 +- client/web/src/nav/GlobalNavbar.tsx | 5 +- client/web/src/routes.constants.ts | 13 --- client/web/src/routes.tsx | 96 +------------------ 12 files changed, 103 insertions(+), 126 deletions(-) create mode 100644 client/web/src/cody/codyProRoutes.tsx diff --git a/client/web/BUILD.bazel b/client/web/BUILD.bazel index 7e935d2fa04..da97cfe6036 100644 --- a/client/web/BUILD.bazel +++ b/client/web/BUILD.bazel @@ -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", diff --git a/client/web/src/auth/PostSignUpPage.tsx b/client/web/src/auth/PostSignUpPage.tsx index 6adb400ce9a..7a7ea24b74e 100644 --- a/client/web/src/auth/PostSignUpPage.tsx +++ b/client/web/src/auth/PostSignUpPage.tsx @@ -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 } diff --git a/client/web/src/cody/codyProRoutes.tsx b/client/web/src/cody/codyProRoutes.tsx new file mode 100644 index 00000000000..6715fff7f15 --- /dev/null +++ b/client/web/src/cody/codyProRoutes.tsx @@ -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: ( + ( + + )} + 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 { + 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 = props => { + const Component = routeComponents[props.path] + return +} diff --git a/client/web/src/cody/management/CodyManagementPage.tsx b/client/web/src/cody/management/CodyManagementPage.tsx index 23601b9d722..4b2ae639f11 100644 --- a/client/web/src/cody/management/CodyManagementPage.tsx +++ b/client/web/src/cody/management/CodyManagementPage.tsx @@ -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 = ({ - isSourcegraphDotCom, authenticatedUser, telemetryRecorder, }) => { @@ -96,7 +94,7 @@ export const CodyManagementPage: React.FunctionComponent {
- + Back to Cody Dashboard diff --git a/client/web/src/cody/subscription/CodySubscriptionPage.tsx b/client/web/src/cody/subscription/CodySubscriptionPage.tsx index e47b6d31702..96d770198b8 100644 --- a/client/web/src/cody/subscription/CodySubscriptionPage.tsx +++ b/client/web/src/cody/subscription/CodySubscriptionPage.tsx @@ -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 = ({ - isSourcegraphDotCom, authenticatedUser, telemetryRecorder, }) => { @@ -65,7 +63,7 @@ export const CodySubscriptionPage: React.FunctionComponent { if (accountSwitchNotRequired) { - navigate(PageRoutes.CodyManagement) + navigate(CodyProRoutes.Manage) } }, [accountSwitchNotRequired, navigate]) @@ -72,7 +72,7 @@ export const CodySwitchAccountPage: React.FunctionComponent{authenticatedUser.emails[0].email}
- + Continue diff --git a/client/web/src/cody/util.ts b/client/web/src/cody/util.ts index aa54115a0e1..c58c31e560e 100644 --- a/client/web/src/cody/util.ts +++ b/client/web/src/cody/util.ts @@ -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 } /** diff --git a/client/web/src/marketing/toast/CodySurveyToast.tsx b/client/web/src/marketing/toast/CodySurveyToast.tsx index 17246a383ec..76231c7c2c6 100644 --- a/client/web/src/marketing/toast/CodySurveyToast.tsx +++ b/client/web/src/marketing/toast/CodySurveyToast.tsx @@ -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) } diff --git a/client/web/src/nav/GlobalNavbar.tsx b/client/web/src/nav/GlobalNavbar.tsx index bd37bc13fe8..bcec2bb792e 100644 --- a/client/web/src/nav/GlobalNavbar.tsx +++ b/client/web/src/nav/GlobalNavbar.tsx @@ -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 = props => { , content: 'Cody AI', variant: navLinkVariant, @@ -381,7 +382,7 @@ export const InlineNavigationPanel: FC = props => { routeMatch={routeMatch} items={[ { - path: isSourcegraphDotCom ? PageRoutes.CodyManagement : PageRoutes.Cody, + path: isSourcegraphDotCom ? CodyProRoutes.Manage : PageRoutes.Cody, content: 'Dashboard', }, { diff --git a/client/web/src/routes.constants.ts b/client/web/src/routes.constants.ts index 2204777bc1d..78a8e714103 100644 --- a/client/web/src/routes.constants.ts +++ b/client/web/src/routes.constants.ts @@ -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', } diff --git a/client/web/src/routes.tsx b/client/web/src/routes.tsx index a77b1617363..e9031a7b2fb 100644 --- a/client/web/src/routes.tsx +++ b/client/web/src/routes.tsx @@ -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: ( - ( - - )} - condition={({ licenseFeatures }) => licenseFeatures.isCodyEnabled} - /> - ), - }, - { - path: PageRoutes.CodyManageTeam, - element: ( - ( - - )} - condition={({ isSourcegraphDotCom, licenseFeatures }) => - isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled() - } - /> - ), - }, - { - path: PageRoutes.CodyAcceptInvite, - element: ( - ( - - )} - condition={({ isSourcegraphDotCom, licenseFeatures }) => - isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled() - } - /> - ), - }, - { - path: PageRoutes.CodyNewProSubscription, - element: ( - ( - - )} - condition={({ isSourcegraphDotCom, licenseFeatures }) => - isSourcegraphDotCom && licenseFeatures.isCodyEnabled && isEmbeddedCodyProUIEnabled() - } - /> - ), - }, - { - path: PageRoutes.CodySubscription, - element: ( - ( - - )} - condition={({ licenseFeatures }) => licenseFeatures.isCodyEnabled} - /> - ), - }, - { - path: PageRoutes.CodySubscriptionManage, - element: ( - ( - - )} - condition={({ isSourcegraphDotCom }) => isSourcegraphDotCom && isEmbeddedCodyProUIEnabled()} - /> - ), - }, + ...codyProRoutes, ...communitySearchContextsRoutes, { path: PageRoutes.Cody,