Ver Fonte

Merge pull request #1551 from porter-dev/nico/por-228-add-analytics-for-new-onboarding-flow

[POR-228] Add analytics for new onboarding flow
Nicolas Frati há 4 anos atrás
pai
commit
846270dddd

+ 2 - 0
dashboard/src/main/home/new-project/NewProject.tsx

@@ -15,6 +15,7 @@ import { isAlphanumeric } from "shared/common";
 import InputRow from "components/form-components/InputRow";
 import Helper from "components/form-components/Helper";
 import TitleSection from "components/TitleSection";
+import { trackCreateNewProject } from "shared/anayltics";
 
 type ValidationError = {
   hasError: boolean;
@@ -94,6 +95,7 @@ export const NewProjectFC = () => {
       setProjects(projectList);
       setCurrentProject(project);
       setButtonStatus("successful");
+      trackCreateNewProject();
       pushFiltered("/onboarding", []);
     } catch (error) {
       setButtonStatus("Couldn't create project, try again.");

+ 6 - 2
dashboard/src/main/home/onboarding/steps/ConnectRegistry/ConnectRegistry.tsx

@@ -15,8 +15,8 @@ import { OFState } from "../../state";
 import { useSnapshot } from "valtio";
 import api from "shared/api";
 import Loading from "components/Loading";
-import { integrationList } from "shared/common";
 import Registry from "./components/Registry";
+import { connectRegistryTracks } from "shared/anayltics";
 
 const ConnectRegistry: React.FC<{}> = ({}) => {
   const snap = useSnapshot(OFState);
@@ -78,11 +78,15 @@ const ConnectRegistry: React.FC<{}> = ({}) => {
   };
 
   const handleSkip = () => {
+    connectRegistryTracks.trackSkipRegistryConnection();
     OFState.actions.nextStep("skip");
   };
 
   const handleSelectProvider = (provider: string) => {
-    provider !== "skip" && OFState.actions.nextStep("continue", provider);
+    if (provider !== "skip") {
+      connectRegistryTracks.trackConnectRegistryIntent({ provider });
+      OFState.actions.nextStep("continue", provider);
+    }
   };
 
   const handleContinueWithCurrent = () => {

+ 32 - 1
dashboard/src/main/home/onboarding/steps/ConnectRegistry/forms/FormFlow.tsx

@@ -28,6 +28,8 @@ import {
 } from "./_GCPRegistryForm";
 import { OFState } from "main/home/onboarding/state";
 import { useSnapshot } from "valtio";
+import { connectRegistryTracks, trackRedirectToGuide } from "shared/anayltics";
+import { StepHandler } from "main/home/onboarding/state/StepHandler";
 
 const Forms = {
   aws: {
@@ -74,6 +76,7 @@ type Props = {
 
 const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
   const snap = useSnapshot(StateHandler);
+  const stepHandler = useSnapshot(StepHandler);
 
   const provider = snap.connected_registry.provider as SupportedProviders;
   const project = snap.project;
@@ -90,8 +93,15 @@ const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
     data?: Partial<Exclude<ConnectedRegistryConfig, SkipRegistryConnection>>
   ) => {
     if (currentStep === "credentials") {
+      connectRegistryTracks.trackRegistryAddCredentials({
+        provider: provider,
+        step: stepHandler.currentStepName,
+      });
       handleContinue(data.credentials);
     } else if (currentStep === "settings") {
+      connectRegistryTracks.trackConnectRegistryClicked({
+        provider: provider,
+      });
       handleContinue(data.settings);
     } else if (currentStep === "test_connection") {
       handleContinue();
@@ -127,7 +137,28 @@ const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
           {FormTitle[provider] && <img src={FormTitle[provider].icon} />}
           {FormTitle[provider] && FormTitle[provider].label}
         </FormHeader>
-        <GuideButton href={FormTitle[provider].doc} target="_blank">
+        <GuideButton
+          href={FormTitle[provider].doc}
+          target="_blank"
+          onAuxClick={() => {
+            trackRedirectToGuide({
+              step: stepHandler.currentStepName,
+              guide_url: FormTitle[provider].doc,
+              provider,
+            });
+            // Will allow the anchor tag to redirect properly
+            return true;
+          }}
+          onClick={() => {
+            trackRedirectToGuide({
+              step: stepHandler.currentStepName,
+              guide_url: FormTitle[provider].doc,
+              provider,
+            });
+            // Will allow the anchor tag to redirect properly
+            return true;
+          }}
+        >
           <i className="material-icons-outlined">help</i>
           Guide
         </GuideButton>

+ 16 - 0
dashboard/src/main/home/onboarding/steps/ConnectSource.tsx

@@ -8,6 +8,7 @@ import { useRouting } from "shared/routing";
 import styled from "styled-components";
 import { OFState } from "../state";
 import github from "assets/github.png";
+import { connectSourceTracks } from "shared/anayltics";
 
 interface GithubAppAccessData {
   username?: string;
@@ -60,6 +61,11 @@ const ConnectSource: React.FC<{
   }, []);
 
   const nextStep = (selectedSource: "docker" | "github") => {
+    if (selectedSource === "docker") {
+      connectSourceTracks.trackUseDockerRegistryClicked();
+    } else {
+      connectSourceTracks.trackContinueAfterGithubConnect();
+    }
     onSuccess(selectedSource);
   };
 
@@ -87,6 +93,11 @@ const ConnectSource: React.FC<{
         <>
           <ConnectToGithubButton
             href={`/api/integrations/github-app/install?redirect_uri=${encoded_redirect_uri}`}
+            onClick={() => {
+              connectSourceTracks.trackConnectGithubButtonClicked();
+              // Will allow the anchor tag to redirect properly
+              return true;
+            }}
           >
             <GitHubIcon src={github} /> Connect to GitHub
           </ConnectToGithubButton>
@@ -120,6 +131,11 @@ const ConnectSource: React.FC<{
             Don't see the right repos?{" "}
             <A
               href={`/api/integrations/github-app/install?redirect_uri=${encoded_redirect_uri}`}
+              onClick={() => {
+                connectSourceTracks.trackInstallOnMoreRepositoriesClicked();
+                // Will allow the anchor tag to redirect properly
+                return true;
+              }}
             >
               Install Porter in more repositories
             </A>

+ 3 - 0
dashboard/src/main/home/onboarding/steps/ProvisionResources/ProvisionResources.tsx

@@ -15,6 +15,7 @@ import backArrow from "assets/back_arrow.png";
 import { StatusPage } from "./forms/StatusPage";
 import { useSnapshot } from "valtio";
 import { OFState } from "../../state";
+import { provisionResourcesTracks } from "shared/anayltics";
 
 type Props = {};
 
@@ -42,9 +43,11 @@ const ProvisionResources: React.FC<Props> = () => {
 
   const handleSelectProvider = (provider: string) => {
     if (provider !== "external") {
+      provisionResourcesTracks.trackProvisionIntent({ provider });
       OFState.actions.nextStep("continue", provider);
       return;
     }
+    provisionResourcesTracks.trackConnectExternalClusterIntent();
     OFState.actions.nextStep("skip");
   };
 

+ 40 - 1
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/FormFlow.tsx

@@ -26,6 +26,11 @@ import {
 } from "./_GCPProvisionerForm";
 import { OFState } from "main/home/onboarding/state";
 import { useSnapshot } from "valtio";
+import {
+  provisionResourcesTracks,
+  trackRedirectToGuide,
+} from "shared/anayltics";
+import { StepHandler } from "main/home/onboarding/state/StepHandler";
 
 const Forms = {
   aws: {
@@ -71,6 +76,7 @@ type Props = {
 
 const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
   const snap = useSnapshot(StateHandler);
+  const stepHandler = useSnapshot(StepHandler);
 
   const provider = snap.provision_resources?.provider as
     | SupportedProviders
@@ -90,8 +96,20 @@ const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
     data?: Partial<Exclude<ProvisionerConfig, SkipProvisionConfig>>
   ) => {
     if (currentStep === "credentials") {
+      provisionResourcesTracks.trackProvisionAddCredentials({
+        provider: provider,
+        step: stepHandler.currentStepName,
+      });
       handleContinue(data);
     } else if (currentStep === "settings") {
+      const settings: any = data?.settings;
+      provisionResourcesTracks.trackProvisionResourcesClicked({
+        provider: provider,
+        cluster_name: settings?.cluster_name,
+        machine_type: settings?.aws_machine_type,
+        region: settings?.region,
+        subscription_tier: settings?.tier,
+      });
       handleContinue(data);
     }
   };
@@ -125,7 +143,28 @@ const FormFlowWrapper: React.FC<Props> = ({ currentStep }) => {
           {FormTitle[provider] && <img src={FormTitle[provider].icon} />}
           {FormTitle[provider] && FormTitle[provider].label}
         </FormHeader>
-        <GuideButton href={FormTitle[provider]?.doc} target="_blank">
+        <GuideButton
+          href={FormTitle[provider]?.doc}
+          target="_blank"
+          onAuxClick={() => {
+            trackRedirectToGuide({
+              step: stepHandler.currentStepName,
+              guide_url: FormTitle[provider].doc,
+              provider,
+            });
+            // Will allow the anchor tag to redirect properly
+            return true;
+          }}
+          onClick={() => {
+            trackRedirectToGuide({
+              step: stepHandler.currentStepName,
+              guide_url: FormTitle[provider].doc,
+              provider,
+            });
+            // Will allow the anchor tag to redirect properly
+            return true;
+          }}
+        >
           <i className="material-icons-outlined">help</i>
           Guide
         </GuideButton>

+ 5 - 1
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/_ConnectExternalCluster.tsx

@@ -4,6 +4,7 @@ import TabSelector from "components/TabSelector";
 import api from "shared/api";
 import SaveButton from "components/SaveButton";
 import { integrationList } from "shared/common";
+import { provisionResourcesTracks } from "shared/anayltics";
 
 type Props = {
   nextStep: () => void;
@@ -173,7 +174,10 @@ const ConnectExternalCluster: React.FC<Props> = ({
       <NextStep
         text="Continue"
         disabled={!enableContinue}
-        onClick={() => nextStep()}
+        onClick={() => {
+          provisionResourcesTracks.trackExternalClusterConnected();
+          nextStep();
+        }}
         status={
           !enableContinue ? "No connected cluster detected" : "successful"
         }

+ 1 - 0
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/_GCPProvisionerForm.tsx

@@ -335,6 +335,7 @@ export const SettingsForm: React.FC<{
         cluster_name: clusterName,
         registry_infra_id: registryProvisionResponse?.id,
         cluster_infra_id: clusterProvisionResponse?.id,
+        region,
       },
     });
   };

+ 1 - 0
dashboard/src/main/home/onboarding/types.ts

@@ -73,6 +73,7 @@ export type GCPProvisionerConfig = {
     cluster_name: string;
     registry_infra_id: number;
     cluster_infra_id: number;
+    region: string;
   };
 };
 

+ 1 - 0
dashboard/src/shared/anayltics/index.ts

@@ -0,0 +1 @@
+export * from "./onboarding/tracks";

+ 29 - 0
dashboard/src/shared/anayltics/onboarding/events.ts

@@ -0,0 +1,29 @@
+export enum COMMON_TRACKS {
+  REDIRECT_TO_GUIDE = "FE Redirect to guide",
+}
+
+export enum PROJECT_CREATION_TRACKS {
+  NEW_PROJECT_EVENT = "FE Create project",
+}
+
+export enum CONNECT_SOURCE_TRACKS {
+  CONNECT_GITHUB_BUTTON_CLICKED = "FE Connect Github",
+  USE_DOCKER_REGISTRY_CLICKED = "FE Use docker registry",
+  CONTINUE_AFTER_GITHUB_CONNECT = "FE Continue after Github connect",
+  INSTALL_ON_MORE_REPOSITORIES_CLICKED = "FE Install on more repositories",
+}
+
+export enum CONNECT_REGISTRY_TRACKS {
+  SKIP_REGISTRY_CONNECTION = "FE Skip registry connection",
+  INTENT = "FE Connect registry intent",
+  ADD_CREDENTIALS = "FE Connect registry added credentials",
+  CONNECT_REGISTRY_CLICKED = "FE Connect registry clicked",
+}
+
+export enum PROVISION_RESOURCES_TRACKS {
+  PROVISION_INTENT = "FE Provision resources intent",
+  ADD_CREDENTIALS = "FE Provision resources added credentials",
+  PROVISION_RESOURCES_CLICKED = "FE Provision resources clicked",
+  CONNECT_EXTERNAL_CLUSTER_INTENT = "FE Provision resources Connect external cluster intent",
+  CONNECTED_EXTERNAL_CLUSTER = "FE Provision resources Connected external cluster",
+}

+ 88 - 0
dashboard/src/shared/anayltics/onboarding/tracks.ts

@@ -0,0 +1,88 @@
+import type {
+  TrackConnectRegistryClickedProps,
+  TrackConnectRegistryIntentProps,
+  TrackProvisionAddCredentialsProps,
+  TrackProvisionIntentProps,
+  TrackProvisionResourcesClickedProps,
+  TrackRedirectToGuideProps,
+  TrackRegistryAddCredentialsProps,
+} from "./types";
+import {
+  COMMON_TRACKS,
+  CONNECT_REGISTRY_TRACKS,
+  CONNECT_SOURCE_TRACKS,
+  PROJECT_CREATION_TRACKS,
+  PROVISION_RESOURCES_TRACKS,
+} from "./events";
+
+export function trackCreateNewProject() {
+  window.analytics?.track(PROJECT_CREATION_TRACKS.NEW_PROJECT_EVENT);
+}
+
+export function trackRedirectToGuide(props: TrackRedirectToGuideProps) {
+  window.analytics?.track(COMMON_TRACKS.REDIRECT_TO_GUIDE, props);
+}
+
+export const connectSourceTracks = {
+  trackConnectGithubButtonClicked() {
+    window.analytics?.track(
+      CONNECT_SOURCE_TRACKS.CONNECT_GITHUB_BUTTON_CLICKED
+    );
+  },
+  trackUseDockerRegistryClicked() {
+    window.analytics?.track(CONNECT_SOURCE_TRACKS.USE_DOCKER_REGISTRY_CLICKED);
+  },
+  trackContinueAfterGithubConnect() {
+    window.analytics?.track(
+      CONNECT_SOURCE_TRACKS.CONTINUE_AFTER_GITHUB_CONNECT
+    );
+  },
+  trackInstallOnMoreRepositoriesClicked() {
+    window.analytics?.track(
+      CONNECT_SOURCE_TRACKS.INSTALL_ON_MORE_REPOSITORIES_CLICKED
+    );
+  },
+};
+
+export const connectRegistryTracks = {
+  trackSkipRegistryConnection() {
+    window.analytics?.track(CONNECT_REGISTRY_TRACKS.SKIP_REGISTRY_CONNECTION);
+  },
+  trackConnectRegistryIntent(props: TrackConnectRegistryIntentProps) {
+    window.analytics?.track(CONNECT_REGISTRY_TRACKS.INTENT, props);
+  },
+  trackRegistryAddCredentials(props: TrackRegistryAddCredentialsProps) {
+    window.analytics?.track(CONNECT_REGISTRY_TRACKS.ADD_CREDENTIALS, props);
+  },
+  trackConnectRegistryClicked(props: TrackConnectRegistryClickedProps) {
+    window.analytics?.track(
+      CONNECT_REGISTRY_TRACKS.CONNECT_REGISTRY_CLICKED,
+      props
+    );
+  },
+};
+
+export const provisionResourcesTracks = {
+  trackConnectExternalClusterIntent() {
+    window.analytics?.track(
+      PROVISION_RESOURCES_TRACKS.CONNECT_EXTERNAL_CLUSTER_INTENT
+    );
+  },
+  trackExternalClusterConnected() {
+    window.analytics?.track(
+      PROVISION_RESOURCES_TRACKS.CONNECTED_EXTERNAL_CLUSTER
+    );
+  },
+  trackProvisionIntent(props: TrackProvisionIntentProps) {
+    window.analytics?.track(PROVISION_RESOURCES_TRACKS.PROVISION_INTENT, props);
+  },
+  trackProvisionAddCredentials(props: TrackProvisionAddCredentialsProps) {
+    window.analytics?.track(PROVISION_RESOURCES_TRACKS.ADD_CREDENTIALS, props);
+  },
+  trackProvisionResourcesClicked(props: TrackProvisionResourcesClickedProps) {
+    window.analytics?.track(
+      PROVISION_RESOURCES_TRACKS.PROVISION_RESOURCES_CLICKED,
+      props
+    );
+  },
+};

+ 35 - 0
dashboard/src/shared/anayltics/onboarding/types.ts

@@ -0,0 +1,35 @@
+export type TrackRedirectToGuideProps = {
+  step: string;
+  guide_url: string;
+  provider?: string;
+};
+
+export type TrackConnectRegistryIntentProps = {
+  provider: string;
+};
+
+export type TrackRegistryAddCredentialsProps = {
+  step: string;
+  provider: string;
+};
+
+export type TrackConnectRegistryClickedProps = {
+  provider: string;
+};
+
+export type TrackProvisionIntentProps = {
+  provider: string;
+};
+
+export type TrackProvisionAddCredentialsProps = {
+  step: string;
+  provider: string;
+};
+
+export type TrackProvisionResourcesClickedProps = {
+  provider: string;
+  cluster_name: string;
+  machine_type?: string;
+  subscription_tier?: string;
+  region?: string;
+};