From eff4420c6110c700480b7f9984f401bf852f8c81 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 19:21:05 -0700 Subject: [PATCH 01/46] Update TODO list --- TODO.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..971709c0 --- /dev/null +++ b/TODO.md @@ -0,0 +1,107 @@ +Goal: stand up mobile version of experiments/rollouts + +Epics: + +- BIG UNKNOWN: figure out outside-of-nimbus plan +- stand up android + - messaging surface + - onboarding surface + - UNKNOWN: enumerate other surfaces +- stand up iOS + - UNKNOWN: sort out surfaces + - redo android steps, but without all the refactoring + +User Stories. As an Android PM, I should + +- have an easy view of rollouts/branches on the messaging surface + + - so I can see a bunch of what Android users see (on the message surface) + - 1-10 + +- research + + - [surfaces & guidelines](https://mozilla-hub.atlassian.net/wiki/spaces/FIREFOX/pages/210206760/Mobile+Message+Surface+Guidelines) + - [mobile telemetry docs](https://experimenter.info/messaging/mobile-messaging/#events-emitted) + - [desktop explore](https://mozilla.cloud.looker.com/explore/user_journey/event_counts) + + 1. look at iOS telemetry & explores + + - [iOS message probes](https://dictionary.telemetry.mozilla.org/apps/firefox_ios?page=1&search=messag) + - Note no experiments probes like Android has + - [iOS event count explore](https://mozilla.cloud.looker.com/explore/firefox_ios/event_counts?qid=OZqOXzZqTujARgvCK12NJ4) + - [recent iOS clicked events](https://mozilla.cloud.looker.com/explore/firefox_ios/event_counts?qid=jQpgYwZpBZEhW73B1dcyzu&toggle=fil,vis) + - XXX look at onboarding also + + 2. look at Android telemetry & explores + - [Android message probes - Glean dictionary](https://dictionary.telemetry.mozilla.org/apps/fenix?page=1&search=messaging) + - [android explore](https://mozilla.cloud.looker.com/explore/fenix/event_counts)$$ + - [recent android messaing click events with most extra keys and experiments](https://mozilla.cloud.looker.com/explore/fenix/event_counts?qid=u0OKWHjWgTcstNgbzvyyBc&toggle=fil) + - [recent android onboarding events](https://mozilla.cloud.looker.com/explore/fenix/event_counts?qid=n71HDr0LIxuNS3vGX9essN&toggle=fil) + - Need to understand this telemetry compared to JSON + +- +- open questions + - what does telemetry look like for onboarding? other surfaces? similar to messaging? + - Does Click telemetry on both iOS and Android alwyas mean CTA? Or something else? + - What is action_uuid extra key (see docs)? + - **Do non-experimental message send pings on iOS or Android?** + - + +1. Draft plan for Android page + + 1. ?File ticket + 2. Build chart for Android messaging (DONE) + 3. Build 2nd chart (LATER) + 4. Build dashboard (DONE: id = 2191) + 5. Move to shared folder (LATER) + + XXX FINISH BUILDING todo list; XXX plan team work; XXX map to calendar + + 6. Build Android page + + 1. ~~Review existing clone for "completed" (DONE)~~ + 2. ~~?Consider options for cloning, since we'll want Android completed page too, and iOS pages (DONE)~~ + 3. ~~Create new dir with new page.tsx (MUST)~~ + 4. ~~TDD Factor out dashboard (DONE)~~ + 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) + 2. ~~Put in separate android/ route (DONE)~~ + + 5. Make test & code updates to not display local table (WIP) + 6. Factor "application=" out of env (MUST) + 7. Add cases / refactor multiple feature ID list in experimentUtils.ts (MUST) + 8. Add cases / refactor nimbusRecipe.ts:getBranchInfo (MUST) + + 9. Add cases / refactor messageUtils.getDashboard (LATER) + 10. Update / move messageUtils.getDashboardIdForTemplate (LATER) + 11. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 12. Add cases / refactor looker.ts:getCTRPercentData (LATER) + 13. Make pills exclude local if not on desktop (LATER) + + 14. Update columns.tsx:filterBySurface (LATER) + 15. Add l10n (LATER) + 16. Factor Out NimbusMessageTable (NICE) + 17. Factor out high-level data fetching (NICE) + + 18. Pull in Android experiments using that URL + 19. Build dashboard link + 20. How to handle multi types + 21. Build CTR + 22. How to handle multi types + +2. standup 2nd page + + - TDD? clone for mobile + +3. standup 2nd dashboard + + * review mobile telemetry using glean dict + * look at explores available for those tables + * TDD? subclass recipes (desktop & mobile) + + 1. Separate dashboards per surface: onboarding, (messaging genrally - may need to split into message_surface dashboard) + 2. 2.What about QA? + +Later: + +- clean up text on messaging graph +- From 374cd7a3febbb06fb4d934f4f7ec752678b60163 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 19:22:42 -0700 Subject: [PATCH 02/46] Add basic instructions for copilot case sensitivity. --- .github/copilot-instructions.md | 14 ++++++++++++++ .github/copilot-test-generation.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 .github/copilot-test-generation.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..738ac577 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,14 @@ +# GitHub Copilot Instructions + +## Case-Sensitive Filesystem + +Some of our development happens on a case-sensitive filesystem. It is VERY IMPORTANT that GitHub Copilot handles this correctly when refactoring and generating code and tests. + +### Guidelines + +1. **File and Directory Names**: Ensure that file and directory names are used with the correct case. For example, `MyFile.ts` and `myfile.ts` are different files on a case-sensitive filesystem. +2. **Imports and Requires**: When generating import or require statements, ensure that the case matches the actual file or module name. +3. **Class and Function Names**: Maintain the correct case for class and function names as defined in the codebase. +4. **Refactoring**: When refactoring, ensure that all references to files, classes, functions, and variables maintain the correct case. + +By following these guidelines, we can avoid issues related to case sensitivity in our development process. diff --git a/.github/copilot-test-generation.md b/.github/copilot-test-generation.md new file mode 100644 index 00000000..738ac577 --- /dev/null +++ b/.github/copilot-test-generation.md @@ -0,0 +1,14 @@ +# GitHub Copilot Instructions + +## Case-Sensitive Filesystem + +Some of our development happens on a case-sensitive filesystem. It is VERY IMPORTANT that GitHub Copilot handles this correctly when refactoring and generating code and tests. + +### Guidelines + +1. **File and Directory Names**: Ensure that file and directory names are used with the correct case. For example, `MyFile.ts` and `myfile.ts` are different files on a case-sensitive filesystem. +2. **Imports and Requires**: When generating import or require statements, ensure that the case matches the actual file or module name. +3. **Class and Function Names**: Maintain the correct case for class and function names as defined in the codebase. +4. **Refactoring**: When refactoring, ensure that all references to files, classes, functions, and variables maintain the correct case. + +By following these guidelines, we can avoid issues related to case sensitivity in our development process. From ead3234c16541b8e9e77eddfd73db7f161982ae0 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 19:41:28 -0700 Subject: [PATCH 03/46] Refactor page.tsx to call fetchData and pass params --- app/android/page.tsx | 7 ++++--- app/dashboard.tsx | 26 ++++++++++++++------------ app/page.tsx | 23 ++++++++++++++++++++--- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 69ece864..904fe12d 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -1,5 +1,6 @@ -import { Dashboard } from "@/app/dashboard"; +import { fetchData, Dashboard } from "@/app/dashboard"; -export default function Page() { - return ; +export default async function Page() { + const data = await fetchData(); + return ; } diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 9e79d155..c53794f7 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -192,7 +192,7 @@ async function getMsgRolloutCollection( return msgRolloutRecipeCollection; } -async function fetchData() { +export async function fetchData() { const recipeCollection = new NimbusRecipeCollection(); await recipeCollection.fetchRecipes(); console.log("recipeCollection.length = ", recipeCollection.recipes.length); @@ -268,19 +268,21 @@ const ReleasedTable = async ({ platform, localData }: ReleasedTableProps) => { interface DashboardProps { platform?: string; + localData: FxMSMessageInfo[]; + experimentAndBranchInfo: any[]; + totalExperiments: number; + msgRolloutInfo: any[]; + totalRolloutExperiments: number; } -export const Dashboard = async ( - { platform }: DashboardProps = { platform: "desktop" }, -) => { - const { - localData, - experimentAndBranchInfo, - totalExperiments, - msgRolloutInfo, - totalRolloutExperiments, - } = await fetchData(); - +export const Dashboard = async ({ + platform = "desktop", + localData, + experimentAndBranchInfo, + totalExperiments, + msgRolloutInfo, + totalRolloutExperiments, +}: DashboardProps) => { return (
diff --git a/app/page.tsx b/app/page.tsx index 1bd77d9b..b7fe886a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,22 @@ -import { Dashboard } from "@/app/dashboard"; +import { fetchData, Dashboard } from "@/app/dashboard"; -export default function Page() { - return ; +export default async function Page() { + const { + localData, + experimentAndBranchInfo, + totalExperiments, + msgRolloutInfo, + totalRolloutExperiments, + } = await fetchData(); + + return ( + + ); } From 98576f88c843597e919385b56cdfd5c4030ccf4c Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 19:48:37 -0700 Subject: [PATCH 04/46] Fixup Android calling of Dashboard component. --- app/android/page.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 904fe12d..21960689 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -1,6 +1,22 @@ import { fetchData, Dashboard } from "@/app/dashboard"; export default async function Page() { - const data = await fetchData(); - return ; + const { + localData, + experimentAndBranchInfo, + totalExperiments, + msgRolloutInfo, + totalRolloutExperiments, + } = await fetchData(); + + return ( + + ); } From 66f3f868e9a2bfb238c09d07f85adba4a97b75f9 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 19:59:48 -0700 Subject: [PATCH 05/46] Made localData optional to Dashboard component --- app/android/page.tsx | 1 - app/dashboard.tsx | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 21960689..2c0bcde7 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -12,7 +12,6 @@ export default async function Page() { return ( { interface DashboardProps { platform?: string; - localData: FxMSMessageInfo[]; + localData?: FxMSMessageInfo[]; experimentAndBranchInfo: any[]; totalExperiments: number; msgRolloutInfo: any[]; @@ -290,7 +290,8 @@ export const Dashboard = async ({
- + {localData + ? : null}
Current {platform} Message Rollouts From cd8a8b57bd36bc787d71d7504393d85c50adf534 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 20:08:23 -0700 Subject: [PATCH 06/46] Make the file case instructions clearer --- .github/copilot-instructions.md | 13 ++++++++++++- .github/copilot-test-generation.md | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 738ac577..b540e3d7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -11,4 +11,15 @@ Some of our development happens on a case-sensitive filesystem. It is VERY IMPOR 3. **Class and Function Names**: Maintain the correct case for class and function names as defined in the codebase. 4. **Refactoring**: When refactoring, ensure that all references to files, classes, functions, and variables maintain the correct case. -By following these guidelines, we can avoid issues related to case sensitivity in our development process. +### Specific Instructions for Component Files + +When working with component files where the component name is uppercase and the file name contains lowercase, ensure the following: + +1. **Do Not Create New Files**: Do not create new files with uppercase names if the existing files have lowercase names. +2. **Correct File Names**: Use the existing files with the correct case. +3. **Correct Imports**: When importing components in other files, ensure the import statement uses the correct case: + ```tsx + import Component from "@/app/component"; + ``` + +By following these guidelines, we can avoid issues related to case sensitivity and unnecessary file creation in our development process. diff --git a/.github/copilot-test-generation.md b/.github/copilot-test-generation.md index 738ac577..b540e3d7 100644 --- a/.github/copilot-test-generation.md +++ b/.github/copilot-test-generation.md @@ -11,4 +11,15 @@ Some of our development happens on a case-sensitive filesystem. It is VERY IMPOR 3. **Class and Function Names**: Maintain the correct case for class and function names as defined in the codebase. 4. **Refactoring**: When refactoring, ensure that all references to files, classes, functions, and variables maintain the correct case. -By following these guidelines, we can avoid issues related to case sensitivity in our development process. +### Specific Instructions for Component Files + +When working with component files where the component name is uppercase and the file name contains lowercase, ensure the following: + +1. **Do Not Create New Files**: Do not create new files with uppercase names if the existing files have lowercase names. +2. **Correct File Names**: Use the existing files with the correct case. +3. **Correct Imports**: When importing components in other files, ensure the import statement uses the correct case: + ```tsx + import Component from "@/app/component"; + ``` + +By following these guidelines, we can avoid issues related to case sensitivity and unnecessary file creation in our development process. From 76fa4773e01aebd34b988f37cdf797c1cc90fa1e Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 20:28:55 -0700 Subject: [PATCH 07/46] Fixup dashboard test --- __tests__/app/dashboard.test.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/__tests__/app/dashboard.test.tsx b/__tests__/app/dashboard.test.tsx index 1d5f2e49..4ce5d530 100644 --- a/__tests__/app/dashboard.test.tsx +++ b/__tests__/app/dashboard.test.tsx @@ -11,9 +11,19 @@ global.fetch = jest.fn(() => }), ) as jest.Mock; +const mockFetchData = { + localData: [], + experimentAndBranchInfo: [], + totalExperiments: 0, + msgRolloutInfo: [], + totalRolloutExperiments: 0, +}; + describe.skip("Dashboard", () => { it("all timeline pill ids exist in the Dashboard component in /", async () => { - const dashboard = await render(await ()); + const dashboard = await render( + await + ); const firefox = dashboard.getByTestId("firefox"); const experiments = dashboard.getByTestId("live_experiments"); From 758d0aeafbb125a94f894973a670959f06b442ab Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sat, 22 Mar 2025 20:31:33 -0700 Subject: [PATCH 08/46] Move platform to a union type --- app/android/page.tsx | 5 ++++- app/dashboard.tsx | 5 +++-- app/page.tsx | 2 +- app/types.ts | 0 lib/types.ts | 3 +++ 5 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 app/types.ts create mode 100644 lib/types.ts diff --git a/app/android/page.tsx b/app/android/page.tsx index 2c0bcde7..605aeb9c 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -1,4 +1,7 @@ import { fetchData, Dashboard } from "@/app/dashboard"; +import { Platform } from "@/lib/types"; + + export default async function Page() { const { @@ -11,7 +14,7 @@ export default async function Page() { return ( { }; interface DashboardProps { - platform?: string; + platform?: Platform; localData?: FxMSMessageInfo[]; experimentAndBranchInfo: any[]; totalExperiments: number; @@ -276,7 +277,7 @@ interface DashboardProps { } export const Dashboard = async ({ - platform = "desktop", + platform = "Desktop", localData, experimentAndBranchInfo, totalExperiments, diff --git a/app/page.tsx b/app/page.tsx index b7fe886a..0f4de03c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -11,7 +11,7 @@ export default async function Page() { return ( Date: Sun, 23 Mar 2025 10:31:08 -0700 Subject: [PATCH 09/46] Refactor fetchData to its own file --- app/android/page.tsx | 6 ++---- app/dashboard.tsx | 48 ++++---------------------------------------- app/page.tsx | 3 ++- 3 files changed, 8 insertions(+), 49 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 605aeb9c..0910294c 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -1,7 +1,5 @@ -import { fetchData, Dashboard } from "@/app/dashboard"; -import { Platform } from "@/lib/types"; - - +import { Dashboard } from "@/app/dashboard"; +import { fetchData } from "@/app/fetchData"; export default async function Page() { const { diff --git a/app/dashboard.tsx b/app/dashboard.tsx index d3d5096f..6a8b3e38 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -17,7 +17,6 @@ import { maybeCreateWelcomePreview, getPreviewLink, messageHasMicrosurvey, - compareSurfacesFn, } from "../lib/messageUtils.ts"; import { NimbusRecipeCollection } from "../lib/nimbusRecipeCollection"; @@ -31,7 +30,7 @@ import { InfoPopover } from "@/components/ui/infopopover.tsx"; import { Timeline } from "@/components/ui/timeline.tsx"; import { Platform } from "@/lib/types"; -const isLookerEnabled = process.env.IS_LOOKER_ENABLED === "true"; +export const isLookerEnabled = process.env.IS_LOOKER_ENABLED === "true"; const hidden_message_impression_threshold = process.env.HIDDEN_MESSAGE_IMPRESSION_THRESHOLD; @@ -133,7 +132,7 @@ async function appendFxMSTelemetryData(existingMessageData: any) { * lib/asrouter-local-prod-messages/data.json and also FxMS telemetry data if * Looker credentials are enabled. */ -async function getASRouterLocalMessageInfoFromFile(): Promise< +export async function getASRouterLocalMessageInfoFromFile(): Promise< FxMSMessageInfo[] > { const fs = require("fs"); @@ -157,7 +156,7 @@ async function getASRouterLocalMessageInfoFromFile(): Promise< return messages; } -async function getMsgExpRecipeCollection( +export async function getMsgExpRecipeCollection( recipeCollection: NimbusRecipeCollection, ): Promise { const expOnlyCollection = new NimbusRecipeCollection(); @@ -178,7 +177,7 @@ async function getMsgExpRecipeCollection( return msgExpRecipeCollection; } -async function getMsgRolloutCollection( +export async function getMsgRolloutCollection( recipeCollection: NimbusRecipeCollection, ): Promise { const msgRolloutRecipeCollection = new NimbusRecipeCollection(); @@ -193,45 +192,6 @@ async function getMsgRolloutCollection( return msgRolloutRecipeCollection; } -export async function fetchData() { - const recipeCollection = new NimbusRecipeCollection(); - await recipeCollection.fetchRecipes(); - console.log("recipeCollection.length = ", recipeCollection.recipes.length); - - const localData = (await getASRouterLocalMessageInfoFromFile()).sort( - compareSurfacesFn, - ); - - const msgExpRecipeCollection = - await getMsgExpRecipeCollection(recipeCollection); - const msgRolloutRecipeCollection = - await getMsgRolloutCollection(recipeCollection); - - const experimentAndBranchInfo = isLookerEnabled - ? await msgExpRecipeCollection.getExperimentAndBranchInfos() - : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => - recipe.getRecipeInfo(), - ); - - const totalExperiments = msgExpRecipeCollection.recipes.length; - - const msgRolloutInfo = isLookerEnabled - ? await msgRolloutRecipeCollection.getExperimentAndBranchInfos() - : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => - recipe.getRecipeInfo(), - ); - - const totalRolloutExperiments = msgRolloutRecipeCollection.recipes.length; - - return { - localData, - experimentAndBranchInfo, - totalExperiments, - msgRolloutInfo, - totalRolloutExperiments, - }; -} - interface ReleasedTableProps { platform: string; localData: FxMSMessageInfo[]; diff --git a/app/page.tsx b/app/page.tsx index 0f4de03c..4f0e1d84 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,4 +1,5 @@ -import { fetchData, Dashboard } from "@/app/dashboard"; +import { Dashboard } from "@/app/dashboard"; +import { fetchData } from "@/app/fetchData"; export default async function Page() { const { From dec580773cc0e95bbdaacab585bea31ec32b6049 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 10:43:57 -0700 Subject: [PATCH 10/46] Renamed fetchData.tsx to fetchData.ts --- app/fetchData.tsx | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 app/fetchData.tsx diff --git a/app/fetchData.tsx b/app/fetchData.tsx new file mode 100644 index 00000000..6bc6eef8 --- /dev/null +++ b/app/fetchData.tsx @@ -0,0 +1,40 @@ +import { compareSurfacesFn } from "@/lib/messageUtils"; +import { NimbusRecipe } from "@/lib/nimbusRecipe"; +import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; +import { getASRouterLocalMessageInfoFromFile, getMsgExpRecipeCollection, getMsgRolloutCollection, isLookerEnabled } from "./dashboard"; + + +export async function fetchData() { + const recipeCollection = new NimbusRecipeCollection(); + await recipeCollection.fetchRecipes(); + console.log("recipeCollection.length = ", recipeCollection.recipes.length); + + const localData = (await getASRouterLocalMessageInfoFromFile()).sort( + compareSurfacesFn + ); + + const msgExpRecipeCollection = await getMsgExpRecipeCollection(recipeCollection); + const msgRolloutRecipeCollection = await getMsgRolloutCollection(recipeCollection); + + const experimentAndBranchInfo = isLookerEnabled + ? await msgExpRecipeCollection.getExperimentAndBranchInfos() + : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() + ); + + const totalExperiments = msgExpRecipeCollection.recipes.length; + + const msgRolloutInfo = isLookerEnabled + ? await msgRolloutRecipeCollection.getExperimentAndBranchInfos() + : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() + ); + + const totalRolloutExperiments = msgRolloutRecipeCollection.recipes.length; + + return { + localData, + experimentAndBranchInfo, + totalExperiments, + msgRolloutInfo, + totalRolloutExperiments, + }; +} From 46ae4b376edad36cd78a3f257dcd8409b52baf81 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 10:49:05 -0700 Subject: [PATCH 11/46] Export compareDatesFn to fix the app --- app/dashboard.tsx | 2 +- app/fetchData.ts | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/fetchData.ts diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 6a8b3e38..10bca5d9 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -46,7 +46,7 @@ const hidden_message_impression_threshold = * @returns -1 if the start date for message a is after the start date for * message b, zero if they're equal, and 1 otherwise. */ -function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { +export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { if (a._rawRecipe.startDate && b._rawRecipe.startDate) { if (a._rawRecipe.startDate > b._rawRecipe.startDate) { return -1; diff --git a/app/fetchData.ts b/app/fetchData.ts new file mode 100644 index 00000000..65f5c681 --- /dev/null +++ b/app/fetchData.ts @@ -0,0 +1,58 @@ +import { compareSurfacesFn } from "@/lib/messageUtils"; +import { NimbusRecipe } from "@/lib/nimbusRecipe"; +import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; +import { compareDatesFn, getASRouterLocalMessageInfoFromFile, getMsgRolloutCollection, isLookerEnabled } from "./dashboard"; + +export async function fetchData() { + const recipeCollection = new NimbusRecipeCollection(); + await recipeCollection.fetchRecipes(); + console.log("recipeCollection.length = ", recipeCollection.recipes.length); + + const localData = (await getASRouterLocalMessageInfoFromFile()).sort( + compareSurfacesFn + ); + + const msgExpRecipeCollection = await getMsgExpRecipeCollection(recipeCollection); + const msgRolloutRecipeCollection = await getMsgRolloutCollection(recipeCollection); + + const experimentAndBranchInfo = isLookerEnabled + ? await msgExpRecipeCollection.getExperimentAndBranchInfos() + : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() + ); + + const totalExperiments = msgExpRecipeCollection.recipes.length; + + const msgRolloutInfo = isLookerEnabled + ? await msgRolloutRecipeCollection.getExperimentAndBranchInfos() + : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() + ); + + const totalRolloutExperiments = msgRolloutRecipeCollection.recipes.length; + + return { + localData, + experimentAndBranchInfo, + totalExperiments, + msgRolloutInfo, + totalRolloutExperiments, + }; +} +export async function getMsgExpRecipeCollection( + recipeCollection: NimbusRecipeCollection +): Promise { + const expOnlyCollection = new NimbusRecipeCollection(); + expOnlyCollection.recipes = recipeCollection.recipes.filter((recipe) => recipe.isExpRecipe() + ); + console.log("expOnlyCollection.length = ", expOnlyCollection.recipes.length); + + const msgExpRecipeCollection = new NimbusRecipeCollection(); + msgExpRecipeCollection.recipes = expOnlyCollection.recipes + .filter((recipe) => recipe.usesMessagingFeatures()) + .sort(compareDatesFn); + console.log( + "msgExpRecipeCollection.length = ", + msgExpRecipeCollection.recipes.length + ); + + return msgExpRecipeCollection; +} From 6be99d234a4658499cdc90cf75dfe5fba105ff98 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:01:09 -0700 Subject: [PATCH 12/46] Remove obsolete fetchData.tsx --- app/fetchData.tsx | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 app/fetchData.tsx diff --git a/app/fetchData.tsx b/app/fetchData.tsx deleted file mode 100644 index 6bc6eef8..00000000 --- a/app/fetchData.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { compareSurfacesFn } from "@/lib/messageUtils"; -import { NimbusRecipe } from "@/lib/nimbusRecipe"; -import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; -import { getASRouterLocalMessageInfoFromFile, getMsgExpRecipeCollection, getMsgRolloutCollection, isLookerEnabled } from "./dashboard"; - - -export async function fetchData() { - const recipeCollection = new NimbusRecipeCollection(); - await recipeCollection.fetchRecipes(); - console.log("recipeCollection.length = ", recipeCollection.recipes.length); - - const localData = (await getASRouterLocalMessageInfoFromFile()).sort( - compareSurfacesFn - ); - - const msgExpRecipeCollection = await getMsgExpRecipeCollection(recipeCollection); - const msgRolloutRecipeCollection = await getMsgRolloutCollection(recipeCollection); - - const experimentAndBranchInfo = isLookerEnabled - ? await msgExpRecipeCollection.getExperimentAndBranchInfos() - : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() - ); - - const totalExperiments = msgExpRecipeCollection.recipes.length; - - const msgRolloutInfo = isLookerEnabled - ? await msgRolloutRecipeCollection.getExperimentAndBranchInfos() - : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() - ); - - const totalRolloutExperiments = msgRolloutRecipeCollection.recipes.length; - - return { - localData, - experimentAndBranchInfo, - totalExperiments, - msgRolloutInfo, - totalRolloutExperiments, - }; -} From b3794cddf6c854f5dcba93b90729ae5f904416e0 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:02:49 -0700 Subject: [PATCH 13/46] Move getASRouterLocalMessageIntoFromFile to fetchData.ts --- app/dashboard.tsx | 33 ++----------------------- app/fetchData.ts | 63 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 10bca5d9..68c45639 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -59,7 +59,7 @@ export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { return 0; } -async function getASRouterLocalColumnFromJSON( +export async function getASRouterLocalColumnFromJSON( messageDef: any, ): Promise { let fxmsMsgInfo: FxMSMessageInfo = { @@ -114,7 +114,7 @@ let columnsShown = false; * message data is also cleaned up to match the message data objects from * ASRouter, remove any test messages, and update templates. */ -async function appendFxMSTelemetryData(existingMessageData: any) { +export async function appendFxMSTelemetryData(existingMessageData: any) { // Get Looker message data (taken from the query in Look // https://mozilla.cloud.looker.com/looks/2162) const lookId = "2162"; @@ -127,35 +127,6 @@ async function appendFxMSTelemetryData(existingMessageData: any) { return mergedData; } -/** - * @returns message data in the form of FxMSMessageInfo from - * lib/asrouter-local-prod-messages/data.json and also FxMS telemetry data if - * Looker credentials are enabled. - */ -export async function getASRouterLocalMessageInfoFromFile(): Promise< - FxMSMessageInfo[] -> { - const fs = require("fs"); - - let data = fs.readFileSync( - "lib/asrouter-local-prod-messages/data.json", - "utf8", - ); - let json_data = JSON.parse(data); - - if (isLookerEnabled) { - json_data = await appendFxMSTelemetryData(json_data); - } - - let messages = await Promise.all( - json_data.map(async (messageDef: any): Promise => { - return await getASRouterLocalColumnFromJSON(messageDef); - }), - ); - - return messages; -} - export async function getMsgExpRecipeCollection( recipeCollection: NimbusRecipeCollection, ): Promise { diff --git a/app/fetchData.ts b/app/fetchData.ts index 65f5c681..54e9e6c0 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -1,7 +1,14 @@ import { compareSurfacesFn } from "@/lib/messageUtils"; import { NimbusRecipe } from "@/lib/nimbusRecipe"; import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; -import { compareDatesFn, getASRouterLocalMessageInfoFromFile, getMsgRolloutCollection, isLookerEnabled } from "./dashboard"; +import { + appendFxMSTelemetryData, + compareDatesFn, + getASRouterLocalColumnFromJSON, + getMsgRolloutCollection, + isLookerEnabled, +} from "@/app/dashboard"; +import { FxMSMessageInfo } from "./columns"; export async function fetchData() { const recipeCollection = new NimbusRecipeCollection(); @@ -9,23 +16,27 @@ export async function fetchData() { console.log("recipeCollection.length = ", recipeCollection.recipes.length); const localData = (await getASRouterLocalMessageInfoFromFile()).sort( - compareSurfacesFn + compareSurfacesFn, ); - const msgExpRecipeCollection = await getMsgExpRecipeCollection(recipeCollection); - const msgRolloutRecipeCollection = await getMsgRolloutCollection(recipeCollection); + const msgExpRecipeCollection = + await getMsgExpRecipeCollection(recipeCollection); + const msgRolloutRecipeCollection = + await getMsgRolloutCollection(recipeCollection); const experimentAndBranchInfo = isLookerEnabled ? await msgExpRecipeCollection.getExperimentAndBranchInfos() - : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() - ); + : msgExpRecipeCollection.recipes.map((recipe: NimbusRecipe) => + recipe.getRecipeInfo(), + ); const totalExperiments = msgExpRecipeCollection.recipes.length; const msgRolloutInfo = isLookerEnabled ? await msgRolloutRecipeCollection.getExperimentAndBranchInfos() - : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => recipe.getRecipeInfo() - ); + : msgRolloutRecipeCollection.recipes.map((recipe: NimbusRecipe) => + recipe.getRecipeInfo(), + ); const totalRolloutExperiments = msgRolloutRecipeCollection.recipes.length; @@ -38,10 +49,11 @@ export async function fetchData() { }; } export async function getMsgExpRecipeCollection( - recipeCollection: NimbusRecipeCollection + recipeCollection: NimbusRecipeCollection, ): Promise { const expOnlyCollection = new NimbusRecipeCollection(); - expOnlyCollection.recipes = recipeCollection.recipes.filter((recipe) => recipe.isExpRecipe() + expOnlyCollection.recipes = recipeCollection.recipes.filter((recipe) => + recipe.isExpRecipe(), ); console.log("expOnlyCollection.length = ", expOnlyCollection.recipes.length); @@ -51,8 +63,37 @@ export async function getMsgExpRecipeCollection( .sort(compareDatesFn); console.log( "msgExpRecipeCollection.length = ", - msgExpRecipeCollection.recipes.length + msgExpRecipeCollection.recipes.length, ); return msgExpRecipeCollection; } +/** + * @returns message data in the form of FxMSMessageInfo from + * lib/asrouter-local-prod-messages/data.json and also FxMS telemetry data if + * Looker credentials are enabled. + */ + +export async function getASRouterLocalMessageInfoFromFile(): Promise< + FxMSMessageInfo[] +> { + const fs = require("fs"); + + let data = fs.readFileSync( + "lib/asrouter-local-prod-messages/data.json", + "utf8", + ); + let json_data = JSON.parse(data); + + if (isLookerEnabled) { + json_data = await appendFxMSTelemetryData(json_data); + } + + let messages = await Promise.all( + json_data.map(async (messageDef: any): Promise => { + return await getASRouterLocalColumnFromJSON(messageDef); + }), + ); + + return messages; +} From a44bd0fac994acb3fd2f3a8b111bab553773ae4e Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:05:57 -0700 Subject: [PATCH 14/46] Move getASRouterLocalColumnFromJSON to fetchData.ts --- app/dashboard.tsx | 53 --------------------------------------------- app/fetchData.ts | 55 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 68c45639..5a9dd329 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -5,18 +5,11 @@ import { } from "./columns"; import { cleanLookerData, - getCTRPercentData, mergeLookerData, runLookQuery, } from "@/lib/looker.ts"; import { - getDashboard, - getSurfaceDataForTemplate, - getTemplateFromMessage, _isAboutWelcomeTemplate, - maybeCreateWelcomePreview, - getPreviewLink, - messageHasMicrosurvey, } from "../lib/messageUtils.ts"; import { NimbusRecipeCollection } from "../lib/nimbusRecipeCollection"; @@ -59,52 +52,6 @@ export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { return 0; } -export async function getASRouterLocalColumnFromJSON( - messageDef: any, -): Promise { - let fxmsMsgInfo: FxMSMessageInfo = { - product: "Desktop", - id: messageDef.id, - template: messageDef.template, - surface: getSurfaceDataForTemplate(getTemplateFromMessage(messageDef)) - .surface, - segment: "some segment", - metrics: "some metrics", - ctrPercent: undefined, // may be populated from Looker data - ctrPercentChange: undefined, // may be populated from Looker data - previewLink: getPreviewLink(maybeCreateWelcomePreview(messageDef)), - impressions: undefined, // may be populated from Looker data - hasMicrosurvey: messageHasMicrosurvey(messageDef.id), - hidePreview: messageDef.hidePreview, - }; - - const channel = "release"; - - if (isLookerEnabled) { - const ctrPercentData = await getCTRPercentData( - fxmsMsgInfo.id, - fxmsMsgInfo.template, - channel, - ); - if (ctrPercentData) { - fxmsMsgInfo.ctrPercent = ctrPercentData.ctrPercent; - fxmsMsgInfo.impressions = ctrPercentData.impressions; - } - } - - fxmsMsgInfo.ctrDashboardLink = getDashboard( - fxmsMsgInfo.template, - fxmsMsgInfo.id, - channel, - ); - - // dashboard link -> dashboard id -> query id -> query -> ctr_percent_from_lastish_day - - // console.log("fxmsMsgInfo: ", fxmsMsgInfo) - - return fxmsMsgInfo; -} - let columnsShown = false; /** diff --git a/app/fetchData.ts b/app/fetchData.ts index 54e9e6c0..fb2f1d55 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -1,14 +1,22 @@ -import { compareSurfacesFn } from "@/lib/messageUtils"; +import { + compareSurfacesFn, + getDashboard, + getPreviewLink, + getSurfaceDataForTemplate, + getTemplateFromMessage, + maybeCreateWelcomePreview, + messageHasMicrosurvey, +} from "@/lib/messageUtils"; import { NimbusRecipe } from "@/lib/nimbusRecipe"; import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; import { appendFxMSTelemetryData, compareDatesFn, - getASRouterLocalColumnFromJSON, getMsgRolloutCollection, isLookerEnabled, } from "@/app/dashboard"; import { FxMSMessageInfo } from "./columns"; +import { getCTRPercentData } from "@/lib/looker"; export async function fetchData() { const recipeCollection = new NimbusRecipeCollection(); @@ -97,3 +105,46 @@ export async function getASRouterLocalMessageInfoFromFile(): Promise< return messages; } +export async function getASRouterLocalColumnFromJSON( + messageDef: any, +): Promise { + let fxmsMsgInfo: FxMSMessageInfo = { + product: "Desktop", + id: messageDef.id, + template: messageDef.template, + surface: getSurfaceDataForTemplate(getTemplateFromMessage(messageDef)) + .surface, + segment: "some segment", + metrics: "some metrics", + ctrPercent: undefined, // may be populated from Looker data + ctrPercentChange: undefined, // may be populated from Looker data + previewLink: getPreviewLink(maybeCreateWelcomePreview(messageDef)), + impressions: undefined, // may be populated from Looker data + hasMicrosurvey: messageHasMicrosurvey(messageDef.id), + hidePreview: messageDef.hidePreview, + }; + + const channel = "release"; + + if (isLookerEnabled) { + const ctrPercentData = await getCTRPercentData( + fxmsMsgInfo.id, + fxmsMsgInfo.template, + channel, + ); + if (ctrPercentData) { + fxmsMsgInfo.ctrPercent = ctrPercentData.ctrPercent; + fxmsMsgInfo.impressions = ctrPercentData.impressions; + } + } + + fxmsMsgInfo.ctrDashboardLink = getDashboard( + fxmsMsgInfo.template, + fxmsMsgInfo.id, + channel, + ); + + // dashboard link -> dashboard id -> query id -> query -> ctr_percent_from_lastish_day + // console.log("fxmsMsgInfo: ", fxmsMsgInfo) + return fxmsMsgInfo; +} From dc315133af5c7e3d5bf7c3dea3114d8c4bf9eda5 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:09:27 -0700 Subject: [PATCH 15/46] Remove extra copy of getMsgExpRecipeCollection from dashboard.tsx --- app/dashboard.tsx | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 5a9dd329..380f1a03 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -74,27 +74,6 @@ export async function appendFxMSTelemetryData(existingMessageData: any) { return mergedData; } -export async function getMsgExpRecipeCollection( - recipeCollection: NimbusRecipeCollection, -): Promise { - const expOnlyCollection = new NimbusRecipeCollection(); - expOnlyCollection.recipes = recipeCollection.recipes.filter((recipe) => - recipe.isExpRecipe(), - ); - console.log("expOnlyCollection.length = ", expOnlyCollection.recipes.length); - - const msgExpRecipeCollection = new NimbusRecipeCollection(); - msgExpRecipeCollection.recipes = expOnlyCollection.recipes - .filter((recipe) => recipe.usesMessagingFeatures()) - .sort(compareDatesFn); - console.log( - "msgExpRecipeCollection.length = ", - msgExpRecipeCollection.recipes.length, - ); - - return msgExpRecipeCollection; -} - export async function getMsgRolloutCollection( recipeCollection: NimbusRecipeCollection, ): Promise { From 19484fcb89910d3af680d0e6d2c5984a4255776a Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:10:56 -0700 Subject: [PATCH 16/46] Remove dead code --- app/dashboard.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 380f1a03..d3468ed6 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -52,8 +52,6 @@ export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { return 0; } -let columnsShown = false; - /** * Appends any FxMS telemetry message data from the query in Look * https://mozilla.cloud.looker.com/looks/2162 that does not already exist (ie. From afc650107578032eed42a45b19eaefe99e15943e Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:17:41 -0700 Subject: [PATCH 17/46] Move appendFxMSTelemetryData to fetchData.ts --- app/dashboard.tsx | 25 ------------------------- app/fetchData.ts | 29 ++++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index d3468ed6..3017eebe 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -3,11 +3,6 @@ import { FxMSMessageInfo, fxmsMessageColumns, } from "./columns"; -import { - cleanLookerData, - mergeLookerData, - runLookQuery, -} from "@/lib/looker.ts"; import { _isAboutWelcomeTemplate, } from "../lib/messageUtils.ts"; @@ -52,26 +47,6 @@ export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { return 0; } -/** - * Appends any FxMS telemetry message data from the query in Look - * https://mozilla.cloud.looker.com/looks/2162 that does not already exist (ie. - * no duplicate message ids) in existingMessageData and returns the result. The - * message data is also cleaned up to match the message data objects from - * ASRouter, remove any test messages, and update templates. - */ -export async function appendFxMSTelemetryData(existingMessageData: any) { - // Get Looker message data (taken from the query in Look - // https://mozilla.cloud.looker.com/looks/2162) - const lookId = "2162"; - let lookerData = await runLookQuery(lookId); - - // Clean and merge Looker data with existing data - let jsonLookerData = cleanLookerData(lookerData); - let mergedData = mergeLookerData(existingMessageData, jsonLookerData); - - return mergedData; -} - export async function getMsgRolloutCollection( recipeCollection: NimbusRecipeCollection, ): Promise { diff --git a/app/fetchData.ts b/app/fetchData.ts index fb2f1d55..20f1385d 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -10,14 +10,17 @@ import { import { NimbusRecipe } from "@/lib/nimbusRecipe"; import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; import { - appendFxMSTelemetryData, compareDatesFn, getMsgRolloutCollection, isLookerEnabled, } from "@/app/dashboard"; import { FxMSMessageInfo } from "./columns"; -import { getCTRPercentData } from "@/lib/looker"; - +import { + cleanLookerData, + getCTRPercentData, + mergeLookerData, + runLookQuery, +} from "@/lib/looker.ts"; export async function fetchData() { const recipeCollection = new NimbusRecipeCollection(); await recipeCollection.fetchRecipes(); @@ -148,3 +151,23 @@ export async function getASRouterLocalColumnFromJSON( // console.log("fxmsMsgInfo: ", fxmsMsgInfo) return fxmsMsgInfo; } + +/** + * Appends any FxMS telemetry message data from the query in Look + * https://mozilla.cloud.looker.com/looks/2162 that does not already exist (ie. + * no duplicate message ids) in existingMessageData and returns the result. The + * message data is also cleaned up to match the message data objects from + * ASRouter, remove any test messages, and update templates. + */ +export async function appendFxMSTelemetryData(existingMessageData: any) { + // Get Looker message data (taken from the query in Look + // https://mozilla.cloud.looker.com/looks/2162) + const lookId = "2162"; + let lookerData = await runLookQuery(lookId); + + // Clean and merge Looker data with existing data + let jsonLookerData = cleanLookerData(lookerData); + let mergedData = mergeLookerData(existingMessageData, jsonLookerData); + + return mergedData; +} From d915b0f2ee4f4efe53c0e17d9f8cad250ddd18d9 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:22:24 -0700 Subject: [PATCH 18/46] Move functions to fetchData and clean up --- app/dashboard.tsx | 43 ------------------------------------------ app/fetchData.ts | 48 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 48 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 3017eebe..18356129 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -7,10 +7,8 @@ import { _isAboutWelcomeTemplate, } from "../lib/messageUtils.ts"; -import { NimbusRecipeCollection } from "../lib/nimbusRecipeCollection"; import { _substituteLocalizations } from "../lib/experimentUtils.ts"; -import { NimbusRecipe } from "../lib/nimbusRecipe.ts"; import { MessageTable } from "./message-table"; import { MenuButton } from "@/components/ui/menubutton.tsx"; @@ -18,50 +16,9 @@ import { InfoPopover } from "@/components/ui/infopopover.tsx"; import { Timeline } from "@/components/ui/timeline.tsx"; import { Platform } from "@/lib/types"; -export const isLookerEnabled = process.env.IS_LOOKER_ENABLED === "true"; - const hidden_message_impression_threshold = process.env.HIDDEN_MESSAGE_IMPRESSION_THRESHOLD; -/** - * A sorting function to sort messages by their start dates in descending order. - * If one or both of the recipes is missing a start date, they will be ordered - * identically since there's not enough information to properly sort them by - * date. - * - * @param a Nimbus recipe to compare with `b`. - * @param b Nimbus recipe to compare with `a`. - * @returns -1 if the start date for message a is after the start date for - * message b, zero if they're equal, and 1 otherwise. - */ -export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { - if (a._rawRecipe.startDate && b._rawRecipe.startDate) { - if (a._rawRecipe.startDate > b._rawRecipe.startDate) { - return -1; - } else if (a._rawRecipe.startDate < b._rawRecipe.startDate) { - return 1; - } - } - - // a must be equal to b - return 0; -} - -export async function getMsgRolloutCollection( - recipeCollection: NimbusRecipeCollection, -): Promise { - const msgRolloutRecipeCollection = new NimbusRecipeCollection(); - msgRolloutRecipeCollection.recipes = recipeCollection.recipes - .filter((recipe) => recipe.usesMessagingFeatures() && !recipe.isExpRecipe()) - .sort(compareDatesFn); - console.log( - "msgRolloutRecipeCollection.length = ", - msgRolloutRecipeCollection.recipes.length, - ); - - return msgRolloutRecipeCollection; -} - interface ReleasedTableProps { platform: string; localData: FxMSMessageInfo[]; diff --git a/app/fetchData.ts b/app/fetchData.ts index 20f1385d..447c7784 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -9,11 +9,6 @@ import { } from "@/lib/messageUtils"; import { NimbusRecipe } from "@/lib/nimbusRecipe"; import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; -import { - compareDatesFn, - getMsgRolloutCollection, - isLookerEnabled, -} from "@/app/dashboard"; import { FxMSMessageInfo } from "./columns"; import { cleanLookerData, @@ -21,6 +16,9 @@ import { mergeLookerData, runLookQuery, } from "@/lib/looker.ts"; + +const isLookerEnabled = process.env.IS_LOOKER_ENABLED === "true"; + export async function fetchData() { const recipeCollection = new NimbusRecipeCollection(); await recipeCollection.fetchRecipes(); @@ -171,3 +169,43 @@ export async function appendFxMSTelemetryData(existingMessageData: any) { return mergedData; } + +/** + * A sorting function to sort messages by their start dates in descending order. + * If one or both of the recipes is missing a start date, they will be ordered + * identically since there's not enough information to properly sort them by + * date. + * + * @param a Nimbus recipe to compare with `b`. + * @param b Nimbus recipe to compare with `a`. + * @returns -1 if the start date for message a is after the start date for + * message b, zero if they're equal, and 1 otherwise. + */ + +export function compareDatesFn(a: NimbusRecipe, b: NimbusRecipe): number { + if (a._rawRecipe.startDate && b._rawRecipe.startDate) { + if (a._rawRecipe.startDate > b._rawRecipe.startDate) { + return -1; + } else if (a._rawRecipe.startDate < b._rawRecipe.startDate) { + return 1; + } + } + + // a must be equal to b + return 0; +} + +export async function getMsgRolloutCollection( + recipeCollection: NimbusRecipeCollection, +): Promise { + const msgRolloutRecipeCollection = new NimbusRecipeCollection(); + msgRolloutRecipeCollection.recipes = recipeCollection.recipes + .filter((recipe) => recipe.usesMessagingFeatures() && !recipe.isExpRecipe()) + .sort(compareDatesFn); + console.log( + "msgRolloutRecipeCollection.length = ", + msgRolloutRecipeCollection.recipes.length, + ); + + return msgRolloutRecipeCollection; +} From 5f2f2b7e3ca15cb49ac995dd1bd70bc7ddfc52d2 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:23:30 -0700 Subject: [PATCH 19/46] Appease prettier --- app/dashboard.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index 18356129..ad65e5ce 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -3,9 +3,7 @@ import { FxMSMessageInfo, fxmsMessageColumns, } from "./columns"; -import { - _isAboutWelcomeTemplate, -} from "../lib/messageUtils.ts"; +import { _isAboutWelcomeTemplate } from "../lib/messageUtils.ts"; import { _substituteLocalizations } from "../lib/experimentUtils.ts"; @@ -78,8 +76,9 @@ export const Dashboard = async ({
- {localData - ? : null} + {localData ? ( + + ) : null}
Current {platform} Message Rollouts From 53659582e3a4e5f54d8422eaadbdf561fdf78fc4 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 11:25:18 -0700 Subject: [PATCH 20/46] Update comment about fetchData file home --- app/fetchData.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/fetchData.ts b/app/fetchData.ts index 447c7784..56dab0db 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -1,3 +1,4 @@ +// XXX ultimately, this wants to live in lib/fetchData.ts, but we need to get rid of our dependency on columns.tsx first. import { compareSurfacesFn, getDashboard, From 56d6fd3c42b109be61843b998089186c2206c6a1 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 14:08:06 -0700 Subject: [PATCH 21/46] Formatting tweaks --- TODO.md | 6 +++--- __tests__/app/dashboard.test.tsx | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/TODO.md b/TODO.md index 971709c0..7db24ea6 100644 --- a/TODO.md +++ b/TODO.md @@ -44,8 +44,7 @@ User Stories. As an Android PM, I should - what does telemetry look like for onboarding? other surfaces? similar to messaging? - Does Click telemetry on both iOS and Android alwyas mean CTA? Or something else? - What is action_uuid extra key (see docs)? - - **Do non-experimental message send pings on iOS or Android?** - - + - ## **Do non-experimental message send pings on iOS or Android?** 1. Draft plan for Android page @@ -63,6 +62,7 @@ User Stories. As an Android PM, I should 2. ~~?Consider options for cloning, since we'll want Android completed page too, and iOS pages (DONE)~~ 3. ~~Create new dir with new page.tsx (MUST)~~ 4. ~~TDD Factor out dashboard (DONE)~~ + 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) 2. ~~Put in separate android/ route (DONE)~~ @@ -71,7 +71,7 @@ User Stories. As an Android PM, I should 7. Add cases / refactor multiple feature ID list in experimentUtils.ts (MUST) 8. Add cases / refactor nimbusRecipe.ts:getBranchInfo (MUST) - 9. Add cases / refactor messageUtils.getDashboard (LATER) + 9. Add cases / refactor messageUtils.getDashboard (LATER) 10. Update / move messageUtils.getDashboardIdForTemplate (LATER) 11. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) 12. Add cases / refactor looker.ts:getCTRPercentData (LATER) diff --git a/__tests__/app/dashboard.test.tsx b/__tests__/app/dashboard.test.tsx index 4ce5d530..48ae9b3e 100644 --- a/__tests__/app/dashboard.test.tsx +++ b/__tests__/app/dashboard.test.tsx @@ -21,9 +21,7 @@ const mockFetchData = { describe.skip("Dashboard", () => { it("all timeline pill ids exist in the Dashboard component in /", async () => { - const dashboard = await render( - await - ); + const dashboard = await render(await ()); const firefox = dashboard.getByTestId("firefox"); const experiments = dashboard.getByTestId("live_experiments"); From ca9ab23ba24172ef7c3fb5a243e4250d50225fc9 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 14:09:45 -0700 Subject: [PATCH 22/46] Update TODO list --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 7db24ea6..3ec2211b 100644 --- a/TODO.md +++ b/TODO.md @@ -44,7 +44,7 @@ User Stories. As an Android PM, I should - what does telemetry look like for onboarding? other surfaces? similar to messaging? - Does Click telemetry on both iOS and Android alwyas mean CTA? Or something else? - What is action_uuid extra key (see docs)? - - ## **Do non-experimental message send pings on iOS or Android?** + - **Do non-experimental message send pings on iOS or Android?** 1. Draft plan for Android page @@ -66,7 +66,7 @@ User Stories. As an Android PM, I should 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) 2. ~~Put in separate android/ route (DONE)~~ - 5. Make test & code updates to not display local table (WIP) + 5. Make test & code updates to not display local table (DONE) 6. Factor "application=" out of env (MUST) 7. Add cases / refactor multiple feature ID list in experimentUtils.ts (MUST) 8. Add cases / refactor nimbusRecipe.ts:getBranchInfo (MUST) From 96aaed65b155bf49d93dc631758744b9949d796d Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 23 Mar 2025 16:45:41 -0700 Subject: [PATCH 23/46] Flesh out Android standup plan --- TODO.md | 57 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index 3ec2211b..1d5fc823 100644 --- a/TODO.md +++ b/TODO.md @@ -62,37 +62,46 @@ User Stories. As an Android PM, I should 2. ~~?Consider options for cloning, since we'll want Android completed page too, and iOS pages (DONE)~~ 3. ~~Create new dir with new page.tsx (MUST)~~ 4. ~~TDD Factor out dashboard (DONE)~~ - 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) 2. ~~Put in separate android/ route (DONE)~~ + 5. ~~Refactor to not display local table on Android (DONE)~~ - 5. Make test & code updates to not display local table (DONE) 6. Factor "application=" out of env (MUST) - 7. Add cases / refactor multiple feature ID list in experimentUtils.ts (MUST) - 8. Add cases / refactor nimbusRecipe.ts:getBranchInfo (MUST) - - 9. Add cases / refactor messageUtils.getDashboard (LATER) - 10. Update / move messageUtils.getDashboardIdForTemplate (LATER) - 11. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) - 12. Add cases / refactor looker.ts:getCTRPercentData (LATER) - 13. Make pills exclude local if not on desktop (LATER) - - 14. Update columns.tsx:filterBySurface (LATER) - 15. Add l10n (LATER) - 16. Factor Out NimbusMessageTable (NICE) - 17. Factor out high-level data fetching (NICE) - - 18. Pull in Android experiments using that URL - 19. Build dashboard link - 20. How to handle multi types - 21. Build CTR - 22. How to handle multi types - -2. standup 2nd page + 1. Create PlatformInfo interface + 1. application name + 2. Create PlatformInfoDict containing (android, desktop) + 3. pull experiments path component into EXPERIMENTER_API_PREFIX + 4. Get application param from PlatformInfoDict; remove from env + 5. Get status param from appropriate files; remove from env + 7. Pull platform-specific-feature-list from experimentUtils into + PlatformInfo (MUST) + 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (add messaging case for now and push to later or SPIKE) + + 9. Add cases / refactor messageUtils.getDashboard (IMPT) + 10. Update / move messageUtils.getDashboardIdForTemplate (IMPT) + + 11. Make pills exclude local if not on desktop (NICE) +. 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) + + 1. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 2. Support microsurveys badge, if sensible on mobile (LATER) + 3. Update columns.tsx:filterBySurface (LATER) + 4. Add l10n (LATER) + + 5. Factor Out NimbusMessageTable (EVEN LATER) + 6. Factor out high-level data fetching (EVEN LATER) + + 7. Pull in Android experiments using that URL + 8. Build dashboard link + 9. How to handle multi types + 10. Build CTR + 11. How to handle multi types + +1. standup 2nd page - TDD? clone for mobile -3. standup 2nd dashboard +2. standup 2nd dashboard * review mobile telemetry using glean dict * look at explores available for those tables From 0157aad64b2c4da038c0a547247567e0d65de671 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 24 Mar 2025 09:03:28 -0700 Subject: [PATCH 24/46] Minor TODO update --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 1d5fc823..11544e24 100644 --- a/TODO.md +++ b/TODO.md @@ -67,7 +67,7 @@ User Stories. As an Android PM, I should 5. ~~Refactor to not display local table on Android (DONE)~~ 6. Factor "application=" out of env (MUST) - 1. Create PlatformInfo interface + 1. Create PlatformInfo interface 1. application name 2. Create PlatformInfoDict containing (android, desktop) 3. pull experiments path component into EXPERIMENTER_API_PREFIX @@ -75,7 +75,7 @@ User Stories. As an Android PM, I should 5. Get status param from appropriate files; remove from env 7. Pull platform-specific-feature-list from experimentUtils into PlatformInfo (MUST) - 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (add messaging case for now and push to later or SPIKE) + 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging case for now; move to PlatformInfo later) 9. Add cases / refactor messageUtils.getDashboard (IMPT) 10. Update / move messageUtils.getDashboardIdForTemplate (IMPT) From 88614f00ffa0c8fe7b76942f77c8a8a7bb8597d8 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 24 Mar 2025 09:04:34 -0700 Subject: [PATCH 25/46] Add WIP MOBILE-EPICS list --- MOBILE-EPICS.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 MOBILE-EPICS.md diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md new file mode 100644 index 00000000..8ec5ae81 --- /dev/null +++ b/MOBILE-EPICS.md @@ -0,0 +1,33 @@ + +# Android +1. Dashboard Epic + 1. Make messaging feature Looker dashboard (3: DONE) + 2. Add monthly CTR, shared folder, permissions & docs) (LATER) +2. Stand up viewable (though incorrect) dashboard route (3: DONE) +3. Make things work for Android & Desktop enough to see Android msg rollouts: + 1. Page route/dashboard component (5: DONE) + 2. Data fetching: (5: DONE) + 3. Experimenter API client work (5) + 5. Feature ID list (3) + 6. Nimbus.GetBranchInfo (5) +4. Basic usability fixes + 1. Hide & LATER experiments table if not working (2) + 2. Make pills exclude "Firefox" on Android page (3?) +5. Rapidly Port features + 1. Add at least one other subsurfaces now? See Research + 2. Dashboard links + 3. Add full length Impressions/CTR chart to Looker dashboard + 4. Inline Impressions/CTR + 5. Better surface column + 6. Completed page +6. Maybe (some need research) + 1. Add other feature IDs? Prob at least onboarding + 2. Microsurveys badge? + 3. Surface-based filtering? +# Key Unknowns to research + 1. Non-Nimbus mobile messaging telemetry + 2. How much work is adding messaging sub-surfaces? + 3. Which other feature ids (eg onboarding) are desired? How much work will they be? + +# iOS + From 6b8cdfb286a73c2b4d1d60411f994774da83b58c Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 24 Mar 2025 11:32:27 -0700 Subject: [PATCH 26/46] Update mobile epics --- MOBILE-EPICS.md | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index 8ec5ae81..a8d81d03 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -1,33 +1,39 @@ +Top-level bullets are user story epics, 2nd-level bullet are regular user stories # Android -1. Dashboard Epic +1. Looker Dashboard 1. Make messaging feature Looker dashboard (3: DONE) - 2. Add monthly CTR, shared folder, permissions & docs) (LATER) -2. Stand up viewable (though incorrect) dashboard route (3: DONE) + 2. Shared folder, permissions & docs) (LATER) +2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) 3. Experimenter API client work (5) - 5. Feature ID list (3) - 6. Nimbus.GetBranchInfo (5) -4. Basic usability fixes - 1. Hide & LATER experiments table if not working (2) - 2. Make pills exclude "Firefox" on Android page (3?) -5. Rapidly Port features - 1. Add at least one other subsurfaces now? See Research - 2. Dashboard links - 3. Add full length Impressions/CTR chart to Looker dashboard - 4. Inline Impressions/CTR - 5. Better surface column + 4. Feature ID list (3) + 5. Nimbus.GetBranchInfo (5) + +4. Add experiments - or hide and LATER if interesting amount of work (3) +5. Key Unknowns to research + 1. Make a list of all-subsurfaces with links to telemetry + 2. How to handle production telemetry + 3. How much work is adding messaging sub-surfaces? + 4. Which other feature ids (eg onboarding) are desired? How much work will they be +6. Basic usability fix + 1. Make pills exclude "Firefox" on Android page (3?) +7. Handle production telemetry (waiting on research) +7. Rapidly Port features + 1. Add at least one other subsurface now? (waiting on research) + 2. Dashboard links (5) + 3. Add monthly Impressions/CTR chart to Looker dashboard (2) + 4. Inline Impressions/CTR (8 - needs breakdown or SPIKE) + 5. Fully useful surface columns () 6. Completed page -6. Maybe (some need research) +8. Maybe 1. Add other feature IDs? Prob at least onboarding 2. Microsurveys badge? 3. Surface-based filtering? -# Key Unknowns to research - 1. Non-Nimbus mobile messaging telemetry - 2. How much work is adding messaging sub-surfaces? - 3. Which other feature ids (eg onboarding) are desired? How much work will they be? # iOS +1. Looker Dashboard +2. Stand up viewable (though incorrect) Skylight dashboard route (3) From ce82b5a2478895ef112a05f2c1674853abd9d7e1 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 24 Mar 2025 12:58:44 -0700 Subject: [PATCH 27/46] Appease prettier --- MOBILE-EPICS.md | 10 +++-- TODO.md | 99 +++++++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index a8d81d03..2f694119 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -1,11 +1,13 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user stories # Android + 1. Looker Dashboard 1. Make messaging feature Looker dashboard (3: DONE) 2. Shared folder, permissions & docs) (LATER) 2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: + 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) 3. Experimenter API client work (5) @@ -17,23 +19,23 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 1. Make a list of all-subsurfaces with links to telemetry 2. How to handle production telemetry 3. How much work is adding messaging sub-surfaces? - 4. Which other feature ids (eg onboarding) are desired? How much work will they be + 4. Which other feature ids (eg onboarding) are desired? How much work will they be 6. Basic usability fix 1. Make pills exclude "Firefox" on Android page (3?) 7. Handle production telemetry (waiting on research) -7. Rapidly Port features +8. Rapidly Port features 1. Add at least one other subsurface now? (waiting on research) 2. Dashboard links (5) 3. Add monthly Impressions/CTR chart to Looker dashboard (2) 4. Inline Impressions/CTR (8 - needs breakdown or SPIKE) 5. Fully useful surface columns () 6. Completed page -8. Maybe +9. Maybe 1. Add other feature IDs? Prob at least onboarding 2. Microsurveys badge? 3. Surface-based filtering? # iOS + 1. Looker Dashboard 2. Stand up viewable (though incorrect) Skylight dashboard route (3) - diff --git a/TODO.md b/TODO.md index 11544e24..b5ead058 100644 --- a/TODO.md +++ b/TODO.md @@ -48,60 +48,61 @@ User Stories. As an Android PM, I should 1. Draft plan for Android page - 1. ?File ticket - 2. Build chart for Android messaging (DONE) - 3. Build 2nd chart (LATER) - 4. Build dashboard (DONE: id = 2191) - 5. Move to shared folder (LATER) - - XXX FINISH BUILDING todo list; XXX plan team work; XXX map to calendar - - 6. Build Android page - - 1. ~~Review existing clone for "completed" (DONE)~~ - 2. ~~?Consider options for cloning, since we'll want Android completed page too, and iOS pages (DONE)~~ - 3. ~~Create new dir with new page.tsx (MUST)~~ - 4. ~~TDD Factor out dashboard (DONE)~~ - 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) - 2. ~~Put in separate android/ route (DONE)~~ - 5. ~~Refactor to not display local table on Android (DONE)~~ - - 6. Factor "application=" out of env (MUST) - 1. Create PlatformInfo interface - 1. application name - 2. Create PlatformInfoDict containing (android, desktop) - 3. pull experiments path component into EXPERIMENTER_API_PREFIX - 4. Get application param from PlatformInfoDict; remove from env - 5. Get status param from appropriate files; remove from env - 7. Pull platform-specific-feature-list from experimentUtils into - PlatformInfo (MUST) - 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging case for now; move to PlatformInfo later) - - 9. Add cases / refactor messageUtils.getDashboard (IMPT) - 10. Update / move messageUtils.getDashboardIdForTemplate (IMPT) - - 11. Make pills exclude local if not on desktop (NICE) -. 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) - - 1. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) - 2. Support microsurveys badge, if sensible on mobile (LATER) - 3. Update columns.tsx:filterBySurface (LATER) - 4. Add l10n (LATER) - - 5. Factor Out NimbusMessageTable (EVEN LATER) - 6. Factor out high-level data fetching (EVEN LATER) - - 7. Pull in Android experiments using that URL - 8. Build dashboard link - 9. How to handle multi types - 10. Build CTR - 11. How to handle multi types + 1. ?File ticket + 2. Build chart for Android messaging (DONE) + 3. Build 2nd chart (LATER) + 4. Build dashboard (DONE: id = 2191) + 5. Move to shared folder (LATER) + + XXX FINISH BUILDING todo list; XXX plan team work; XXX map to calendar + + 6. Build Android page + + 1. ~~Review existing clone for "completed" (DONE)~~ + 2. ~~?Consider options for cloning, since we'll want Android completed page too, and iOS pages (DONE)~~ + 3. ~~Create new dir with new page.tsx (MUST)~~ + 4. ~~TDD Factor out dashboard (DONE)~~ + 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) + 2. ~~Put in separate android/ route (DONE)~~ + 5. ~~Refactor to not display local table on Android (DONE)~~ + + 6. Factor "application=" out of env (MUST) + 1. Create PlatformInfo interface + 1. application name + 2. Create PlatformInfoDict containing (android, desktop) + 3. pull experiments path component into EXPERIMENTER_API_PREFIX + 4. Get application param from PlatformInfoDict; remove from env + 5. Get status param from appropriate files; remove from env + 7. Pull platform-specific-feature-list from experimentUtils into + PlatformInfo (MUST) + 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging case for now; move to PlatformInfo later) + + 9. Add cases / refactor messageUtils.getDashboard (IMPT) + 10. Update / move messageUtils.getDashboardIdForTemplate (IMPT) + + 11. Make pills exclude local if not on desktop (NICE) + + . 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) + + 1. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 2. Support microsurveys badge, if sensible on mobile (LATER) + 3. Update columns.tsx:filterBySurface (LATER) + 4. Add l10n (LATER) + + 5. Factor Out NimbusMessageTable (EVEN LATER) + 6. Factor out high-level data fetching (EVEN LATER) + + 7. Pull in Android experiments using that URL + 8. Build dashboard link + 9. How to handle multi types + 10. Build CTR + 11. How to handle multi types 1. standup 2nd page - TDD? clone for mobile -2. standup 2nd dashboard +1. standup 2nd dashboard * review mobile telemetry using glean dict * look at explores available for those tables From d093b8b63524ab8064c2bf4842fcff357e635bd2 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Tue, 25 Mar 2025 16:47:03 -0700 Subject: [PATCH 28/46] Create platformInfo object --- lib/platformInfo.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 lib/platformInfo.ts diff --git a/lib/platformInfo.ts b/lib/platformInfo.ts new file mode 100644 index 00000000..efebd876 --- /dev/null +++ b/lib/platformInfo.ts @@ -0,0 +1,21 @@ + +interface PlatformInfo { + nimbusAppSlug: string; + displayName: string; +} + +export const platformDictionary: { [key: string]: PlatformInfo } = { + android: { + nimbusAppSlug: "fenix", + displayName: "Android", + }, + ios: { + nimbusAppSlug: "ios", + displayName: "iOS", + }, + desktop: { + nimbusAppSlug: "firefox-desktop", + displayName: "Desktop", + }, +}; + From c24d048c65a68270a1d3b45545ac962ddf887bc6 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Tue, 25 Mar 2025 17:14:18 -0700 Subject: [PATCH 29/46] Added a test to check for correct URL construction --- __tests__/lib/nimbusRecipeCollection.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/__tests__/lib/nimbusRecipeCollection.test.ts b/__tests__/lib/nimbusRecipeCollection.test.ts index f9d5082e..3b2a8585 100644 --- a/__tests__/lib/nimbusRecipeCollection.test.ts +++ b/__tests__/lib/nimbusRecipeCollection.test.ts @@ -27,6 +27,26 @@ describe("NimbusRecipeCollection", () => { expect(recipes).toEqual([new NimbusRecipe(fakeFetchData[0])]); }); + + it("constructs the correct URL for live experiments", async () => { + const nimbusRecipeCollection = new NimbusRecipeCollection(); + await nimbusRecipeCollection.fetchRecipes(); + + expect(global.fetch).toHaveBeenCalledWith( + `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_LIVE}`, + { credentials: "omit" }, + ); + }); + + it("constructs the correct URL for completed experiments", async () => { + const nimbusRecipeCollection = new NimbusRecipeCollection(true); + await nimbusRecipeCollection.fetchRecipes(); + + expect(global.fetch).toHaveBeenCalledWith( + `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_COMPLETED}`, + { credentials: "omit" }, + ); + }); }); describe("getExperimentAndBranchInfos", () => { From 3c1e9c577e5a09fe1238e23ad239fd9375001e9b Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Wed, 26 Mar 2025 13:22:08 -0700 Subject: [PATCH 30/46] Move experiments path component to a more sensible env var --- .env | 6 +++--- TODO.md | 39 ++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/.env b/.env index c1f850a2..075c426e 100644 --- a/.env +++ b/.env @@ -2,16 +2,16 @@ # Base URL for the experimenter API (defaults to the production instance) # -EXPERIMENTER_API_PREFIX="https://experimenter.services.mozilla.com/api/v7/" +EXPERIMENTER_API_PREFIX="https://experimenter.services.mozilla.com/api/v7/experiments/" # API calls with parameters to fetch experiments we want to display. # https://htmlpreview.github.io/?https://github.com/mozilla/experimenter/blob/main/docs/experimenter/swagger-ui.html has more info. # # Live experiments -EXPERIMENTER_API_CALL_LIVE="experiments/?status=Live&application=firefox-desktop" +EXPERIMENTER_API_CALL_LIVE="?status=Live&application=firefox-desktop" # Completed experiments -EXPERIMENTER_API_CALL_COMPLETED="experiments/?status=Complete&application=firefox-desktop" +EXPERIMENTER_API_CALL_COMPLETED="?status=Complete&application=firefox-desktop" # Looker configurables IS_LOOKER_ENABLED=false diff --git a/TODO.md b/TODO.md index b5ead058..d3c73ea8 100644 --- a/TODO.md +++ b/TODO.md @@ -67,12 +67,13 @@ User Stories. As an Android PM, I should 5. ~~Refactor to not display local table on Android (DONE)~~ 6. Factor "application=" out of env (MUST) - 1. Create PlatformInfo interface - 1. application name - 2. Create PlatformInfoDict containing (android, desktop) - 3. pull experiments path component into EXPERIMENTER_API_PREFIX - 4. Get application param from PlatformInfoDict; remove from env - 5. Get status param from appropriate files; remove from env + 1. ~~Create PlatformInfo interface~~ + 1. ~~application name~~ + 2. ~~Create PlatformInfoDict containing (android, desktop)~~ + 3. ~~pull experiments path component into EXPERIMENTER_API_PREFIX~~ + 4. Figure out how to resolve NimbusAppSlug and Platform param stuff + 5. Get application param from PlatformInfoDict; remove from env + 6. Get status param from appropriate files; remove from env 7. Pull platform-specific-feature-list from experimentUtils into PlatformInfo (MUST) 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging case for now; move to PlatformInfo later) @@ -84,25 +85,25 @@ User Stories. As an Android PM, I should . 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) - 1. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) - 2. Support microsurveys badge, if sensible on mobile (LATER) - 3. Update columns.tsx:filterBySurface (LATER) - 4. Add l10n (LATER) + 12. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 13. Support microsurveys badge, if sensible on mobile (LATER) + 14. Update columns.tsx:filterBySurface (LATER) + 15. Add l10n (LATER) - 5. Factor Out NimbusMessageTable (EVEN LATER) - 6. Factor out high-level data fetching (EVEN LATER) + 16. Factor Out NimbusMessageTable (EVEN LATER) + 17. Factor out high-level data fetching (EVEN LATER) - 7. Pull in Android experiments using that URL - 8. Build dashboard link - 9. How to handle multi types - 10. Build CTR - 11. How to handle multi types + 18. Pull in Android experiments using that URL + 19. Build dashboard link + 20. How to handle multi types + 21. Build CTR + 22. How to handle multi types -1. standup 2nd page +2. standup 2nd page - TDD? clone for mobile -1. standup 2nd dashboard +3. standup 2nd dashboard * review mobile telemetry using glean dict * look at explores available for those tables From 601d3cd6ac18ec00f8e1323459052613480f9bb7 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Wed, 26 Mar 2025 13:36:07 -0700 Subject: [PATCH 31/46] Standarize platform typing to the nimbus platform slug strings --- app/android/page.tsx | 2 +- app/dashboard.tsx | 2 +- app/page.tsx | 2 +- lib/platformInfo.ts | 15 +++++---------- lib/types.ts | 8 +++++--- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 0910294c..d428ab94 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -12,7 +12,7 @@ export default async function Page() { return ( = { + fenix: { displayName: "Android", }, ios: { - nimbusAppSlug: "ios", displayName: "iOS", }, - desktop: { - nimbusAppSlug: "firefox-desktop", + "firefox-desktop": { displayName: "Desktop", }, }; - diff --git a/lib/types.ts b/lib/types.ts index f6dda6b0..68681e99 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,3 +1,5 @@ -// These are used as strings in the UI, so we want to force them to be -// consistent and not have to worry about typos. -export type Platform = "Android" | "iOS" | "Desktop"; +// These are the same strings that the experimenter API uses to determine which +// endpoint to hit. XXX we should use our own ID and put this in +// PlatformInfo in case Nimbus changes its strings. + +export type Platform = "fenix" | "ios" | "firefox-desktop"; From d0e1f074c9659910695a86393fa10252e5c95224 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Wed, 26 Mar 2025 13:44:25 -0700 Subject: [PATCH 32/46] Fix platformDisplayName use --- app/dashboard.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/dashboard.tsx b/app/dashboard.tsx index e98f0471..7c29d838 100644 --- a/app/dashboard.tsx +++ b/app/dashboard.tsx @@ -13,16 +13,17 @@ import { MenuButton } from "@/components/ui/menubutton.tsx"; import { InfoPopover } from "@/components/ui/infopopover.tsx"; import { Timeline } from "@/components/ui/timeline.tsx"; import { Platform } from "@/lib/types"; +import { platformDictionary } from "@/lib/platformInfo.ts"; const hidden_message_impression_threshold = process.env.HIDDEN_MESSAGE_IMPRESSION_THRESHOLD; interface ReleasedTableProps { - platform: string; + platformDisplayName: string; localData: FxMSMessageInfo[]; } -const ReleasedTable = async ({ platform, localData }: ReleasedTableProps) => { +const ReleasedTable = async ({ platformDisplayName, localData }: ReleasedTableProps) => { return (
{ data-testid="firefox" className="scroll-m-20 text-xl font-semibold text-center pt-6 flex items-center justify-center gap-x-1" > - {platform} Messages Released on Firefox + {platformDisplayName} Messages Released on Firefox { + + const platformDisplayName = platformDictionary[platform].displayName; + return (
@@ -77,11 +81,11 @@ export const Dashboard = async ({
{localData ? ( - + ) : null}
- Current {platform} Message Rollouts + Current {platformDisplayName} Message Rollouts
- Current {platform} Message Experiments + Current {platformDisplayName} Message Experiments
Date: Wed, 26 Mar 2025 17:02:36 -0700 Subject: [PATCH 33/46] Remove some env vars for modularity --- .env | 9 --------- .env.sample | 5 +++-- __tests__/lib/nimbusRecipeCollection.test.ts | 12 +++++++++--- app/android/page.tsx | 8 ++++++-- app/fetchData.ts | 5 +++-- app/page.tsx | 6 ++++-- lib/nimbusRecipeCollection.ts | 17 ++++++++++++++--- 7 files changed, 39 insertions(+), 23 deletions(-) diff --git a/.env b/.env index 075c426e..3641f420 100644 --- a/.env +++ b/.env @@ -4,15 +4,6 @@ # EXPERIMENTER_API_PREFIX="https://experimenter.services.mozilla.com/api/v7/experiments/" -# API calls with parameters to fetch experiments we want to display. -# https://htmlpreview.github.io/?https://github.com/mozilla/experimenter/blob/main/docs/experimenter/swagger-ui.html has more info. -# -# Live experiments -EXPERIMENTER_API_CALL_LIVE="?status=Live&application=firefox-desktop" - -# Completed experiments -EXPERIMENTER_API_CALL_COMPLETED="?status=Complete&application=firefox-desktop" - # Looker configurables IS_LOOKER_ENABLED=false LOOKERSDK_BASE_URL=null diff --git a/.env.sample b/.env.sample index 39026f15..5a380ee4 100644 --- a/.env.sample +++ b/.env.sample @@ -1,7 +1,8 @@ # Copy this to .env.local to set local variables - # Preview -# EXPERIMENTER_API_CALL="experiments/?status=Preview&application=firefox-desktop" +# Base URL for the experimenter API (defaults to the production instance) +# +EXPERIMENTER_API_PREFIX="https://experimenter.services.mozilla.com/api/v7/experiments/" # Disable Auth0 for dev && preview environments IS_AUTH_ENABLED='false' diff --git a/__tests__/lib/nimbusRecipeCollection.test.ts b/__tests__/lib/nimbusRecipeCollection.test.ts index 3b2a8585..5abf41fa 100644 --- a/__tests__/lib/nimbusRecipeCollection.test.ts +++ b/__tests__/lib/nimbusRecipeCollection.test.ts @@ -2,6 +2,9 @@ import { NimbusRecipe } from "@/lib/nimbusRecipe"; import { NimbusRecipeCollection } from "@/lib/nimbusRecipeCollection"; import { ExperimentFakes } from "@/__tests__/ExperimentFakes.mjs"; import { RecipeInfo } from "@/app/columns"; +import { Platform } from "@/lib/types"; + +const platform: Platform = "firefox-desktop"; const fakeFetchData = [ExperimentFakes.recipe()]; global.fetch = jest.fn(() => @@ -29,11 +32,14 @@ describe("NimbusRecipeCollection", () => { }); it("constructs the correct URL for live experiments", async () => { - const nimbusRecipeCollection = new NimbusRecipeCollection(); + const nimbusRecipeCollection = new NimbusRecipeCollection( + false, + platform, + ); //XXX YYY await nimbusRecipeCollection.fetchRecipes(); expect(global.fetch).toHaveBeenCalledWith( - `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_LIVE}`, + `${process.env.EXPERIMENTER_API_PREFIX}?status=Live&application=${platform}`, { credentials: "omit" }, ); }); @@ -43,7 +49,7 @@ describe("NimbusRecipeCollection", () => { await nimbusRecipeCollection.fetchRecipes(); expect(global.fetch).toHaveBeenCalledWith( - `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_COMPLETED}`, + `${process.env.EXPERIMENTER_API_PREFIX}?status=Complete&application=${platform}`, { credentials: "omit" }, ); }); diff --git a/app/android/page.tsx b/app/android/page.tsx index d428ab94..1fa3e62e 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -1,5 +1,8 @@ import { Dashboard } from "@/app/dashboard"; import { fetchData } from "@/app/fetchData"; +import { Platform } from "@/lib/types"; + +const platform: Platform = "fenix"; export default async function Page() { const { @@ -8,11 +11,12 @@ export default async function Page() { totalExperiments, msgRolloutInfo, totalRolloutExperiments, - } = await fetchData(); + } = await fetchData(platform); + return ( ; isCompleted: boolean; fetchRecipes: () => Promise>; + platform: Platform; }; /** @@ -47,16 +49,25 @@ async function updateBranchesCTR(recipe: NimbusRecipe): Promise { export class NimbusRecipeCollection implements NimbusRecipeCollectionType { recipes: Array; isCompleted: boolean; + platform: Platform; - constructor(isCompleted: boolean = false) { + // XXX XXX remove this default platform, it's a total footgun + constructor( + isCompleted: boolean = false, + platform: Platform = "firefox-desktop", + ) { this.recipes = []; this.isCompleted = isCompleted; + this.platform = platform; } async fetchRecipes(): Promise> { - let experimenterUrl = `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_LIVE}`; + // XXX should really be using URL.parse and URLSearchParams to manage all + // this stuff + let experimenterUrl = `${process.env.EXPERIMENTER_API_PREFIX}?status=Live&application=${this.platform}`; if (this.isCompleted) { - experimenterUrl = `${process.env.EXPERIMENTER_API_PREFIX}${process.env.EXPERIMENTER_API_CALL_COMPLETED}`; + // XXX rename to isComplete for consistency + experimenterUrl = `${process.env.EXPERIMENTER_API_PREFIX}?status=Complete&application=${this.platform}`; } // console.log("experimenterURL = ", experimenterUrl) From ae6183204d619124656ce7f821bef97678fb55f1 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Wed, 26 Mar 2025 17:02:57 -0700 Subject: [PATCH 34/46] Appease prettier --- app/android/page.tsx | 1 - app/dashboard.tsx | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/android/page.tsx b/app/android/page.tsx index 1fa3e62e..7caaea97 100644 --- a/app/android/page.tsx +++ b/app/android/page.tsx @@ -13,7 +13,6 @@ export default async function Page() { totalRolloutExperiments, } = await fetchData(platform); - return ( { +const ReleasedTable = async ({ + platformDisplayName, + localData, +}: ReleasedTableProps) => { return (
{ - const platformDisplayName = platformDictionary[platform].displayName; return ( @@ -81,7 +83,10 @@ export const Dashboard = async ({
{localData ? ( - + ) : null}
From 312b432814a3bee386182e9ff07df9c72386a3f6 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Wed, 26 Mar 2025 19:25:07 -0700 Subject: [PATCH 35/46] Add in a couple of mobile surfaces --- lib/experimentUtils.ts | 2 ++ lib/nimbusRecipe.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/experimentUtils.ts b/lib/experimentUtils.ts index 9bb2fa71..598a4a09 100644 --- a/lib/experimentUtils.ts +++ b/lib/experimentUtils.ts @@ -26,7 +26,9 @@ export const MESSAGING_EXPERIMENTS_DEFAULT_FEATURES: string[] = [ "fxms-message-10", "fxms-message-11", "infobar", + "messaging", // XXX YYY "moments-page", + "onboarding", // XXX YYY "pbNewtab", "spotlight", "testFeature", diff --git a/lib/nimbusRecipe.ts b/lib/nimbusRecipe.ts index 0d0b34c1..a140683b 100644 --- a/lib/nimbusRecipe.ts +++ b/lib/nimbusRecipe.ts @@ -245,7 +245,16 @@ export class NimbusRecipe implements NimbusRecipeType { console.warn(`we don't fully support moments messages yet`); return branchInfo; + case "messaging": + console.warn(`we don't fully support messaging messages yet`); + return branchInfo; + + case "onboarding": + console.warn(`we don't fully support onboarding messages yet`); + return branchInfo; + default: + console.log("template = ", template); if (!feature.value?.messages) { // console.log("v.messages is null"); // console.log(", feature.value = ", feature.value); From d32f0b7e065360cfe9f0b4e57899c073a62e3da4 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 30 Mar 2025 15:07:25 -0700 Subject: [PATCH 36/46] Make fetchData for mobile default to live --- app/fetchData.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/fetchData.ts b/app/fetchData.ts index 206552fc..bb6fbdde 100644 --- a/app/fetchData.ts +++ b/app/fetchData.ts @@ -22,7 +22,10 @@ import { Platform } from "@/lib/types"; const isLookerEnabled = process.env.IS_LOOKER_ENABLED === "true"; export async function fetchData(platform: Platform) { - const recipeCollection = new NimbusRecipeCollection(true, platform); //XXX YYY + // XXX at some point, once the completed experiments get ported to use + // the new infra including this, we're going to need to do + // something better than just pass "false" as the first param here. + const recipeCollection = new NimbusRecipeCollection(false, platform); await recipeCollection.fetchRecipes(); console.log("recipeCollection.length = ", recipeCollection.recipes.length); From cb93e418578b368f06492f5c18b862ffcb9e3f1b Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 30 Mar 2025 15:08:48 -0700 Subject: [PATCH 37/46] Add some mobile surfaces + getAndroidBranchInfo --- app/columns.tsx | 4 +- lib/experimentUtils.ts | 9 ++++- lib/nimbusRecipe.ts | 91 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 88 insertions(+), 16 deletions(-) diff --git a/app/columns.tsx b/app/columns.tsx index e175cdd2..d1009b08 100644 --- a/app/columns.tsx +++ b/app/columns.tsx @@ -93,8 +93,8 @@ type NimbusExperiment = typeof nimbusExperimentV7Schema.properties; export type RecipeInfo = { product: "Desktop" | "Android"; id: string; - template?: string; - surface?: string; + template?: string; // XXX template JSON name + surface?: string; // XXX template display name segment?: string; ctrPercent?: number; ctrPercentChange?: number; diff --git a/lib/experimentUtils.ts b/lib/experimentUtils.ts index 598a4a09..619202fa 100644 --- a/lib/experimentUtils.ts +++ b/lib/experimentUtils.ts @@ -26,13 +26,18 @@ export const MESSAGING_EXPERIMENTS_DEFAULT_FEATURES: string[] = [ "fxms-message-10", "fxms-message-11", "infobar", - "messaging", // XXX YYY "moments-page", - "onboarding", // XXX YYY "pbNewtab", "spotlight", "testFeature", "whatsNewPage", + + // XXX these should live elsewhere; they are Android features + "cfr", + "encourage-search-cfr", + "messaging", + "juno-onboarding", + "set-to-default-prompt", ]; /** diff --git a/lib/nimbusRecipe.ts b/lib/nimbusRecipe.ts index a140683b..25c82e25 100644 --- a/lib/nimbusRecipe.ts +++ b/lib/nimbusRecipe.ts @@ -78,10 +78,85 @@ export class NimbusRecipe implements NimbusRecipeType { this._isCompleted = isCompleted; } - /** - * @returns an array of BranchInfo objects, one per branch in this recipe - */ + getAndroidBranchInfo(branch: any): BranchInfo { + let branchInfo: BranchInfo = { + product: "Android", + id: branch.slug, + isBranch: true, + // The raw experiment data can be automatically serialized to + // the client by NextJS (but classes can't), and any + // needed NimbusRecipe class rewrapping can be done there. + nimbusExperiment: this._rawRecipe, + slug: branch.slug, + screenshots: branch.screenshots, + description: branch.description, + }; + + // XXX need to handle multi branches + const feature = branch.features[0]; + + switch (feature.featureId) { + case "messaging": + // console.log("in messaging feature, feature = ", feature); + + // console.log("feature.value = ", feature.value); + if (Object.keys(feature.value).length === 0) { + console.warn( + "empty feature value, returning error, branch.slug = ", + branch.slug, + ); + return branchInfo; + } + + const message0: any = Object.values(feature.value.messages)[0]; + // console.log("message0 = ", message0); + + const surface = message0.surface; + + // XXX need to rename template & surface somehow + branchInfo.template = surface; + branchInfo.surface = surface; + + switch (surface) { + case "messages": + console.warn(`we don't fully support messaging messages yet`); + branchInfo.id = Object.keys(branch.feature.value.id.messages)[0]; + default: + console.warn("unhandled message surface: ", branchInfo.surface); + } + + case "juno-onboarding": + console.warn(`we don't fully support juno-onboarding messages yet`); + + default: + console.warn("default hit"); + console.warn("branch.slug = ", branch.slug); + console.warn("We don't support feature = ", feature); + // JSON.stringify(branch.features), + // ); + } + + const proposedEndDate = getExperimentLookerDashboardDate( + branchInfo.nimbusExperiment.startDate, + branchInfo.nimbusExperiment.proposedDuration, + ); + let formattedEndDate; + if (branchInfo.nimbusExperiment.endDate) { + formattedEndDate = formatDate(branchInfo.nimbusExperiment.endDate, 1); + } + + return branchInfo; + } getBranchInfo(branch: any): BranchInfo { + switch (this._rawRecipe.appName) { + case "fenix": + return this.getAndroidBranchInfo(branch); + default: + return this.getDesktopBranchInfo(branch); + } + } + + getDesktopBranchInfo(branch: any): BranchInfo { let branchInfo: BranchInfo = { product: "Desktop", id: branch.slug, @@ -245,16 +320,8 @@ export class NimbusRecipe implements NimbusRecipeType { console.warn(`we don't fully support moments messages yet`); return branchInfo; - case "messaging": - console.warn(`we don't fully support messaging messages yet`); - return branchInfo; - - case "onboarding": - console.warn(`we don't fully support onboarding messages yet`); - return branchInfo; - default: - console.log("template = ", template); + //console.log("Hit default case, template = ", template); if (!feature.value?.messages) { // console.log("v.messages is null"); // console.log(", feature.value = ", feature.value); From 12b9157d7956061865dbb2117c9ee4caae0f0be9 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Sun, 30 Mar 2025 15:09:03 -0700 Subject: [PATCH 38/46] Update TODO and EPICS --- MOBILE-EPICS.md | 37 +++++++++++++++++----------------- TODO.md | 53 ++++++++++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index 2f694119..9afb2e41 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -10,30 +10,31 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) - 3. Experimenter API client work (5) - 4. Feature ID list (3) - 5. Nimbus.GetBranchInfo (5) + 3. Experimenter API client work (DONE) + 4. Feature ID list (LATER) + 5. Nimbus.GetBranchInfo (5: DONE) -4. Add experiments - or hide and LATER if interesting amount of work (3) -5. Key Unknowns to research +4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) +5. Get simple dashboard links for surfaces we support (3) +6. Handle production telemetry (waiting on research) + +7. Key Unknowns to research 1. Make a list of all-subsurfaces with links to telemetry 2. How to handle production telemetry 3. How much work is adding messaging sub-surfaces? 4. Which other feature ids (eg onboarding) are desired? How much work will they be -6. Basic usability fix +8. Basic usability fix 1. Make pills exclude "Firefox" on Android page (3?) -7. Handle production telemetry (waiting on research) -8. Rapidly Port features - 1. Add at least one other subsurface now? (waiting on research) - 2. Dashboard links (5) - 3. Add monthly Impressions/CTR chart to Looker dashboard (2) - 4. Inline Impressions/CTR (8 - needs breakdown or SPIKE) - 5. Fully useful surface columns () - 6. Completed page -9. Maybe - 1. Add other feature IDs? Prob at least onboarding - 2. Microsurveys badge? - 3. Surface-based filtering? +9. Rapidly Port features +10. Add at least one other subsurface now? (DONE) +11. Add monthly Impressions/CTR chart to Looker dashboard (2) +12. Inline Impressions/CTR (8 - needs breakdown or SPIKE) +13. Fully useful surface columns () +14. Completed page +15. Maybe +16. Add other feature IDs? Prob at least onboarding +17. Microsurveys badge? +18. Surface-based filtering? # iOS diff --git a/TODO.md b/TODO.md index d3c73ea8..969324b1 100644 --- a/TODO.md +++ b/TODO.md @@ -65,39 +65,46 @@ User Stories. As an Android PM, I should 1. Use platform search param (TRIED; TOO FIDDLY, MAYBE LATER) 2. ~~Put in separate android/ route (DONE)~~ 5. ~~Refactor to not display local table on Android (DONE)~~ - - 6. Factor "application=" out of env (MUST) + 6. Factor "application=" out of env (DONE) 1. ~~Create PlatformInfo interface~~ 1. ~~application name~~ 2. ~~Create PlatformInfoDict containing (android, desktop)~~ 3. ~~pull experiments path component into EXPERIMENTER_API_PREFIX~~ - 4. Figure out how to resolve NimbusAppSlug and Platform param stuff - 5. Get application param from PlatformInfoDict; remove from env - 6. Get status param from appropriate files; remove from env + 4. ~~Figure out how to resolve NimbusAppSlug and Platform param stuff~~ + 5. ~~Get application param from PlatformInfoDict; remove from env~~ + 6. ~~Get status param from appropriate files; remove from env~~ 7. Pull platform-specific-feature-list from experimentUtils into - PlatformInfo (MUST) - 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging case for now; move to PlatformInfo later) - - 9. Add cases / refactor messageUtils.getDashboard (IMPT) - 10. Update / move messageUtils.getDashboardIdForTemplate (IMPT) - - 11. Make pills exclude local if not on desktop (NICE) + PlatformInfo (LATER) + 8. Move nimbusRecipe.ts:getBranchInfo into own file included into PlatformInfo? (fallback: add messaging cases for now; move to PlatformInfo later - XXX DONE) + 1. Detect by surface + 2. Call into GetAndroidBranchInfo + 1. Move existing code + 2. Copy-paste proposedEndDate + 3. ... + 9. Fix exeriments (DONE -- for messaging & juno-onboarding) + + 10.COMMIT STUFF + 11. Add cases / refactor messageUtils.getDashboard (IMPT) + 12. Update / move messageUtils.getDashboardIdForTemplate (IMPT) + + 13. Visual polish on surfaces? + 14. Make pills exclude local if not on desktop (NICE) . 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) - 12. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) - 13. Support microsurveys badge, if sensible on mobile (LATER) - 14. Update columns.tsx:filterBySurface (LATER) - 15. Add l10n (LATER) + 15. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 16. Support microsurveys badge, if sensible on mobile (LATER) + 17. Update columns.tsx:filterBySurface (LATER) + 18. Add l10n (LATER) - 16. Factor Out NimbusMessageTable (EVEN LATER) - 17. Factor out high-level data fetching (EVEN LATER) + 19. Factor Out NimbusMessageTable (EVEN LATER) + 20. Factor out high-level data fetching (EVEN LATER) - 18. Pull in Android experiments using that URL - 19. Build dashboard link - 20. How to handle multi types - 21. Build CTR - 22. How to handle multi types + 21. Pull in Android experiments using that URL + 22. Build dashboard link + 23. How to handle multi types + 24. Build CTR + 25. How to handle multi types 2. standup 2nd page From 40f431b836dd3eb620922334b36220c4dbad05f7 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 31 Mar 2025 11:29:51 -0700 Subject: [PATCH 39/46] Add dashboard link and update TODO/EPICS --- MOBILE-EPICS.md | 41 +++++++++++++++++++---------------- TODO.md | 38 ++++++++++++++++++-------------- lib/messageUtils.ts | 53 +++++++++++++++++++++++++++++++++++++++++++++ lib/nimbusRecipe.ts | 29 ++++++++++++++++++++++--- 4 files changed, 123 insertions(+), 38 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index 9afb2e41..a63e2d66 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -16,25 +16,28 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) 5. Get simple dashboard links for surfaces we support (3) -6. Handle production telemetry (waiting on research) - -7. Key Unknowns to research - 1. Make a list of all-subsurfaces with links to telemetry - 2. How to handle production telemetry - 3. How much work is adding messaging sub-surfaces? - 4. Which other feature ids (eg onboarding) are desired? How much work will they be -8. Basic usability fix - 1. Make pills exclude "Firefox" on Android page (3?) -9. Rapidly Port features -10. Add at least one other subsurface now? (DONE) -11. Add monthly Impressions/CTR chart to Looker dashboard (2) -12. Inline Impressions/CTR (8 - needs breakdown or SPIKE) -13. Fully useful surface columns () -14. Completed page -15. Maybe -16. Add other feature IDs? Prob at least onboarding -17. Microsurveys badge? -18. Surface-based filtering? +6. Publish to web so they can test +7. Get Amplitude onboarding dashboard + +8. Handle production telemetry (waiting on research) + +9. Key Unknowns to research +10. Make a list of all-subsurfaces with links to telemetry +11. How to handle production telemetry +12. How much work is adding messaging sub-surfaces? +13. Which other feature ids (eg onboarding) are desired? How much work will they be +14. Basic usability fix +15. Make pills exclude "Firefox" on Android page (3?) +16. Rapidly Port features +17. Add at least one other subsurface now? (DONE) +18. Add monthly Impressions/CTR chart to Looker dashboard (2) +19. Inline Impressions/CTR (8 - needs breakdown or SPIKE) +20. Fully useful surface columns () +21. Completed page +22. Maybe +23. Add other feature IDs? Prob at least onboarding +24. Microsurveys badge? +25. Surface-based filtering? # iOS diff --git a/TODO.md b/TODO.md index 969324b1..b336988b 100644 --- a/TODO.md +++ b/TODO.md @@ -83,28 +83,34 @@ User Stories. As an Android PM, I should 3. ... 9. Fix exeriments (DONE -- for messaging & juno-onboarding) - 10.COMMIT STUFF - 11. Add cases / refactor messageUtils.getDashboard (IMPT) - 12. Update / move messageUtils.getDashboardIdForTemplate (IMPT) + 10. Deploy to web (ALREADY WORKING) + 11. Add getAndroidDashboard + 12. Add getAndroidDashboardIdForTemplate + 13. -- + 14. Build onBoarding dashboard in Amplitude + 15. Link in - 13. Visual polish on surfaces? - 14. Make pills exclude local if not on desktop (NICE) + 16. Add cases / refactor messageUtils.getDashboard (IMPT) + 17. Update / move messageUtils.getDashboardIdForTemplate (IMPT) + + 18. Visual polish on surfaces? + 19. Make pills exclude local if not on desktop (NICE) . 2. Add cases / refactor looker.ts:getCTRPercentData (NICE) - 15. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) - 16. Support microsurveys badge, if sensible on mobile (LATER) - 17. Update columns.tsx:filterBySurface (LATER) - 18. Add l10n (LATER) + 20. Add cases / refactor templates & getSurfaceDataForTemplate (LATER) + 21. Support microsurveys badge, if sensible on mobile (LATER) + 22. Update columns.tsx:filterBySurface (LATER) + 23. Add l10n (LATER) - 19. Factor Out NimbusMessageTable (EVEN LATER) - 20. Factor out high-level data fetching (EVEN LATER) + 24. Factor Out NimbusMessageTable (EVEN LATER) + 25. Factor out high-level data fetching (EVEN LATER) - 21. Pull in Android experiments using that URL - 22. Build dashboard link - 23. How to handle multi types - 24. Build CTR - 25. How to handle multi types + 26. Pull in Android experiments using that URL + 27. Build dashboard link + 28. How to handle multi types + 29. Build CTR + 30. How to handle multi types 2. standup 2nd page diff --git a/lib/messageUtils.ts b/lib/messageUtils.ts index 11d31eaf..8b467ad3 100644 --- a/lib/messageUtils.ts +++ b/lib/messageUtils.ts @@ -113,6 +113,59 @@ export function _isAboutWelcomeTemplate(template: string): boolean { return aboutWelcomeSurfaces.includes(template); } +//mozilla.cloud.looker.com/dashboards/2191?Normalized+Channel=release&Submission+Date=2025%2F02%2F13+to+2025%2F03%2F13&Experiment+Slug=rootca-info-card-hcr1-fenix&Value+Branch=treatment-a&Sample+ID=%3C%3D10&Value=info%5E_card%5E_rootCA%5E_HCR1%25 + +export function getAndroidDashboard( + surface: string, + msgIdPrefix: string, + channel?: string, + experiment?: string, + branchSlug?: string, + startDate?: string | null, + endDate?: string | null, + isCompleted?: boolean, +): string | undefined { + // The isCompleted value can be useful for messages that used to be in remote + // settings or old versions of Firefox. + const submissionDate = getLookerSubmissionTimestampDateFilter( + startDate, + endDate, + isCompleted, + ); + + const dashboardId = 2191; // messages/push notification + // XXXgetDashboardIdForTemplate(surface); + let baseUrl = `https://mozilla.cloud.looker.com/dashboards/${dashboardId}`; + let paramObj; + + paramObj = { + "Submission Date": submissionDate, + //"Messaging System Message Id": msgIdPrefix, + "Normalized Channel": channel ? channel : "", + "Normalized OS": "", + "Client Info App Display Version": "", + "Normalized Country Code": "", + "Experiment Slug": experiment ? experiment : "", // XXX + "Experiment Branch": branchSlug ? branchSlug : "", + // XXX assumes last part of message id is something like + // "-en-us" and chops that off, since we want to know about + // all the messages in the experiment. Will break + // (in "no results" way) on experiment with messages not configured + // like that. + + Value: msgIdPrefix.slice(0, -5) + "%", // XXX + }; + + if (paramObj) { + const params = new URLSearchParams(Object.entries(paramObj)); + let url = new URL(baseUrl); + url.search = params.toString(); + return url.toString(); + } + + return undefined; +} + export function getDashboard( template: string, msgId: string, diff --git a/lib/nimbusRecipe.ts b/lib/nimbusRecipe.ts index 25c82e25..aa9e6325 100644 --- a/lib/nimbusRecipe.ts +++ b/lib/nimbusRecipe.ts @@ -1,5 +1,6 @@ import { BranchInfo, RecipeInfo, RecipeOrBranchInfo } from "../app/columns.jsx"; import { + getAndroidDashboard, getDashboard, getSurfaceDataForTemplate, getPreviewLink, @@ -109,24 +110,33 @@ export class NimbusRecipe implements NimbusRecipeType { } const message0: any = Object.values(feature.value.messages)[0]; + const message0Id: string = Object.keys(feature.value.messages)[0]; + branchInfo.id = message0Id; + // console.log("message0 = ", message0); const surface = message0.surface; - // XXX need to rename template & surface somehow branchInfo.template = surface; branchInfo.surface = surface; switch (surface) { case "messages": - console.warn(`we don't fully support messaging messages yet`); - branchInfo.id = Object.keys(branch.feature.value.id.messages)[0]; + // XXX I don' tthink this a real case + console.log("in messages surface case"); + break; + + case "survey": + break; + default: console.warn("unhandled message surface: ", branchInfo.surface); } + break; case "juno-onboarding": console.warn(`we don't fully support juno-onboarding messages yet`); + break; default: console.warn("default hit"); @@ -145,6 +155,19 @@ export class NimbusRecipe implements NimbusRecipeType { formattedEndDate = formatDate(branchInfo.nimbusExperiment.endDate, 1); } + branchInfo.ctrDashboardLink = getAndroidDashboard( + branchInfo.surface as string, + branchInfo.id, + undefined, + branchInfo.nimbusExperiment.slug, + branch.slug, + branchInfo.nimbusExperiment.startDate, + branchInfo.nimbusExperiment.endDate ? formattedEndDate : proposedEndDate, + this._isCompleted, + ); + + console.log("Android Dashboard:", branchInfo.ctrDashboardLink); + return branchInfo; } getBranchInfo(branch: any): BranchInfo { From 771d8404901853c3536a4a2ce44b7712503c796a Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Mon, 31 Mar 2025 11:34:07 -0700 Subject: [PATCH 40/46] Disable dashboard where it's not yet work --- lib/messageUtils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/messageUtils.ts b/lib/messageUtils.ts index 8b467ad3..f83a23e1 100644 --- a/lib/messageUtils.ts +++ b/lib/messageUtils.ts @@ -156,6 +156,9 @@ export function getAndroidDashboard( Value: msgIdPrefix.slice(0, -5) + "%", // XXX }; + // XXX we really handle all messaging surfaces, at least in theory + if (surface !== "survey") return undefined; + if (paramObj) { const params = new URLSearchParams(Object.entries(paramObj)); let url = new URL(baseUrl); From f4725d2c0d4f4fd4fd1130f5d74401a321a2a9c4 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Tue, 8 Apr 2025 11:49:17 -0700 Subject: [PATCH 41/46] Update MOBILE-EPICS.md --- MOBILE-EPICS.md | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index a63e2d66..c31a0d5e 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -7,29 +7,38 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 2. Shared folder, permissions & docs) (LATER) 2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: - 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) - 3. Experimenter API client work (DONE) - 4. Feature ID list (LATER) - 5. Nimbus.GetBranchInfo (5: DONE) - -4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) -5. Get simple dashboard links for surfaces we support (3) -6. Publish to web so they can test -7. Get Amplitude onboarding dashboard - + +1. Diagnose Viewpoint Dashboard link 0/0 CTR +1. Prototype (timebox) simple onboarding dashboard (funnel?) + +1. Start landing pieces of android branch incrementally: + 4. Experimenter API client work (DONE) - move to main + 5. Feature ID list (CLEAN UP) - Update comments in file. "Cross-platform list of Nimbus feature IDs" + 6. Nimbus.GetBranchInfo (5: DONE) - Write tests + 4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) - Tests? + 5. Get simple dashboard links for surfaces we support (3: DONE) - Tests? + 6. Publish to web so they can test (DONE) +1. Add at least one other subsurface now? (DONE) - Tests? + +1. Fix $pivot by index numbers stuff in Looker dashboard +1. Make pills exclude "Firefox" on Android page (3?) 8. Handle production telemetry (waiting on research) - 9. Key Unknowns to research -10. Make a list of all-subsurfaces with links to telemetry -11. How to handle production telemetry -12. How much work is adding messaging sub-surfaces? -13. Which other feature ids (eg onboarding) are desired? How much work will they be -14. Basic usability fix -15. Make pills exclude "Firefox" on Android page (3?) + 1. Enumerate Nimbus telemetry feature ids to show + 2. Enumerate production teletry that can be shown for each surface + 3. + 3. Make a list of all-subsurfaces (of messaging) with links to telemetry + + 13. Which other feature ids (eg onboarding) are desired? How much work will they be + 14. Make Amplitude choices + 14. TODO (Dan): talk to JB re Amplitude rollout + 15. MAKE + + 16. + 16. Rapidly Port features -17. Add at least one other subsurface now? (DONE) 18. Add monthly Impressions/CTR chart to Looker dashboard (2) 19. Inline Impressions/CTR (8 - needs breakdown or SPIKE) 20. Fully useful surface columns () @@ -42,4 +51,4 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie # iOS 1. Looker Dashboard -2. Stand up viewable (though incorrect) Skylight dashboard route (3) +2. Stand up viewable Skylight dashboard route (3) From 07aad9d734d4e9b62e18f7a8fa49066df66f001f Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Tue, 8 Apr 2025 11:50:54 -0700 Subject: [PATCH 42/46] Appease prettier --- MOBILE-EPICS.md | 69 ++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index c31a0d5e..701de267 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -7,46 +7,39 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 2. Shared folder, permissions & docs) (LATER) 2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: + 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) - -1. Diagnose Viewpoint Dashboard link 0/0 CTR -1. Prototype (timebox) simple onboarding dashboard (funnel?) - -1. Start landing pieces of android branch incrementally: - 4. Experimenter API client work (DONE) - move to main - 5. Feature ID list (CLEAN UP) - Update comments in file. "Cross-platform list of Nimbus feature IDs" - 6. Nimbus.GetBranchInfo (5: DONE) - Write tests - 4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) - Tests? - 5. Get simple dashboard links for surfaces we support (3: DONE) - Tests? - 6. Publish to web so they can test (DONE) -1. Add at least one other subsurface now? (DONE) - Tests? - -1. Fix $pivot by index numbers stuff in Looker dashboard -1. Make pills exclude "Firefox" on Android page (3?) -8. Handle production telemetry (waiting on research) -9. Key Unknowns to research - 1. Enumerate Nimbus telemetry feature ids to show - 2. Enumerate production teletry that can be shown for each surface - 3. - 3. Make a list of all-subsurfaces (of messaging) with links to telemetry - - 13. Which other feature ids (eg onboarding) are desired? How much work will they be - 14. Make Amplitude choices - 14. TODO (Dan): talk to JB re Amplitude rollout - 15. MAKE - - 16. - -16. Rapidly Port features -18. Add monthly Impressions/CTR chart to Looker dashboard (2) -19. Inline Impressions/CTR (8 - needs breakdown or SPIKE) -20. Fully useful surface columns () -21. Completed page -22. Maybe -23. Add other feature IDs? Prob at least onboarding -24. Microsurveys badge? -25. Surface-based filtering? + +4. Diagnose Viewpoint Dashboard link 0/0 CTR +5. Prototype (timebox) simple onboarding dashboard (funnel?) + +6. Start landing pieces of android branch incrementally: 4. Experimenter API client work (DONE) - move to main 5. Feature ID list (CLEAN UP) - Update comments in file. "Cross-platform list of Nimbus feature IDs" 6. Nimbus.GetBranchInfo (5: DONE) - Write tests 4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) - Tests? 5. Get simple dashboard links for surfaces we support (3: DONE) - Tests? 6. Publish to web so they can test (DONE) +7. Add at least one other subsurface now? (DONE) - Tests? + +8. Fix $pivot by index numbers stuff in Looker dashboard +9. Make pills exclude "Firefox" on Android page (3?) +10. Handle production telemetry (waiting on research) +11. Key Unknowns to research + + 1. Enumerate Nimbus telemetry feature ids to show 2. Enumerate production teletry that can be shown for each surface 3. + 2. Make a list of all-subsurfaces (of messaging) with links to telemetry + 3. Which other feature ids (eg onboarding) are desired? How much work will they be + 4. Make Amplitude choices + 5. TODO (Dan): talk to JB re Amplitude rollout + 6. MAKE + + 7. + +12. Rapidly Port features +13. Add monthly Impressions/CTR chart to Looker dashboard (2) +14. Inline Impressions/CTR (8 - needs breakdown or SPIKE) +15. Fully useful surface columns () +16. Completed page +17. Maybe +18. Add other feature IDs? Prob at least onboarding +19. Microsurveys badge? +20. Surface-based filtering? # iOS From f08fe1a95768e6ebc65548fcd450311fff264492 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Fri, 11 Apr 2025 15:14:57 -0700 Subject: [PATCH 43/46] Update EPICs --- MOBILE-EPICS.md | 80 ++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index 701de267..e710b337 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -7,39 +7,59 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 2. Shared folder, permissions & docs) (LATER) 2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: - 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) -4. Diagnose Viewpoint Dashboard link 0/0 CTR -5. Prototype (timebox) simple onboarding dashboard (funnel?) - -6. Start landing pieces of android branch incrementally: 4. Experimenter API client work (DONE) - move to main 5. Feature ID list (CLEAN UP) - Update comments in file. "Cross-platform list of Nimbus feature IDs" 6. Nimbus.GetBranchInfo (5: DONE) - Write tests 4. Add experiments - or hide and LATER if interesting amount of work (2: DONE) - Tests? 5. Get simple dashboard links for surfaces we support (3: DONE) - Tests? 6. Publish to web so they can test (DONE) -7. Add at least one other subsurface now? (DONE) - Tests? - -8. Fix $pivot by index numbers stuff in Looker dashboard -9. Make pills exclude "Firefox" on Android page (3?) -10. Handle production telemetry (waiting on research) -11. Key Unknowns to research - - 1. Enumerate Nimbus telemetry feature ids to show 2. Enumerate production teletry that can be shown for each surface 3. - 2. Make a list of all-subsurfaces (of messaging) with links to telemetry - 3. Which other feature ids (eg onboarding) are desired? How much work will they be - 4. Make Amplitude choices - 5. TODO (Dan): talk to JB re Amplitude rollout - 6. MAKE - - 7. - -12. Rapidly Port features -13. Add monthly Impressions/CTR chart to Looker dashboard (2) -14. Inline Impressions/CTR (8 - needs breakdown or SPIKE) -15. Fully useful surface columns () -16. Completed page -17. Maybe -18. Add other feature IDs? Prob at least onboarding -19. Microsurveys badge? -20. Surface-based filtering? +4. Diagnose Viewpoint Dashboard link 0/0 CTR (DONE) + +5. Start landing pieces of android branch incrementally: + 1. Experimenter API client work (DONE) - landed on main + 2. Publish to web so they can test (DONE) + + 3. Env var changes - landed on branch + 1. Draft plan; ask Emily to review + 2. Create PR for main for this one change + 3. Netlify deploy should be failing + 4. Add new env variable to Netlify + 5. Netlify deploy should start succeeding + 6. Update docs (README and .env* and CONTRIBUTING?) + 7. Merge branch change + 4. Feature ID list (DONE on branch) + 1. CLEAN UP slightly: Update comments in file & land eg "Cross-platform list of Nimbus feature IDs" + 5. Fix existing dashboard tests on branch + 6. Nimbus.GetBranchInfo (5: DONE) - Write tests & review + 7. Show experiments & rollouts for a few key surfaces (DONE on branch) - Tests? + 8. Get simple dashboard links for messaging surface (DONE on branch) - Tests? + +6. Onboarding dashboard - desktop-equivalent (WIP on branch) +7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (2) + 1. Correctly label these "users impressed", +8. Add Inline Impressions/CTR to Skylight `messaging` (8 - needs breakdown or SPIKE) + ** TODO (Dan): draft checklist & plan for this + +9. Clean up dashboards with separate stats: users impressed & clicks / User Impression Rate & CTR + 1. Separate chart? + + +--- + +1. Fix $pivot by index numbers stuff in Looker dashboard +2. Make pills exclude "Firefox" on Android page, since we don't yet have production section (3?) +3. Onboarding funnel (XXXdmose add notes) +4. Fully useful surface columns +5. Completed page + +6. Key Unknowns to research + 1. Enumerate Nimbus telemetry feature ids to show + 1. Enumerate production teletry that can be shown for each surface + 2. Make a list of all-subsurfaces (of messaging) with links to telemetry + 3. Which other feature ids (eg onboarding) are desired? How much work will they be? +7. Handle production telemetry (waiting on research; chat with Vasant) + +8. Maybe immediate; maybe iOS first + 1. Add other feature IDs? Prob at least onboarding + 2. Microsurveys badge? + 3. Surface-based filtering? # iOS From b57e061529032c42513758e2059bb8f72efe253c Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Fri, 11 Apr 2025 15:15:20 -0700 Subject: [PATCH 44/46] prettier --- MOBILE-EPICS.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index e710b337..158a58f3 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -7,12 +7,14 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 2. Shared folder, permissions & docs) (LATER) 2. Stand up viewable (though incorrect) Skylight dashboard route (3: DONE) 3. Make things work for Android & Desktop enough to see Android msg rollouts: + 1. Page route/dashboard component (5: DONE) 2. Data fetching: (5: DONE) 4. Diagnose Viewpoint Dashboard link 0/0 CTR (DONE) 5. Start landing pieces of android branch incrementally: + 1. Experimenter API client work (DONE) - landed on main 2. Publish to web so they can test (DONE) @@ -22,7 +24,7 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 3. Netlify deploy should be failing 4. Add new env variable to Netlify 5. Netlify deploy should start succeeding - 6. Update docs (README and .env* and CONTRIBUTING?) + 6. Update docs (README and .env\* and CONTRIBUTING?) 7. Merge branch change 4. Feature ID list (DONE on branch) 1. CLEAN UP slightly: Update comments in file & land eg "Cross-platform list of Nimbus feature IDs" @@ -32,14 +34,13 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 8. Get simple dashboard links for messaging surface (DONE on branch) - Tests? 6. Onboarding dashboard - desktop-equivalent (WIP on branch) -7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (2) - 1. Correctly label these "users impressed", -8. Add Inline Impressions/CTR to Skylight `messaging` (8 - needs breakdown or SPIKE) - ** TODO (Dan): draft checklist & plan for this - -9. Clean up dashboards with separate stats: users impressed & clicks / User Impression Rate & CTR - 1. Separate chart? +7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (2) + 1. Correctly label these "users impressed", +8. Add Inline Impressions/CTR to Skylight `messaging` (8 - needs breakdown or SPIKE) + \*\* TODO (Dan): draft checklist & plan for this +9. Clean up dashboards with separate stats: users impressed & clicks / User Impression Rate & CTR +10. Separate chart? --- @@ -50,13 +51,13 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 5. Completed page 6. Key Unknowns to research - 1. Enumerate Nimbus telemetry feature ids to show - 1. Enumerate production teletry that can be shown for each surface - 2. Make a list of all-subsurfaces (of messaging) with links to telemetry - 3. Which other feature ids (eg onboarding) are desired? How much work will they be? -7. Handle production telemetry (waiting on research; chat with Vasant) +7. Enumerate Nimbus telemetry feature ids to show + 1. Enumerate production teletry that can be shown for each surface +8. Make a list of all-subsurfaces (of messaging) with links to telemetry +9. Which other feature ids (eg onboarding) are desired? How much work will they be? +10. Handle production telemetry (waiting on research; chat with Vasant) -8. Maybe immediate; maybe iOS first +11. Maybe immediate; maybe iOS first 1. Add other feature IDs? Prob at least onboarding 2. Microsurveys badge? 3. Surface-based filtering? From 6c34a6a542e8615bee2e719eba9b32f00d706384 Mon Sep 17 00:00:00 2001 From: Sarah Chung Date: Thu, 17 Apr 2025 16:44:11 -0400 Subject: [PATCH 45/46] Update MOBILE-EPICS --- MOBILE-EPICS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index 158a58f3..bc4b334a 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -18,7 +18,7 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 1. Experimenter API client work (DONE) - landed on main 2. Publish to web so they can test (DONE) - 3. Env var changes - landed on branch + 3. Env var changes - landed on branch (DONE) 1. Draft plan; ask Emily to review 2. Create PR for main for this one change 3. Netlify deploy should be failing @@ -26,15 +26,15 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 5. Netlify deploy should start succeeding 6. Update docs (README and .env\* and CONTRIBUTING?) 7. Merge branch change - 4. Feature ID list (DONE on branch) + 4. Feature ID list (DONE) 1. CLEAN UP slightly: Update comments in file & land eg "Cross-platform list of Nimbus feature IDs" 5. Fix existing dashboard tests on branch - 6. Nimbus.GetBranchInfo (5: DONE) - Write tests & review - 7. Show experiments & rollouts for a few key surfaces (DONE on branch) - Tests? - 8. Get simple dashboard links for messaging surface (DONE on branch) - Tests? + 6. Nimbus.GetBranchInfo (DONE - tests added) + 7. Get simple dashboard links for messaging surface (DONE - tests added) + 8. Show experiments & rollouts for a few key surfaces (DONE on branch) - Tests? 6. Onboarding dashboard - desktop-equivalent (WIP on branch) -7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (2) +7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (DONE on branch) 1. Correctly label these "users impressed", 8. Add Inline Impressions/CTR to Skylight `messaging` (8 - needs breakdown or SPIKE) \*\* TODO (Dan): draft checklist & plan for this From 5e4290af6269453d76e513c9f6f890fc3855516e Mon Sep 17 00:00:00 2001 From: Sarah Chung Date: Tue, 29 Apr 2025 15:10:49 -0400 Subject: [PATCH 46/46] Add notes on onboarding dashboard in MOBILE-EPICS --- MOBILE-EPICS.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MOBILE-EPICS.md b/MOBILE-EPICS.md index bc4b334a..c8b60f49 100644 --- a/MOBILE-EPICS.md +++ b/MOBILE-EPICS.md @@ -34,6 +34,15 @@ Top-level bullets are user story epics, 2nd-level bullet are regular user storie 8. Show experiments & rollouts for a few key surfaces (DONE on branch) - Tests? 6. Onboarding dashboard - desktop-equivalent (WIP on branch) + - Notes: + - [Link](https://mozilla.cloud.looker.com/explore/fenix/event_counts?qid=KV1MOvKpSSGkcvLOfpIxJX&origin_space=60&toggle=fil) to the in-progress dashboard + - `sequence_id` + - https://searchfox.org/mozilla-release/source/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/view/OnboardingPageUiData.kt#51 + - Seems to be a sequence of a card type as seen above, and determines the order in which these cards are shown in the onboarding sequence + - `element_type` + - element types of `onboarding_card` can have impression actions, while element types of `primary_button` or `secondary_button` can have click actions + - `sequence_position` + - The same card can be in different positions for different experiment or treatments (?) 7. Add monthly Impressions/CTR chart to Looker `messaging` dashboard (DONE on branch) 1. Correctly label these "users impressed", 8. Add Inline Impressions/CTR to Skylight `messaging` (8 - needs breakdown or SPIKE)