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

Commit dbc8d5b

Browse files
authored
fix(plg): ensure invite flow is enabled only for embedded UI (#63466)
Makes the invite flow on "/cody/manage" page dependent on the `dotcom.codyProConfig.useEmbeddedUI` site config param. Previously we didn't have a check for this site config param on this page (to be precise, it's predecessor, see https://github.com/sourcegraph/sourcegraph/pull/63442). <!-- 💡 To write a useful PR description, make sure that your description covers: - WHAT this PR is changing: - How was it PREVIOUSLY. - How it will be from NOW on. - WHY this PR is needed. - CONTEXT, i.e. to which initiative, project or RFC it belongs. The structure of the description doesn't matter as much as covering these points, so use your best judgement based on your context. Learn how to write good pull request description: https://www.notion.so/sourcegraph/Write-a-good-pull-request-description-610a7fd3e613496eb76f450db5a49b6e?pvs=4 --> | `useEmbeddedUI` | Plan | Role | Screenshot | | -- | -- | -- | -- | | `false` | admin | Pro |<img width="1483" alt="Screenshot 2024-06-25 at 13 02 18" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/8d5687df-43a9-4dbe-b82c-ecc60696da0f">| | `false` | member | Pro |<img width="1483" alt="Screenshot 2024-06-25 at 13 14 17" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/cd53550c-5d51-4830-834c-1c233d13e72a">| | `false` | n/a | Free |<img width="1483" alt="Screenshot 2024-06-25 at 13 17 15" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/f18720d4-a000-4bfb-b948-bbda29e49911">| | `true` | admin | Pro |<img width="1483" alt="Screenshot 2024-06-25 at 13 30 03" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/618675d5-13b9-44b8-be50-4c506b46b702">| | `true` | member | Pro |<img width="1483" alt="Screenshot 2024-06-25 at 13 25 24" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/ccac77e8-c7ca-44a5-b033-3c6dad8e5d70">| | `true` | n/a | Free |<img width="1483" alt="Screenshot 2024-06-25 at 13 31 41" src="https://github.com/sourcegraph/sourcegraph/assets/25318659/a7373ae9-a440-4282-805f-018d703cf3b0">| ## Test plan - Tested manually (screenshots attached): - Run Sourcegraph instance in dotcom mode - Tweak `dotcom.codyProConfig.useEmbeddedUI` site config param, log in with users with different team roles (member/admin) and check results with the table above. <!-- All pull requests REQUIRE a test plan: https://docs-legacy.sourcegraph.com/dev/background-information/testing_principles --> <!-- 1. Ensure your pull request title is formatted as: $type($domain): $what 2. Add bullet list items for each additional detail you want to cover (see example below) 3. You can edit this after the pull request was merged, as long as release shipping it hasn't been promoted to the public. 4. For more information, please see this how-to https://www.notion.so/sourcegraph/Writing-a-changelog-entry-dd997f411d524caabf0d8d38a24a878c? Audience: TS/CSE > Customers > Teammates (in that order). Cheat sheet: $type = chore|fix|feat $domain: source|search|ci|release|plg|cody|local|... --> <!-- Example: Title: fix(search): parse quotes with the appropriate context Changelog section: ## Changelog - When a quote is used with regexp pattern type, then ... - Refactored underlying code. -->
1 parent 80827c7 commit dbc8d5b

File tree

1 file changed

+74
-49
lines changed

1 file changed

+74
-49
lines changed

client/web/src/cody/management/CodyManagementPage.tsx

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { AcceptInviteBanner } from '../invites/AcceptInviteBanner'
2525
import { InviteUsers } from '../invites/InviteUsers'
2626
import { isCodyEnabled } from '../isCodyEnabled'
2727
import { USER_CODY_PLAN, USER_CODY_USAGE } from '../subscription/queries'
28-
import { getManageSubscriptionPageURL } from '../util'
28+
import { getManageSubscriptionPageURL, isEmbeddedCodyProUIEnabled } from '../util'
2929

3030
import { useSubscriptionSummary } from './api/react-query/subscriptions'
3131
import { SubscriptionStats } from './SubscriptionStats'
@@ -70,7 +70,6 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
7070
)
7171

7272
const subscriptionSummaryQueryResult = useSubscriptionSummary()
73-
const isAdmin = subscriptionSummaryQueryResult?.data?.userRole === 'admin'
7473

7574
const subscription = data?.currentUser?.codySubscription
7675

@@ -80,26 +79,6 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
8079
}
8180
}, [data, navigate])
8281

83-
const getTeamInviteButton = (): JSX.Element | null => {
84-
const isSoloUser = subscriptionSummaryQueryResult?.data?.teamMaxMembers === 1
85-
const hasFreeSeats = subscriptionSummaryQueryResult?.data
86-
? subscriptionSummaryQueryResult.data.teamMaxMembers >
87-
subscriptionSummaryQueryResult.data.teamCurrentMembers
88-
: false
89-
const targetUrl = hasFreeSeats ? CodyProRoutes.ManageTeam : `${CodyProRoutes.NewProSubscription}?addSeats=1`
90-
const label = isSoloUser || hasFreeSeats ? 'Invite co-workers' : 'Add seats'
91-
92-
if (!subscriptionSummaryQueryResult?.data) {
93-
return null
94-
}
95-
96-
return (
97-
<Button as={Link} to={targetUrl} variant="success" className="text-nowrap">
98-
<Icon aria-hidden={true} svgPath={mdiPlusThick} /> {label}
99-
</Button>
100-
)
101-
}
102-
10382
const onClickUpgradeToProCTA = useCallback(() => {
10483
telemetryRecorder.recordEvent('cody.management.upgradeToProCTA', 'click')
10584
}, [telemetryRecorder])
@@ -116,12 +95,80 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
11695
return null
11796
}
11897

119-
const isUserOnProTier = subscription.plan === CodySubscriptionPlan.PRO
98+
// Generate invite-related widgets for the page.
99+
// The returned widgets depend on the user's role and subscription status.
100+
// Only applicable when embedded Cody Pro UI is enabled.
101+
const inviteWidgets = ((): {
102+
banner?: React.ReactElement
103+
link?: React.ReactElement
104+
form?: React.ReactElement
105+
} => {
106+
// Invites flow is supported only for embedded Cody UI.
107+
if (!isEmbeddedCodyProUIEnabled()) {
108+
return {}
109+
}
110+
111+
const banner = <AcceptInviteBanner onSuccess={refetch} />
112+
113+
const subscriptionSummary = subscriptionSummaryQueryResult.data
114+
// User is not admin: only banner widget is available from the invite flow (user with any role may get an invite).
115+
if (!subscriptionSummary || subscriptionSummary.userRole !== 'admin') {
116+
return { banner }
117+
}
118+
119+
// User is admin: define link and form widgets.
120+
121+
const form = <InviteUsers telemetryRecorder={telemetryRecorder} subscriptionSummary={subscriptionSummary} />
122+
123+
const isSoloUser = subscriptionSummary.teamMaxMembers === 1
124+
const hasFreeSeats = subscriptionSummary.teamMaxMembers > subscriptionSummary.teamCurrentMembers
125+
const targetUrl = hasFreeSeats ? CodyProRoutes.ManageTeam : `${CodyProRoutes.NewProSubscription}?addSeats=1`
126+
const label = isSoloUser || hasFreeSeats ? 'Invite co-workers' : 'Add seats'
127+
const link = (
128+
<Button as={Link} to={targetUrl} variant="success" className="text-nowrap">
129+
<Icon aria-hidden={true} svgPath={mdiPlusThick} /> {label}
130+
</Button>
131+
)
132+
133+
return { banner, link, form }
134+
})()
135+
136+
const pageHeaderLink: React.ReactNode = (() => {
137+
// If invites link widget is defined, render it.
138+
if (inviteWidgets.link) {
139+
return inviteWidgets.link
140+
}
141+
142+
// User already has a Pro subscription - render a link to the manage subscription page.
143+
if (subscription.plan === CodySubscriptionPlan.PRO) {
144+
return (
145+
<ButtonLink
146+
variant="primary"
147+
to={getManageSubscriptionPageURL()}
148+
onClick={() => {
149+
telemetryRecorder.recordEvent('cody.manageSubscription', 'click')
150+
}}
151+
>
152+
<Icon svgPath={mdiCreditCardOutline} className="mr-1" aria-hidden={true} />
153+
Manage subscription
154+
</ButtonLink>
155+
)
156+
}
157+
158+
// User is on a free plan. Render a link to the subscriptions page.
159+
return (
160+
<ButtonLink to={CodyProRoutes.Subscription} variant="primary" onClick={onClickUpgradeToProCTA}>
161+
Upgrade plan
162+
</ButtonLink>
163+
)
164+
})()
120165

121166
return (
122167
<Page className={classNames('d-flex flex-column')}>
123168
<PageTitle title="Dashboard" />
124-
<AcceptInviteBanner onSuccess={refetch} />
169+
170+
{inviteWidgets.banner}
171+
125172
{welcomeToPro && (
126173
<CodyAlert variant="greenCodyPro">
127174
<H2 className="mt-4">Welcome to Cody Pro</H2>
@@ -134,29 +181,12 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
134181
className="my-4 d-inline-flex align-items-center"
135182
actions={
136183
<div className="d-flex flex-column flex-gap-2">
137-
{isAdmin ? (
138-
getTeamInviteButton()
139-
) : isUserOnProTier ? (
140-
<ButtonLink
141-
variant="primary"
142-
to={getManageSubscriptionPageURL()}
143-
onClick={() => {
144-
telemetryRecorder.recordEvent('cody.manageSubscription', 'click')
145-
}}
146-
>
147-
<Icon svgPath={mdiCreditCardOutline} className="mr-1" aria-hidden={true} />
148-
Manage subscription
149-
</ButtonLink>
150-
) : (
151-
<ButtonLink to="/cody/subscription" variant="primary" onClick={onClickUpgradeToProCTA}>
152-
Upgrade plan
153-
</ButtonLink>
154-
)}
184+
{pageHeaderLink}
155185
<Link
156186
to="https://help.sourcegraph.com"
157187
target="_blank"
158188
rel="noreferrer"
159-
className="text-muted text-sm"
189+
className="text-muted text-center text-sm"
160190
>
161191
<Icon svgPath={mdiHelpCircleOutline} className="mr-1" aria-hidden={true} />
162192
Help &amp; community
@@ -170,12 +200,7 @@ export const CodyManagementPage: React.FunctionComponent<CodyManagementPageProps
170200
</PageHeader.Heading>
171201
</PageHeader>
172202

173-
{isAdmin && !!subscriptionSummaryQueryResult.data && (
174-
<InviteUsers
175-
telemetryRecorder={telemetryRecorder}
176-
subscriptionSummary={subscriptionSummaryQueryResult.data}
177-
/>
178-
)}
203+
{inviteWidgets.form}
179204

180205
<div className={classNames('border bg-1 mb-2', styles.container)}>
181206
<SubscriptionStats

0 commit comments

Comments
 (0)