Quellcode durchsuchen

Remove embedded dashboard, add more error handling and type checks

Mauricio Araujo vor 2 Jahren
Ursprung
Commit
2332c577fd

+ 0 - 55
api/server/handlers/billing/plan.go

@@ -104,61 +104,6 @@ func (c *ListCreditsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	c.WriteResult(w, r, credits)
 }
 
-// GetUsageDashboardHandler returns an embeddable dashboard to display information related to customer usage.
-type GetUsageDashboardHandler struct {
-	handlers.PorterHandlerReadWriter
-}
-
-// NewGetUsageDashboardHandler returns a new GetUsageDashboardHandler
-func NewGetUsageDashboardHandler(
-	config *config.Config,
-	decoderValidator shared.RequestDecoderValidator,
-	writer shared.ResultWriter,
-) *GetUsageDashboardHandler {
-	return &GetUsageDashboardHandler{
-		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
-	}
-}
-
-func (c *GetUsageDashboardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	ctx, span := telemetry.NewSpan(r.Context(), "serve-usage-dashboard")
-	defer span.End()
-
-	proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
-
-	if !c.Config().BillingManager.MetronomeEnabled || !proj.GetFeatureFlag(models.MetronomeEnabled, c.Config().LaunchDarklyClient) {
-		c.WriteResult(w, r, "")
-
-		telemetry.WithAttributes(span,
-			telemetry.AttributeKV{Key: "metronome-config-exists", Value: c.Config().BillingManager.MetronomeEnabled},
-			telemetry.AttributeKV{Key: "metronome-enabled", Value: proj.GetFeatureFlag(models.MetronomeEnabled, c.Config().LaunchDarklyClient)},
-		)
-		return
-	}
-
-	telemetry.WithAttributes(span,
-		telemetry.AttributeKV{Key: "metronome-enabled", Value: true},
-		telemetry.AttributeKV{Key: "usage-id", Value: proj.UsageID},
-	)
-
-	request := &types.EmbeddableDashboardRequest{}
-
-	if ok := c.DecodeAndValidate(w, r, request); !ok {
-		err := telemetry.Error(ctx, span, nil, "error decoding embeddable usage dashboard request")
-		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
-		return
-	}
-
-	credits, err := c.Config().BillingManager.MetronomeClient.GetCustomerDashboard(ctx, proj.UsageID, request.DashboardType, request.Options, request.ColorOverrides)
-	if err != nil {
-		err := telemetry.Error(ctx, span, err, "error getting customer dashboard")
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-		return
-	}
-
-	c.WriteResult(w, r, credits)
-}
-
 // ListCustomerUsageHandler returns customer usage aggregations like CPU and RAM hours.
 type ListCustomerUsageHandler struct {
 	handlers.PorterHandlerReadWriter

+ 0 - 28
api/server/router/project.go

@@ -397,34 +397,6 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
-	// POST /api/projects/{project_id}/billing/dashboard -> project.NewGetUsageDashboardHandler
-	getUsageDashboardEndpoint := factory.NewAPIEndpoint(
-		&types.APIRequestMetadata{
-			Verb:   types.APIVerbCreate,
-			Method: types.HTTPVerbPost,
-			Path: &types.Path{
-				Parent:       basePath,
-				RelativePath: relPath + "/billing/dashboard",
-			},
-			Scopes: []types.PermissionScope{
-				types.UserScope,
-				types.ProjectScope,
-			},
-		},
-	)
-
-	getUsageDashboardHandler := billing.NewGetUsageDashboardHandler(
-		config,
-		factory.GetDecoderValidator(),
-		factory.GetResultWriter(),
-	)
-
-	routes = append(routes, &router.Route{
-		Endpoint: getUsageDashboardEndpoint,
-		Handler:  getUsageDashboardHandler,
-		Router:   r,
-	})
-
 	// POST /api/projects/{project_id}/billing/usage -> project.NewListCustomerUsageHandler
 	listCustomerUsageEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{

+ 150 - 148
dashboard/src/lib/hooks/useStripe.tsx

@@ -37,7 +37,7 @@ type TSetDefaultPaymentMethod = {
 };
 
 type TCheckHasPaymentEnabled = {
-  hasPaymentEnabled: boolean;
+  hasPaymentEnabled: boolean | null;
   refetchPaymentEnabled: (options: {
     throwOnError: boolean;
     cancelRefetch: boolean;
@@ -45,33 +45,19 @@ type TCheckHasPaymentEnabled = {
 };
 
 type TGetPublishableKey = {
-  publishableKey: string;
-};
-
-type TGetUsageDashboard = {
-  url: string;
+  publishableKey: string | null;
 };
 
 type TGetCredits = {
-  creditGrants: CreditGrants | undefined;
+  creditGrants: CreditGrants | null;
 };
 
 type TGetPlan = {
-  plan: Plan | undefined;
+  plan: Plan | null;
 };
 
 type TGetUsage = {
-  usage: UsageList | undefined;
-};
-
-const embeddableDashboardColors = {
-  grayDark: "Gray_dark",
-  grayMedium: "Gray_medium",
-  grayLight: "Gray_light",
-  grayExtraLigth: "Gray_extralight",
-  white: "White",
-  primaryMedium: "Primary_medium",
-  primaryLight: "Primary_light",
+  usage: UsageList | null;
 };
 
 export const usePaymentMethods = (): TUsePaymentMethod => {
@@ -87,20 +73,28 @@ export const usePaymentMethods = (): TUsePaymentMethod => {
   // Fetch list of payment methods
   const paymentMethodReq = useQuery(
     ["getPaymentMethods", currentProject?.id],
-    async (): Promise<PaymentMethod[]> => {
+    async (): Promise<PaymentMethod[] | null> => {
+      if (!currentProject?.billing_enabled) {
+        return null;
+      }
+
       if (!currentProject?.id || currentProject.id === -1) {
-        return [];
+        return null;
       }
-      const listResponse = await api.listPaymentMethod(
-        "<token>",
-        {},
-        { project_id: currentProject?.id }
-      );
 
-      const data = PaymentMethodValidator.array().parse(listResponse.data);
-      setPaymentMethodList(data);
+      try {
+        const listResponse = await api.listPaymentMethod(
+          "<token>",
+          {},
+          { project_id: currentProject?.id }
+        );
 
-      return data;
+        const data = PaymentMethodValidator.array().parse(listResponse.data);
+        setPaymentMethodList(data);
+        return data;
+      } catch (error) {
+        return null
+      }
     }
   );
 
@@ -146,6 +140,10 @@ export const usePaymentMethods = (): TUsePaymentMethod => {
 export const useCreatePaymentMethod = (): TCreatePaymentMethod => {
   const { currentProject } = useContext(Context);
 
+  if (!currentProject?.billing_enabled) {
+    return { createPaymentMethod: async () => "" };
+  }
+
   const createPaymentMethod = async (): Promise<string> => {
     const resp = await api.addPaymentMethod(
       "<token>",
@@ -163,14 +161,50 @@ export const useCreatePaymentMethod = (): TCreatePaymentMethod => {
   };
 };
 
+export const useSetDefaultPaymentMethod = (): TSetDefaultPaymentMethod => {
+  const { currentProject } = useContext(Context);
+
+  if (!currentProject?.billing_enabled) {
+    return { setDefaultPaymentMethod: async () => { } };
+  }
+
+  const setDefaultPaymentMethod = async (
+    paymentMethodId: string
+  ): Promise<void> => {
+    // Set payment method as default
+    const res = await api.setDefaultPaymentMethod(
+      "<token>",
+      {},
+      { project_id: currentProject?.id, payment_method_id: paymentMethodId }
+    );
+
+    if (res.status !== 200) {
+      throw Error("failed to set payment method as default");
+    }
+  };
+
+  return {
+    setDefaultPaymentMethod,
+  };
+};
+
 export const checkIfProjectHasPayment = (): TCheckHasPaymentEnabled => {
   const { currentProject } = useContext(Context);
 
+
   // Check if payment is enabled for the project
   const paymentEnabledReq = useQuery(
-    currentProject?.id ? ["checkPaymentEnabled", currentProject.id] : ["checkPaymentEnabled", null],
-    currentProject?.id
-      ? async (): Promise<boolean> => {
+    ["checkPaymentEnabled", currentProject?.id],
+    async (): Promise<boolean | null> => {
+      if (!currentProject?.billing_enabled) {
+        return null;
+      }
+
+      if (!currentProject?.id) {
+        return null;
+      }
+
+      try {
         const res = await api.getHasBilling(
           "<token>",
           {},
@@ -179,83 +213,47 @@ export const checkIfProjectHasPayment = (): TCheckHasPaymentEnabled => {
 
         const data = z.boolean().parse(res.data);
         return data;
+      } catch (error) {
+        return null
       }
-      : async () => false
-  );
+    });
 
   return {
-    hasPaymentEnabled: paymentEnabledReq.data ?? false,
+    hasPaymentEnabled: paymentEnabledReq.data ?? null,
     refetchPaymentEnabled: paymentEnabledReq.refetch,
   };
 };
-
-export const useCustomeUsageDashboard = (
-  dashboard: string
-): TGetUsageDashboard => {
-  const { currentProject } = useContext(Context);
-
-  const colorOverrides = [
-    { name: embeddableDashboardColors.grayDark, value: "#121212" },
-    { name: embeddableDashboardColors.grayMedium, value: "#DFDFE1" },
-    { name: embeddableDashboardColors.grayLight, value: "#DFDFE1" },
-    { name: embeddableDashboardColors.grayExtraLigth, value: "#DFDFE1" },
-    { name: embeddableDashboardColors.white, value: "#121212" },
-    { name: embeddableDashboardColors.primaryLight, value: "#121212" },
-    { name: embeddableDashboardColors.primaryMedium, value: "#DFDFE1" },
-  ];
-
-  // Return an embeddable dashboard for the customer
-  const dashboardReq = useQuery(
-    ["getUsageDashboard", currentProject?.id, dashboard],
-    async () => {
-      if (!currentProject?.id || currentProject.id === -1) {
-        return;
-      }
-      const res = await api.getUsageDashboard(
-        "<token>",
-        {
-          dashboard,
-          color_overrides: colorOverrides,
-        },
-        {
-          project_id: currentProject?.id,
-        }
-      );
-      return res.data;
-    },
-    {
-      staleTime: Infinity,
-    }
-  );
-
-  return {
-    url: dashboardReq.data,
-  };
-};
-
 export const usePublishableKey = (): TGetPublishableKey => {
   const { currentProject } = useContext(Context);
 
   // Fetch list of payment methods
   const keyReq = useQuery(
     ["getPublishableKey", currentProject?.id],
-    async () => {
+    async (): Promise<string | null> => {
+      if (!currentProject?.billing_enabled) {
+        return null;
+      }
+
       if (!currentProject?.id || currentProject.id === -1) {
         return null;
       }
-      const res = await api.getPublishableKey(
-        "<token>",
-        {},
-        {
-          project_id: currentProject?.id,
-        }
-      );
-      return res.data;
-    }
-  );
+
+      try {
+        const res = await api.getPublishableKey(
+          "<token>",
+          {},
+          {
+            project_id: currentProject?.id,
+          }
+        );
+        return res.data;
+      } catch (error) {
+        return null
+      }
+    });
 
   return {
-    publishableKey: keyReq.data,
+    publishableKey: keyReq.data ?? null,
   };
 };
 
@@ -265,23 +263,33 @@ export const usePorterCredits = (): TGetCredits => {
   // Fetch available credits
   const creditsReq = useQuery(
     ["getPorterCredits", currentProject?.id],
-    async () => {
+    async (): Promise<CreditGrants | null> => {
+      if (!currentProject?.metronome_enabled) {
+        return null;
+      }
+
       if (!currentProject?.id || currentProject.id === -1) {
-        return;
+        return null;
+      }
+
+      try {
+        const res = await api.getPorterCredits(
+          "<token>",
+          {},
+          {
+            project_id: currentProject?.id,
+          }
+        );
+        const creditGrants = CreditGrantsValidator.parse(res.data);
+        return creditGrants;
+      } catch (error) {
+        return null
       }
-      const res = await api.getPorterCredits(
-        "<token>",
-        {},
-        {
-          project_id: currentProject?.id,
-        }
-      );
-      return CreditGrantsValidator.parse(res.data);
     }
   );
 
   return {
-    creditGrants: creditsReq.data,
+    creditGrants: creditsReq.data ?? null,
   };
 };
 
@@ -290,9 +298,17 @@ export const useCustomerPlan = (): TGetPlan => {
 
   // Fetch current plan
   const planReq = useQuery(
-    currentProject?.id ? ["getCustomerPlan", currentProject.id] : ["getCustomerPlan", null],
-    currentProject?.id
-      ? async (): Promise<PlanType> => {
+    ["getCustomerPlan", currentProject?.id],
+    async (): Promise<Plan | null> => {
+      if (!currentProject?.metronome_enabled) {
+        return null;
+      }
+
+      if (!currentProject?.id) {
+        return null;
+      }
+
+      try {
         const res = await api.getCustomerPlan(
           "<token>",
           {},
@@ -301,12 +317,13 @@ export const useCustomerPlan = (): TGetPlan => {
 
         const plan = PlanValidator.parse(res.data);
         return plan;
+      } catch (error) {
+        return null
       }
-      : async () => null
-  );
+    });
 
   return {
-    plan: planReq.data,
+    plan: planReq.data ?? null,
   };
 };
 
@@ -319,49 +336,34 @@ export const useCustomerUsage = (
   // Fetch customer usage
   const usageReq = useQuery(
     ["listCustomerUsage", currentProject?.id],
-    async () => {
-      if (!currentProject?.id || currentProject.id === -1) {
-        return;
+    async (): Promise<UsageList | null> => {
+      if (!currentProject?.metronome_enabled) {
+        return null;
       }
-      const res = await api.getCustomerUsage(
-        "<token>",
-        {
-          window_size: windowSize,
-          current_period: currentPeriod,
-        },
-        {
-          project_id: currentProject?.id,
-        }
-      );
-      const usage = UsageValidator.array().parse(res.data);
-      return usage;
-    }
-  );
-
-  return {
-    usage: usageReq.data,
-  };
-};
-
-export const useSetDefaultPaymentMethod = (): TSetDefaultPaymentMethod => {
-  const { currentProject } = useContext(Context);
 
-  const setDefaultPaymentMethod = async (
-    paymentMethodId: string
-  ): Promise<void> => {
-    // Set payment method as default
-    const res = await api.setDefaultPaymentMethod(
-      "<token>",
-      {},
-      { project_id: currentProject?.id, payment_method_id: paymentMethodId }
-    );
+      if (!currentProject?.id || currentProject.id === -1) {
+        return null;
+      }
 
-    if (res.status !== 200) {
-      throw Error("failed to set payment method as default");
-    }
-  };
+      try {
+        const res = await api.getCustomerUsage(
+          "<token>",
+          {
+            window_size: windowSize,
+            current_period: currentPeriod,
+          },
+          {
+            project_id: currentProject?.id,
+          }
+        );
+        const usage = UsageValidator.array().parse(res.data);
+        return usage;
+      } catch (error) {
+        return null;
+      }
+    });
 
   return {
-    setDefaultPaymentMethod,
+    usage: usageReq.data ?? null,
   };
 };

+ 2 - 2
dashboard/src/main/home/Home.tsx

@@ -401,9 +401,9 @@ const Home: React.FC<Props> = (props) => {
             !trialExpired
           }
         >
-          {!currentProject?.sandbox_enabled && showCardBanner && plan && (
+          {!currentProject?.sandbox_enabled && showCardBanner && currentProject?.billing_enabled && currentProject?.metronome_enabled && (
             <>
-              {!trialExpired && (
+              {!trialExpired && plan && (
                 <GlobalBanner>
                   <i className="material-icons-round">warning</i>
                   Please

+ 43 - 68
dashboard/src/shared/api.tsx

@@ -386,9 +386,8 @@ const getFeedEvents = baseApi<
   }
 >("GET", (pathParams) => {
   const { project_id, cluster_id, stack_name, page } = pathParams;
-  return `/api/projects/${project_id}/clusters/${cluster_id}/applications/${stack_name}/events?page=${
-    page || 1
-  }`;
+  return `/api/projects/${project_id}/clusters/${cluster_id}/applications/${stack_name}/events?page=${page || 1
+    }`;
 });
 
 const createEnvironment = baseApi<
@@ -876,11 +875,9 @@ const detectBuildpack = baseApi<
     branch: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/gitrepos/${
-    pathParams.git_repo_id
-  }/repos/${pathParams.kind}/${pathParams.owner}/${
-    pathParams.name
-  }/${encodeURIComponent(pathParams.branch)}/buildpack/detect`;
+  return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id
+    }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name
+    }/${encodeURIComponent(pathParams.branch)}/buildpack/detect`;
 });
 
 const detectGitlabBuildpack = baseApi<
@@ -911,11 +908,9 @@ const getBranchContents = baseApi<
     branch: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/gitrepos/${
-    pathParams.git_repo_id
-  }/repos/${pathParams.kind}/${pathParams.owner}/${
-    pathParams.name
-  }/${encodeURIComponent(pathParams.branch)}/contents`;
+  return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id
+    }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name
+    }/${encodeURIComponent(pathParams.branch)}/contents`;
 });
 
 const getProcfileContents = baseApi<
@@ -931,11 +926,9 @@ const getProcfileContents = baseApi<
     branch: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/gitrepos/${
-    pathParams.git_repo_id
-  }/repos/${pathParams.kind}/${pathParams.owner}/${
-    pathParams.name
-  }/${encodeURIComponent(pathParams.branch)}/procfile`;
+  return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id
+    }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name
+    }/${encodeURIComponent(pathParams.branch)}/procfile`;
 });
 
 const getPorterYamlContents = baseApi<
@@ -951,11 +944,9 @@ const getPorterYamlContents = baseApi<
     branch: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/gitrepos/${
-    pathParams.git_repo_id
-  }/repos/${pathParams.kind}/${pathParams.owner}/${
-    pathParams.name
-  }/${encodeURIComponent(pathParams.branch)}/porteryaml`;
+  return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id
+    }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name
+    }/${encodeURIComponent(pathParams.branch)}/porteryaml`;
 });
 
 const parsePorterYaml = baseApi<
@@ -1015,32 +1006,30 @@ const getBranchHead = baseApi<
     branch: string;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/gitrepos/${
-    pathParams.git_repo_id
-  }/repos/${pathParams.kind}/${pathParams.owner}/${
-    pathParams.name
-  }/${encodeURIComponent(pathParams.branch)}/head`;
+  return `/api/projects/${pathParams.project_id}/gitrepos/${pathParams.git_repo_id
+    }/repos/${pathParams.kind}/${pathParams.owner}/${pathParams.name
+    }/${encodeURIComponent(pathParams.branch)}/head`;
 });
 
 const createApp = baseApi<
   | {
-      name: string;
-      deployment_target_id: string;
-      type: "github";
-      git_repo_id: number;
-      git_branch: string;
-      git_repo_name: string;
-      porter_yaml_path: string;
-    }
+    name: string;
+    deployment_target_id: string;
+    type: "github";
+    git_repo_id: number;
+    git_branch: string;
+    git_repo_name: string;
+    porter_yaml_path: string;
+  }
   | {
-      name: string;
-      deployment_target_id: string;
-      type: "docker-registry";
-      image: {
-        repository: string;
-        tag: string;
-      };
-    },
+    name: string;
+    deployment_target_id: string;
+    type: "docker-registry";
+    image: {
+      repository: string;
+      tag: string;
+    };
+  },
   {
     project_id: number;
     cluster_id: number;
@@ -2266,11 +2255,9 @@ const getEnvGroup = baseApi<
     version?: number;
   }
 >("GET", (pathParams) => {
-  return `/api/projects/${pathParams.id}/clusters/${
-    pathParams.cluster_id
-  }/namespaces/${pathParams.namespace}/envgroup?name=${pathParams.name}${
-    pathParams.version ? "&version=" + pathParams.version : ""
-  }`;
+  return `/api/projects/${pathParams.id}/clusters/${pathParams.cluster_id
+    }/namespaces/${pathParams.namespace}/envgroup?name=${pathParams.name}${pathParams.version ? "&version=" + pathParams.version : ""
+    }`;
 });
 
 const getConfigMap = baseApi<
@@ -3476,17 +3463,6 @@ const getCustomerUsage = baseApi<
   }
 >("POST", ({ project_id }) => `/api/projects/${project_id}/billing/usage`);
 
-const getUsageDashboard = baseApi<
-  {
-    dashboard: string;
-    dashboard_options?: Array<{ key: string; value: string }>;
-    color_overrides?: Array<{ name: string; value: string }>;
-  },
-  {
-    project_id?: number;
-  }
->("POST", ({ project_id }) => `/api/projects/${project_id}/billing/dashboard`);
-
 const getCustomerPlan = baseApi<
   {},
   {
@@ -3550,7 +3526,7 @@ const deletePaymentMethod = baseApi<
     `/api/projects/${project_id}/billing/payment_method/${payment_method_id}`
 );
 
-const getGithubStatus = baseApi<{}, {}>("GET", ({}) => `/api/status/github`);
+const getGithubStatus = baseApi<{}, {}>("GET", ({ }) => `/api/status/github`);
 
 const createSecretAndOpenGitHubPullRequest = baseApi<
   {
@@ -3628,12 +3604,12 @@ const updateAppEventWebhooks = baseApi<
 });
 
 const systemStatusHistory = baseApi<
-{},
-{
-  projectId: number; clusterId: number;
-}>("GET", (pathParams) => {
-  return `/api/projects/${pathParams.projectId}/clusters/${pathParams.clusterId}/system-status-history`;
-});
+  {},
+  {
+    projectId: number; clusterId: number;
+  }>("GET", (pathParams) => {
+    return `/api/projects/${pathParams.projectId}/clusters/${pathParams.clusterId}/system-status-history`;
+  });
 
 // Bundle export to allow default api import (api.<method> is more readable)
 export default {
@@ -3929,7 +3905,6 @@ export default {
   getPorterCredits,
   getCustomerPlan,
   getCustomerUsage,
-  getUsageDashboard,
   listPaymentMethod,
   addPaymentMethod,
   setDefaultPaymentMethod,

+ 0 - 30
internal/billing/metronome.go

@@ -228,36 +228,6 @@ func (m MetronomeClient) ListCustomerCredits(ctx context.Context, customerID uui
 	return response, nil
 }
 
-// GetCustomerDashboard will return an embeddable Metronome dashboard
-func (m MetronomeClient) GetCustomerDashboard(ctx context.Context, customerID uuid.UUID, dashboardType string, options []types.DashboardOption, colorOverrides []types.ColorOverride) (url string, err error) {
-	ctx, span := telemetry.NewSpan(ctx, "get-customer-usage-dashboard")
-	defer span.End()
-
-	if customerID == uuid.Nil {
-		return url, telemetry.Error(ctx, span, err, "customer id empty")
-	}
-
-	path := "dashboards/getEmbeddableUrl"
-
-	req := types.EmbeddableDashboardRequest{
-		CustomerID:     customerID,
-		Options:        options,
-		DashboardType:  dashboardType,
-		ColorOverrides: colorOverrides,
-	}
-
-	var result struct {
-		Data map[string]string `json:"data"`
-	}
-
-	_, err = m.do(http.MethodPost, path, req, &result)
-	if err != nil {
-		return url, telemetry.Error(ctx, span, err, "failed to get embeddable dashboard")
-	}
-
-	return result.Data["url"], nil
-}
-
 // ListCustomerUsage will return the aggregated usage for a customer
 func (m MetronomeClient) ListCustomerUsage(ctx context.Context, customerID uuid.UUID, startingOn string, endingBefore string, windowsSize string, currentPeriod bool) (usage []types.Usage, err error) {
 	ctx, span := telemetry.NewSpan(ctx, "list-customer-usage")