Skip to content

Commit 47ea9a7

Browse files
authored
Undo reverts (#5507)
* Reapply "MNTOR-3814 - use context to fetch experiment data from Cirrus (#5440)" (#5505) This reverts commit 80e7178. * Revert "handle nimbus user id not set (#5503)" This reverts commit 4de104f.
1 parent 80e7178 commit 47ea9a7

File tree

11 files changed

+420
-23
lines changed

11 files changed

+420
-23
lines changed

src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export default async function DashboardPage({ params, searchParams }: Props) {
167167
totalNumberOfPerformedScans={profileStats?.total}
168168
isNewUser={isNewUser}
169169
elapsedTimeInDaysSinceInitialScan={elapsedTimeInDaysSinceInitialScan}
170-
experimentData={experimentData}
170+
experimentData={experimentData["Features"]}
171171
activeTab={activeTab}
172172
hasFirstMonitoringScan={hasFirstMonitoringScan}
173173
signInCount={signInCount}

src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/settings/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export default async function SettingsPage({ params, searchParams }: Props) {
125125
yearlySubscriptionUrl={`${yearlySubscriptionUrl}&${additionalSubplatParams.toString()}`}
126126
subscriptionBillingAmount={getSubscriptionBillingAmount()}
127127
enabledFeatureFlags={enabledFeatureFlags}
128-
experimentData={experimentData}
128+
experimentData={experimentData["Features"]}
129129
lastScanDate={lastOneRepScan?.created_at}
130130
isMonthlySubscriber={isMonthlySubscriber}
131131
activeTab={activeTab}

src/app/(proper_react)/(redesign)/(authenticated)/user/welcome/[[...slug]]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export default async function Onboarding({ params, searchParams }: Props) {
7777
breachesTotalCount={allBreachesCount}
7878
stepId={firstSlug === FreeScanSlug ? "enterInfo" : "getStarted"}
7979
previousRoute={previousRoute}
80-
experimentData={experimentData}
80+
experimentData={experimentData["Features"]}
8181
/>
8282
);
8383
}

src/app/(proper_react)/(redesign)/(public)/page.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,39 +59,41 @@ export default async function Page({ searchParams }: Props) {
5959
oneRepActivations > monthlySubscribersQuota;
6060
return (
6161
<AccountsMetricsFlowProvider
62-
enabled={experimentData["landing-page-free-scan-cta"].enabled}
62+
enabled={experimentData["Features"]["landing-page-free-scan-cta"].enabled}
6363
metricsFlowParams={{
6464
entrypoint: CONST_URL_MONITOR_LANDING_PAGE_ID,
6565
entrypoint_experiment: "landing-page-free-scan-cta",
6666
entrypoint_variation:
67-
experimentData["landing-page-free-scan-cta"].variant,
67+
experimentData["Features"]["landing-page-free-scan-cta"].variant,
6868
form_type:
69-
experimentData["landing-page-free-scan-cta"].variant ===
69+
experimentData["Features"]["landing-page-free-scan-cta"].variant ===
7070
"ctaWithEmail"
7171
? "email"
7272
: "button",
7373
service: process.env.OAUTH_CLIENT_ID as string,
7474
}}
7575
>
7676
{enabledFeatureFlags.includes("LandingPageRedesign") &&
77-
experimentData["landing-page-redesign-plus-eligible-experiment"]
78-
.enabled &&
79-
experimentData["landing-page-redesign-plus-eligible-experiment"]
80-
.variant === "redesign" ? (
77+
experimentData["Features"][
78+
"landing-page-redesign-plus-eligible-experiment"
79+
].enabled &&
80+
experimentData["Features"][
81+
"landing-page-redesign-plus-eligible-experiment"
82+
].variant === "redesign" ? (
8183
<LandingViewRedesign
8284
eligibleForPremium={eligibleForPremium}
8385
l10n={getL10n()}
8486
countryCode={countryCode}
8587
scanLimitReached={scanLimitReached}
86-
experimentData={experimentData}
88+
experimentData={experimentData["Features"]}
8789
/>
8890
) : (
8991
<LandingView
9092
eligibleForPremium={eligibleForPremium}
9193
l10n={getL10n()}
9294
countryCode={countryCode}
9395
scanLimitReached={scanLimitReached}
94-
experimentData={experimentData}
96+
experimentData={experimentData["Features"]}
9597
/>
9698
)}
9799
</AccountsMetricsFlowProvider>

src/app/api/v1/user/welcome-scan/create/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export async function POST(
9898
previewMode: searchParams.get("nimbus_preview") === "true",
9999
});
100100
const optionalInfoExperimentData =
101-
experimentData["welcome-scan-optional-info"];
101+
experimentData["Features"]["welcome-scan-optional-info"];
102102

103103
const profileData: CreateProfileRequest = {
104104
first_name: firstName,

src/app/functions/server/getExperiments.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export async function getExperiments(params: {
2828
locale: string;
2929
countryCode: string;
3030
previewMode: boolean;
31-
}): Promise<ExperimentData["Features"]> {
31+
}): Promise<ExperimentData> {
3232
if (["local"].includes(process.env.APP_ENV ?? "local")) {
33-
return localExperimentData["Features"];
33+
return localExperimentData;
3434
}
3535

3636
if (!process.env.NIMBUS_SIDECAR_URL) {
@@ -87,10 +87,7 @@ export async function getExperiments(params: {
8787
experimentData = json;
8888
}
8989

90-
return (
91-
(experimentData as ExperimentData["Features"]) ??
92-
defaultExperimentData["Features"]
93-
);
90+
return (experimentData as ExperimentData) ?? defaultExperimentData;
9491
} catch (ex) {
9592
logger.error("Could not connect to Cirrus", {
9693
serverUrl,
@@ -99,6 +96,6 @@ export async function getExperiments(params: {
9996
params,
10097
});
10198
captureException(ex);
102-
return defaultExperimentData["Features"];
99+
return defaultExperimentData;
103100
}
104101
}

src/app/hooks/useGlean.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ import EventMetricType from "@mozilla/glean/private/metrics/event";
99
import type { GleanMetricMap } from "../../telemetry/generated/_map";
1010
import { useSession } from "next-auth/react";
1111
import { hasPremium } from "../functions/universal/user";
12+
import { useExperiments } from "../../contextProviders/experiments";
1213

1314
export const useGlean = () => {
1415
const session = useSession();
16+
const experimentData = useExperiments();
17+
// Telemetry recording is mocked in our unit tests, therefore we
18+
// do not have test coverage for this method.
19+
/* c8 ignore start */
1520
const isPremiumUser = hasPremium(session.data?.user);
1621
const record = useCallback(
1722
async <
@@ -36,10 +41,30 @@ export const useGlean = () => {
3641
? "Plus"
3742
: "Free";
3843

44+
// Record the `nimbus_*` keys on all events.
45+
// `nimbus_*` is set on every metric, but it's too much work for TypeScript
46+
// to infer that — hence the type assertion.
47+
if (experimentData) {
48+
(data as GleanMetricMap["button"]["click"]).nimbus_user_id =
49+
experimentData["Enrollments"]["nimbus_user_id"];
50+
(data as GleanMetricMap["button"]["click"]).nimbus_app_id =
51+
experimentData["Enrollments"]["app_id"];
52+
(data as GleanMetricMap["button"]["click"]).nimbus_experiment =
53+
experimentData["Enrollments"]["experiment"];
54+
(data as GleanMetricMap["button"]["click"]).nimbus_branch =
55+
experimentData["Enrollments"]["branch"];
56+
(data as GleanMetricMap["button"]["click"]).nimbus_experiment_type =
57+
experimentData["Enrollments"]["experiment_type"];
58+
(data as GleanMetricMap["button"]["click"]).nimbus_is_preview =
59+
experimentData["Enrollments"]["is_preview"].toString();
60+
} else {
61+
console.warn("No experiment data available for Glean");
62+
}
63+
3964
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4065
mod[event].record(data as any);
4166
},
42-
[isPremiumUser],
67+
[isPremiumUser, experimentData],
4368
);
4469
/* c8 ignore end */
4570

src/app/layout.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import { GoogleAnalyticsWorkaround } from "./components/client/GoogleAnalyticsWo
1717
import StripeScript from "./components/client/StripeScript";
1818
import { GleanScript } from "./components/client/GleanScript";
1919
import { getExperimentationId } from "./functions/server/getExperimentationId";
20+
import { getExperiments } from "./functions/server/getExperiments";
21+
import { getCountryCode } from "./functions/server/getCountryCode";
22+
import { ExperimentsProvider } from "../contextProviders/experiments";
23+
import * as Sentry from "@sentry/nextjs";
2024

2125
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
2226

@@ -54,6 +58,26 @@ export default async function RootLayout({
5458
const nonce = headers().get("x-nonce") ?? "";
5559
const currentLocale = getLocale(getL10nBundles());
5660
const session = await getServerSession();
61+
const headersList = headers();
62+
const countryCode = getCountryCode(headersList);
63+
64+
// Check for Nimbus preview mode. Note that this requires a full page reload
65+
// to activate: https://nextjs.org/docs/app/api-reference/file-conventions/layout#caveats
66+
const nimbusPreviewMode = headers().get("x-nimbus-preview-mode");
67+
const experimentationId = getExperimentationId(session?.user ?? null);
68+
const experimentData = await getExperiments({
69+
experimentationId: experimentationId,
70+
countryCode: countryCode,
71+
locale: currentLocale,
72+
previewMode: nimbusPreviewMode === "true",
73+
});
74+
75+
const nimbus_user_id = experimentData["Enrollments"].nimbus_user_id;
76+
if (nimbus_user_id !== experimentationId) {
77+
Sentry.captureMessage(
78+
`Nimbus user ID from Cirrus: [${nimbus_user_id}] did not match experimentationId: [${experimentationId}]`,
79+
);
80+
}
5781

5882
return (
5983
<html lang={currentLocale}>
@@ -64,12 +88,14 @@ export default async function RootLayout({
6488
data-ga4-measurement-id={CONST_GA4_MEASUREMENT_ID}
6589
data-node-env={process.env.NODE_ENV}
6690
>
67-
<SessionProvider session={session}>{children}</SessionProvider>
91+
<ExperimentsProvider experimentData={experimentData}>
92+
<SessionProvider session={session}>{children}</SessionProvider>
93+
</ExperimentsProvider>
6894
</body>
6995
<StripeScript />
7096
<GleanScript
7197
channel={process.env.APP_ENV ?? ""}
72-
experimentationId={getExperimentationId(session?.user ?? null)}
98+
experimentationId={experimentationId}
7399
/>
74100
{headers().get("DNT") !== "1" && (
75101
<GoogleAnalyticsWorkaround
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
"use client";
6+
7+
import { ReactNode, createContext, useContext } from "react";
8+
import { ExperimentData } from "../telemetry/generated/nimbus/experiments";
9+
10+
interface ExperimentsProviderProps {
11+
children: ReactNode;
12+
experimentData: ExperimentData;
13+
}
14+
15+
export const ExperimentsContext = createContext<ExperimentData | null>(null);
16+
17+
export const ExperimentsProvider = ({
18+
children,
19+
experimentData,
20+
}: ExperimentsProviderProps) => {
21+
return (
22+
<ExperimentsContext.Provider value={experimentData}>
23+
{children}
24+
</ExperimentsContext.Provider>
25+
);
26+
};
27+
28+
export const useExperiments = () => {
29+
const context = useContext(ExperimentsContext);
30+
return context;
31+
};

src/middleware.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ export function middleware(request: NextRequest) {
2929
existingExperimentationId?.value ?? `guest-${crypto.randomUUID()}`;
3030
requestHeaders.set("x-experimentation-id", experimentationId);
3131

32+
// Check for Nimbus preview mode. Note that this requires a full page reload
33+
// to activate: https://nextjs.org/docs/app/api-reference/file-conventions/layout#caveats
34+
const nimbusPreviewMode = request.nextUrl.searchParams.get("nimbus_preview");
35+
requestHeaders.set(
36+
"x-nimbus-preview-mode",
37+
nimbusPreviewMode === "true" ? "true" : "false",
38+
);
39+
3240
const response = NextResponse.next({
3341
request: {
3442
headers: requestHeaders,

0 commit comments

Comments
 (0)