瀏覽代碼

banner w/o casing on workflow yet

Justin Rhee 3 年之前
父節點
當前提交
9ed09f8881
共有 18 個文件被更改,包括 228 次插入137 次删除
  1. 二進制
      dashboard/src/assets/refresh.png
  2. 20 2
      dashboard/src/components/porter/Banner.tsx
  3. 2 2
      dashboard/src/components/porter/Link.tsx
  4. 32 54
      dashboard/src/main/home/app-dashboard/expanded-app/ExpandedApp.tsx
  5. 99 36
      dashboard/src/main/home/app-dashboard/expanded-app/GHABanner.tsx
  6. 63 31
      dashboard/src/main/home/app-dashboard/new-app-flow/GithubActionModal.tsx
  7. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/NotificationSettingsSection.tsx
  8. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/build-settings/BuildSettingsTab.tsx
  9. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/LogsSection.tsx
  10. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/components/PreviewEnvironmentsHeader.tsx
  11. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentDetail.tsx
  12. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentList.tsx
  13. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/CreateBranchEnvironment.tsx
  14. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/CreatePREnvironment.tsx
  15. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentSettings.tsx
  16. 1 1
      dashboard/src/main/home/dashboard/ClusterSection.tsx
  17. 1 1
      dashboard/src/main/home/dashboard/Dashboard.tsx
  18. 1 1
      dashboard/src/main/home/modals/UsageWarningModal.tsx

二進制
dashboard/src/assets/refresh.png


+ 20 - 2
dashboard/src/components/Banner.tsx → dashboard/src/components/porter/Banner.tsx

@@ -9,9 +9,16 @@ interface Props {
   icon?: React.ReactNode;
   children: React.ReactNode;
   noMargin?: boolean;
+  suffix?: React.ReactNode;
 }
 
-const Banner: React.FC<Props> = ({ type, icon, children, noMargin }) => {
+const Banner: React.FC<Props> = ({ 
+  type,
+  icon,
+  children,
+  noMargin,
+  suffix,
+}) => {
   const renderIcon = () => {
     if (icon) {
       return icon;
@@ -28,14 +35,24 @@ const Banner: React.FC<Props> = ({ type, icon, children, noMargin }) => {
       color={type === "error" ? "#ff385d" : type === "warning" && "#f5cb42"}
       noMargin={noMargin}
     >
+      <>
       {renderIcon()}
       <span>{children}</span>
+      </>
+      {suffix && (
+        <Suffix>{suffix}</Suffix>
+      )}
     </StyledBanner>
   );
 };
 
 export default Banner;
 
+const Suffix = styled.div`
+  margin-left: auto;
+  padding-left: 10px;
+`;
+
 const StyledBanner = styled.div<{
   color?: string;
   noMargin?: boolean;
@@ -52,7 +69,8 @@ const StyledBanner = styled.div<{
   padding: 10px 14px;
   color: ${(props) => props.color || "#ffffff"};
   align-items: center;
-  background: #ffffff11;
+  jusrify-content: space-between;
+  background: ${({ theme }) => theme.fg};
   > img {
     margin-right: 10px;
     width: 20px;

+ 2 - 2
dashboard/src/components/porter/Link.tsx

@@ -42,14 +42,14 @@ const Link: React.FC<Props> = ({
 export default Link;
 
 const Div = styled.span<{ underline?: boolean }>`
-  color: #8590ff;
+  color: #ffffff;
   cursor: pointer;
   display: inline;
   text-decoration: ${props => props.underline ? "underline" : ""};
 `;
 
 const StyledLink = styled(DynamicLink)<{ underline?: boolean }>`
-  color: #8590ff;
+  color: #ffffff;
   display: inline;
   cursor: pointer;
   text-decoration: ${props => props.underline ? "underline" : ""};

+ 32 - 54
dashboard/src/main/home/app-dashboard/expanded-app/ExpandedApp.tsx

@@ -31,11 +31,12 @@ import Services from "../new-app-flow/Services";
 import { Service } from "../new-app-flow/serviceTypes";
 import ConfirmOverlay from "components/porter/ConfirmOverlay";
 import Fieldset from "components/porter/Fieldset";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import AppEvents from "./AppEvents";
 import { createFinalPorterYaml } from "../new-app-flow/schema";
 import EnvGroupArray, { KeyValueType } from "main/home/cluster-dashboard/env-groups/EnvGroupArray";
 import { PorterYamlSchema } from "../new-app-flow/schema";
+import GHABanner from "./GHABanner";
 
 type Props = RouteComponentProps & {};
 
@@ -55,6 +56,8 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
   const [isLoading, setIsLoading] = useState(true);
   const [deleting, setDeleting] = useState(false);
   const [appData, setAppData] = useState(null);
+  const [workflowCheckPassed, setWorkflowCheckPassed] = useState<boolean>(false);
+
   const [error, setError] = useState(null);
   const [forceRefreshRevisions, setForceRefreshRevisions] = useState<boolean>(
     false
@@ -399,7 +402,7 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
               setServices={setServices}
               services={services}
             />
-            <Spacer y={0.5} />
+            <Spacer y={1} />
             <Button
               onClick={() => {
                 updatePorterApp();
@@ -408,11 +411,10 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
                 <Error message={updateError} />
               ) : undefined}
               loadingText={"Updating..."}
-              width={"150px"}
             >
               Update app
             </Button>
-            <Spacer y={0.5} />
+            <Spacer y={3} />
           </>
         )
       case "build-settings":
@@ -556,34 +558,14 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
             </Fieldset>
           ) : (
             <>
-              {true ? (
-                <>
-                  {appData.app.pull_request_url ? (
-                    <Banner type="warning">
-                      Your application will not be available until you merge
-                      <Spacer inline width="5px" />
-                      <Link
-                        to={appData.app.pull_request_url}
-                        underline
-                      >
-                        this PR
-                      </Link>
-                      <Spacer inline width="5px" />
-                      into your <Mono>{appData.app.git_branch}</Mono> branch.
-                    </Banner>
-                  ) : (
-                    <Banner type="warning">
-                      Your application will not be available until you add the Porter GitHub Action to your <Mono>{appData.app.git_branch}</Mono> branch.
-                      <Spacer inline width="5px" />
-                      <Link
-                        to={appData.app.pull_request_url}
-                        underline
-                      >
-                        See details
-                      </Link>
-                    </Banner>
-                  )}
-                </>
+              {!workflowCheckPassed ? (
+                <GHABanner
+                  repoName={appData.app.repo_name}
+                  branchName={appData.app.git_branch}
+                  pullRequestUrl={appData.app.pull_request_url}
+                  stackName={appData.app.name}
+                  gitRepoId={appData.app.git_repo_id}
+                />
               ) : (
                 <>
                   <DarkMatter />
@@ -611,22 +593,24 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
               <Spacer y={1} />
               <TabSelector
                 options={
-                  appData.app.git_repo_id
-                    ? [
-                      { label: "Events", value: "events" },
-                      { label: "Logs", value: "logs" },
-                      { label: "Metrics", value: "metrics" },
-                      { label: "Overview", value: "overview" },
-                      { label: "Build settings", value: "build-settings" },
-                      { label: "Settings", value: "settings" },
-                    ]
-                    : [
-                      { label: "Events", value: "events" },
-                      { label: "Logs", value: "logs" },
-                      { label: "Metrics", value: "metrics" },
-                      { label: "Overview", value: "overview" },
-                      { label: "Settings", value: "settings" },
-                    ]
+                  appData.app.git_repo_id ? (workflowCheckPassed ? [
+                    { label: "Events", value: "events" },
+                    { label: "Logs", value: "logs" },
+                    { label: "Metrics", value: "metrics" },
+                    { label: "Overview", value: "overview" },
+                    { label: "Build settings", value: "build-settings" },
+                    { label: "Settings", value: "settings" },
+                  ] : [
+                    { label: "Overview", value: "overview" },
+                    { label: "Build settings", value: "build-settings" },
+                    { label: "Settings", value: "settings" },
+                  ]) : [
+                    { label: "Events", value: "events" },
+                    { label: "Logs", value: "logs" },
+                    { label: "Metrics", value: "metrics" },
+                    { label: "Overview", value: "overview" },
+                    { label: "Settings", value: "settings" },
+                  ]
                 }
                 currentTab={tab}
                 setCurrentTab={setTab}
@@ -654,12 +638,6 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
 
 export default withRouter(ExpandedApp);
 
-const Mono = styled.span`
-  font-family: monospace;
-  display: inline;
-  margin: 0 3px 0;
-`;
-
 const Spinner = styled.img`
   width: 15px;
   height: 15px;

+ 99 - 36
dashboard/src/main/home/app-dashboard/expanded-app/GHABanner.tsx

@@ -1,57 +1,120 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useState, useContext } from "react";
 import styled from "styled-components";
 
+import refresh from "assets/refresh.png";
+
+import { Context } from "shared/Context";
+
+import Banner from "components/porter/Banner";
+import Spacer from "components/porter/Spacer";
+import Link from "components/porter/Link";
+import GithubActionModal from "../new-app-flow/GithubActionModal";
+import Container from "components/porter/Container";
+
+
 type Props = {
-  pull_request_url: string;
+  pullRequestUrl: string;
   branchName: string;
   repoName: string;
+  stackName: string;
+  gitRepoId: number;
 };
 
 const GHABanner: React.FC<Props> = ({
-  pull_request_url,
+  pullRequestUrl,
   branchName,
   repoName,
+  stackName,
+  gitRepoId,
 }) => {
-  const [isExpanded, setIsExpanded] = useState(false);
-
-  useEffect(() => {
-    // Do something
-  }, []);
-
+  const { currentProject, currentCluster } = useContext(Context);
+  const [showGHAModal, setShowGHAModal] = useState(false);
   return (
-    <StyledGHABanner>
-      <>
-        {appData.app.pull_request_url ? (
-          <Banner type="warning">
-            Your application will not be available until you merge
-            <Spacer inline width="5px" />
-            <Link
-              to={appData.app.pull_request_url}
-              underline
+    <>
+      <StyledGHABanner>
+        <>
+          {pullRequestUrl ? (
+            <Banner 
+              type="warning"
+              suffix={
+                <RefreshButton onClick={() => window.location.reload()}>
+                  <img src={refresh} /> Refresh
+                </RefreshButton>
+              }
             >
-              this PR
-            </Link>
-            <Spacer inline width="5px" />
-            into your <Mono>{appData.app.git_branch}</Mono> branch.
-          </Banner>
-        ) : (
-          <Banner type="warning">
-            Your application will not be available until you add the Porter GitHub Action to your <Mono>{appData.app.git_branch}</Mono> branch.
-            <Spacer inline width="5px" />
-            <Link
-              to={appData.app.pull_request_url}
-              underline
+              <Container row spaced>
+                Your application will not be available until you merge
+                <Spacer inline width="5px" />
+                <Link
+                  to={pullRequestUrl}
+                  underline
+                >
+                  this PR
+                </Link>
+                <Spacer inline width="5px" />
+                into your branch.
+              </Container>
+            </Banner>
+          ) : (
+            <Banner   
+              type="warning"
+              suffix={
+                <RefreshButton onClick={() => window.location.reload()}>
+                  <img src={refresh} /> Refresh
+                </RefreshButton>
+              }
             >
-              See details
-            </Link>
-          </Banner>
-        )}
-      </>
-    </StyledGHABanner>
+              Your application will not be available until you add the Porter workflow to your branch.
+              <Spacer inline width="5px" />
+              <Link
+                onClick={() => setShowGHAModal(true)}
+                underline
+              >
+                See details
+              </Link>
+            </Banner>
+          )}
+        </>
+      </StyledGHABanner>
+      {showGHAModal && (
+        <GithubActionModal
+          closeModal={() => setShowGHAModal(false)}
+          githubAppInstallationID={gitRepoId}
+          githubRepoOwner={repoName.split("/")[0]}
+          githubRepoName={repoName.split("/")[1]}
+          branch={branchName}
+          stackName={stackName}
+          projectId={currentProject.id}
+          clusterId={currentCluster.id}
+        />
+      )}
+    </>
   );
 };
 
 export default GHABanner;
 
 const StyledGHABanner = styled.div`
+`;
+
+const RefreshButton = styled.div`
+  color: #ffffff44;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  :hover {
+    color: #ffffff;
+    > img {
+      opacity: 1;
+    }
+  }
+
+  > img {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 11px;
+    margin-right: 10px;
+    opacity: 0.3;
+  }
 `;

+ 63 - 31
dashboard/src/main/home/app-dashboard/new-app-flow/GithubActionModal.tsx

@@ -14,6 +14,8 @@ import { getGithubAction } from "./utils";
 import AceEditor from "react-ace";
 import YamlEditor from "components/YamlEditor";
 import Error from "components/porter/Error";
+import Container from "components/porter/Container";
+import Checkbox from "components/porter/Checkbox";
 
 
 type Props = RouteComponentProps & {
@@ -25,7 +27,7 @@ type Props = RouteComponentProps & {
   stackName?: string;
   projectId?: number;
   clusterId?: number;
-  deployPorterApp: () => Promise<boolean>;
+  deployPorterApp?: () => Promise<boolean>;
   deploymentError?: string;
 }
 
@@ -46,14 +48,17 @@ const GithubActionModal: React.FC<Props> = ({
 }) => {
   const [choice, setChoice] = React.useState<Choice>("open_pr");
   const [loading, setLoading] = React.useState<boolean>(false);
+  const [isChecked, setIsChecked] = React.useState<boolean>(false);
 
   const submit = async () => {
     if (githubAppInstallationID && githubRepoOwner && githubRepoName && branch && stackName) {
       try {
         setLoading(true)
         // this creates the dummy chart
-
-        const success = await deployPorterApp();
+        var success = true;
+        if (deployPorterApp) {
+          success = await deployPorterApp();
+        }
 
         if (success) {
           // this creates the secret and possibly the PR
@@ -64,7 +69,7 @@ const GithubActionModal: React.FC<Props> = ({
               github_repo_owner: githubRepoOwner,
               github_repo_name: githubRepoName,
               branch,
-              open_pr: choice === "open_pr",
+              open_pr: (choice === "open_pr" || isChecked),
             },
             {
               project_id: projectId,
@@ -85,6 +90,9 @@ const GithubActionModal: React.FC<Props> = ({
               }
             )
             window.open(res.data.url, "_blank", "noreferrer");
+            if (!deployPorterApp) {
+              window.location.reload();
+            }
           }
           props.history.push(`/apps/${stackName}`);
         }
@@ -106,7 +114,7 @@ const GithubActionModal: React.FC<Props> = ({
       <Text color="helper">
         In order to automatically update your services every time new code is pushed to your GitHub branch, the following file must exist in your GitHub repository:
       </Text>
-      <Spacer y={1} />
+      <Spacer y={0.5} />
       <ExpandableSection
         noWrapper
         expandText="[+] Show code"
@@ -130,26 +138,51 @@ const GithubActionModal: React.FC<Props> = ({
         Porter can open a PR for you to approve and merge this file into your repository, or you can add it yourself. If you allow Porter to open a PR, you will be redirected to the PR in a new tab after submitting below.
       </Text>
       <Spacer y={1} />
-      <Select
-        options={[
-          { label: "I authorize Porter to open a PR on my behalf (recommended)", value: "open_pr" },
-          { label: "I will copy the file into my repository myself", value: "copy" },
-        ]}
-        setValue={(x: string) => setChoice(x as Choice)}
-        width="100%"
-      />
-      <StyledButton>
-        <Button
-          onClick={submit}
-          width={"150px"}
-          loadingText={"Submitting..."}
-          status={loading ? "loading" : deploymentError ? (
-            <Error message={deploymentError} />
-          ) : undefined}
-        >
-          Deploy app
-        </Button>
-      </StyledButton>
+      {deployPorterApp ? (
+        <>
+          <Select
+            options={[
+              { label: "I authorize Porter to open a PR on my behalf (recommended)", value: "open_pr" },
+              { label: "I will copy the file into my repository myself", value: "copy" },
+            ]}
+            setValue={(x: string) => setChoice(x as Choice)}
+            width="100%"
+          />
+          <Spacer y={1} />
+          <Button
+            onClick={submit}
+            width={"110px"}
+            loadingText={"Submitting..."}
+            status={loading ? "loading" : deploymentError ? (
+              <Error message={deploymentError} />
+            ) : undefined}
+          >
+            Deploy app
+          </Button>
+        </>
+      ) : (
+        <>
+          <Checkbox
+            checked={isChecked}
+            toggleChecked={() => setIsChecked(!isChecked)}
+          >
+            <Text>
+              I authorize Porter to open a PR on my behalf
+            </Text>
+          </Checkbox>
+          <Spacer y={1} />
+          <Button
+            disabled={!isChecked}
+            onClick={submit}
+            loadingText={"Submitting..."}
+            status={loading ? "loading" : deploymentError ? (
+              <Error message={deploymentError} />
+            ) : undefined}
+          >
+            Open a PR for me
+          </Button>
+        </>
+      )}
     </Modal>
   )
 }
@@ -164,9 +197,8 @@ const Tab = styled.span`
 const ModalHeader = styled.div`
   font-weight: 600;
   font-size: 1.5vw;
-  font-family: monospace; ;
-`;
-
-const StyledButton = styled.div`
-  margin-top: 10px;
-`;
+  font-family: monospace;
+  height: 40px;
+  display: flex;
+  align-items: center;
+`;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/NotificationSettingsSection.tsx

@@ -7,7 +7,7 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import { ChartType } from "shared/types";
 import Loading from "components/Loading";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import styled from "styled-components";
 
 const NOTIF_CATEGORIES = ["success", "fail"];

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/build-settings/BuildSettingsTab.tsx

@@ -15,7 +15,7 @@ import styled from "styled-components";
 import yaml from "js-yaml";
 import { AxiosError } from "axios";
 import BranchList from "components/repo-selector/BranchList";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import { UpdateBuildconfigResponse } from "./types";
 import BuildpackConfigSection from "./_BuildpackConfigSection";
 import InputRow from "components/form-components/InputRow";

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/logs-section/LogsSection.tsx

@@ -20,7 +20,7 @@ import dayjs from "dayjs";
 import Loading from "components/Loading";
 import _ from "lodash";
 import { ChartType } from "shared/types";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 
 export type InitLogData = Partial<{
   podName: string;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/components/PreviewEnvironmentsHeader.tsx

@@ -3,7 +3,7 @@ import styled from "styled-components";
 import DashboardHeader from "../../DashboardHeader";
 import PullRequestIcon from "assets/pull_request_icon.svg";
 import api from "shared/api";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import Spacer from "components/porter/Spacer";
 
 export const PreviewEnvironmentsHeader = () => {

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentDetail.tsx

@@ -13,7 +13,7 @@ import ChartList from "../../chart/ChartList";
 import github from "assets/github-white.png";
 import { integrationList } from "shared/common";
 import { capitalize } from "shared/string_utils";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import Modal from "main/home/modals/Modal";
 import { validatePorterYAML } from "../utils";
 import Placeholder from "components/Placeholder";

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentList.tsx

@@ -13,7 +13,7 @@ import DynamicLink from "components/DynamicLink";
 import DashboardHeader from "../../DashboardHeader";
 import RadioFilter from "components/RadioFilter";
 import Placeholder from "components/Placeholder";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 
 import pullRequestIcon from "assets/pull_request_icon.svg";
 import filterOutline from "assets/filter-outline.svg";

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/CreateBranchEnvironment.tsx

@@ -6,7 +6,7 @@ import Helper from "components/form-components/Helper";
 import api from "shared/api";
 import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
 import { validatePorterYAML } from "../utils";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import { useRouting } from "shared/routing";
 import PorterYAMLErrorsModal from "../components/PorterYAMLErrorsModal";
 import Placeholder from "components/Placeholder";

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/CreatePREnvironment.tsx

@@ -8,7 +8,7 @@ import api from "shared/api";
 import { EllipsisTextWrapper } from "../components/styled";
 import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
 import { getPRDeploymentList, validatePorterYAML } from "../utils";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import { useRouting } from "shared/routing";
 import PorterYAMLErrorsModal from "../components/PorterYAMLErrorsModal";
 import Placeholder from "components/Placeholder";

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentSettings.tsx

@@ -14,7 +14,7 @@ import SaveButton from "components/SaveButton";
 import _ from "lodash";
 import { Context } from "shared/Context";
 import PageNotFound from "components/PageNotFound";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import InputRow from "components/form-components/InputRow";
 import Modal from "main/home/modals/Modal";
 import { useRouting } from "shared/routing";

+ 1 - 1
dashboard/src/main/home/dashboard/ClusterSection.tsx

@@ -3,7 +3,7 @@ import styled from "styled-components";
 
 import { Context } from "shared/Context";
 
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 
 import ProvisionerFlow from "components/ProvisionerFlow";
 import ClusterList from "./ClusterList";

+ 1 - 1
dashboard/src/main/home/dashboard/Dashboard.tsx

@@ -17,7 +17,7 @@ import FormDebugger from "components/porter-form/FormDebugger";
 import TitleSection from "components/TitleSection";
 import ClusterSection from "./ClusterSection";
 import { StatusPage } from "../onboarding/steps/ProvisionResources/forms/StatusPage";
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 import Spacer from "components/porter/Spacer";
 
 type Props = RouteComponentProps & WithAuthProps & {

+ 1 - 1
dashboard/src/main/home/modals/UsageWarningModal.tsx

@@ -1,7 +1,7 @@
 import React, { useContext, useEffect, useState } from "react";
 import styled from "styled-components";
 
-import Banner from "components/Banner";
+import Banner from "components/porter/Banner";
 
 import { Context } from "shared/Context";
 import { Usage, UsageData } from "shared/types";