Bläddra i källkod

Standardize app save button across app dashboard (#4125)

Feroze Mohideen 2 år sedan
förälder
incheckning
acca2fb319

+ 6 - 12
dashboard/src/main/home/app-dashboard/app-view/AppDataContainer.tsx

@@ -18,9 +18,7 @@ import { match } from "ts-pattern";
 import { z } from "zod";
 
 import Banner from "components/porter/Banner";
-import Button from "components/porter/Button";
 import { Error as ErrorComponent } from "components/porter/Error";
-import Icon from "components/porter/Icon";
 import Link from "components/porter/Link";
 import Spacer from "components/porter/Spacer";
 import Tag from "components/porter/Tag";
@@ -42,8 +40,8 @@ import {
 import api from "shared/api";
 import { Context } from "shared/Context";
 import alert from "assets/alert-warning.svg";
-import save from "assets/save-01.svg";
 
+import AppSaveButton from "./AppSaveButton";
 import ConfirmRedeployModal from "./ConfirmRedeployModal";
 import { GithubErrorBanner } from "./GithubErrorBanner";
 import { useLatestRevision } from "./LatestRevisionContext";
@@ -594,19 +592,15 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
             type="warning"
             suffix={
               <>
-                <Button
-                  type="submit"
-                  loadingText={"Updating..."}
+                <AppSaveButton
                   height={"10px"}
                   status={isSubmitting ? "loading" : ""}
-                  disabled={isSubmitting || latestRevision.status === "CREATED"}
+                  isDisabled={
+                    isSubmitting || latestRevision.status === "CREATED"
+                  }
                   disabledTooltipMessage="Please wait for the deploy to complete before updating the app"
                   disabledTooltipPosition="bottom"
-                >
-                  <Icon src={save} height={"13px"} />
-                  <Spacer inline x={0.5} />
-                  Save as latest version
-                </Button>
+                />
               </>
             }
           >

+ 42 - 0
dashboard/src/main/home/app-dashboard/app-view/AppSaveButton.tsx

@@ -0,0 +1,42 @@
+import React from "react";
+
+import Button from "components/porter/Button";
+import Icon from "components/porter/Icon";
+import Spacer from "components/porter/Spacer";
+
+import save from "assets/save-01.svg";
+
+import { type ButtonStatus } from "./AppDataContainer";
+
+type Props = {
+  status: ButtonStatus;
+  isDisabled: boolean;
+  disabledTooltipMessage: string;
+  height?: string;
+  disabledTooltipPosition?: "top" | "bottom" | "left" | "right";
+};
+const AppSaveButton: React.FC<Props> = ({
+  status,
+  isDisabled,
+  disabledTooltipMessage,
+  height,
+  disabledTooltipPosition,
+}) => {
+  return (
+    <Button
+      type="submit"
+      status={status}
+      loadingText={"Saving..."}
+      disabled={isDisabled}
+      disabledTooltipMessage={disabledTooltipMessage}
+      height={height}
+      disabledTooltipPosition={disabledTooltipPosition}
+    >
+      <Icon src={save} height={"13px"} />
+      <Spacer inline x={0.5} />
+      Save
+    </Button>
+  );
+};
+
+export default AppSaveButton;

+ 13 - 18
dashboard/src/main/home/app-dashboard/app-view/tabs/BuildSettingsTab.tsx

@@ -1,13 +1,14 @@
-import React, { useMemo } from "react";
-import RepoSettings from "../../create-app/RepoSettings";
+import React from "react";
 import { useFormContext } from "react-hook-form";
-import { PorterAppFormData } from "lib/porter-apps";
-import { useLatestRevision } from "../LatestRevisionContext";
-import Spacer from "components/porter/Spacer";
-import Button from "components/porter/Button";
-import Error from "components/porter/Error";
 import { match } from "ts-pattern";
-import { ButtonStatus } from "../AppDataContainer";
+
+import Spacer from "components/porter/Spacer";
+import { type PorterAppFormData } from "lib/porter-apps";
+
+import RepoSettings from "../../create-app/RepoSettings";
+import { type ButtonStatus } from "../AppDataContainer";
+import AppSaveButton from "../AppSaveButton";
+import { useLatestRevision } from "../LatestRevisionContext";
 
 type Props = {
   buttonStatus: ButtonStatus;
@@ -16,7 +17,7 @@ type Props = {
 const BuildSettingsTab: React.FC<Props> = ({ buttonStatus }) => {
   const {
     watch,
-    formState: { isSubmitting, errors },
+    formState: { isSubmitting },
   } = useFormContext<PorterAppFormData>();
   const { projectId, latestRevision } = useLatestRevision();
 
@@ -35,17 +36,11 @@ const BuildSettingsTab: React.FC<Props> = ({ buttonStatus }) => {
               appExists
             />
             <Spacer y={1} />
-            <Button
-              type="submit"
+            <AppSaveButton
               status={buttonStatus}
-              disabled={
-                isSubmitting ||
-                latestRevision.status === "CREATED"
-              }
+              isDisabled={isSubmitting || latestRevision.status === "CREATED"}
               disabledTooltipMessage="Please wait for the build to complete before updating build settings"
-            >
-              Save build settings
-            </Button>
+            />
           </>
         ))
         .otherwise(() => null)}

+ 4 - 8
dashboard/src/main/home/app-dashboard/app-view/tabs/Environment.tsx

@@ -3,7 +3,6 @@ import { useQuery } from "@tanstack/react-query";
 import { useFormContext } from "react-hook-form";
 import { z } from "zod";
 
-import Button from "components/porter/Button";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { type PorterAppFormData, type SourceOptions } from "lib/porter-apps";
@@ -13,6 +12,7 @@ import api from "shared/api";
 import EnvSettings from "../../validate-apply/app-settings/EnvSettings";
 import { populatedEnvGroup } from "../../validate-apply/app-settings/types";
 import { type ButtonStatus } from "../AppDataContainer";
+import AppSaveButton from "../AppSaveButton";
 import { useLatestRevision } from "../LatestRevisionContext";
 
 type Props = {
@@ -71,15 +71,11 @@ const Environment: React.FC<Props> = ({ latestSource, buttonStatus }) => {
         attachedEnvGroups={attachedEnvGroups}
       />
       <Spacer y={0.5} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        loadingText={"Updating..."}
-        disabled={isSubmitting || latestRevision.status === "CREATED"}
+        isDisabled={isSubmitting || latestRevision.status === "CREATED"}
         disabledTooltipMessage="Please wait for the deploy to complete before updating environment variables"
-      >
-        Update app
-      </Button>
+      />
     </>
   );
 };

+ 26 - 22
dashboard/src/main/home/app-dashboard/app-view/tabs/HelmEditorTab.tsx

@@ -1,24 +1,28 @@
 import React from "react";
-import { useLatestRevision } from "../LatestRevisionContext";
-import HelmOverrides from "../../validate-apply/helm/HelmOverrides";
-import { useFormContext } from "react-hook-form";
-import { PorterAppFormData } from "../../../../../lib/porter-apps";
-import Button from "../../../../../components/porter/Button";
-import { ButtonStatus } from "../AppDataContainer";
 import yaml from "js-yaml";
-import Text from "../../../../../components/porter/Text";
-import Spacer from "../../../../../components/porter/Spacer";
+import { useFormContext } from "react-hook-form";
+
+import Spacer from "components/porter/Spacer";
+import Text from "components/porter/Text";
+import { type PorterAppFormData } from "lib/porter-apps";
+
+import HelmOverrides from "../../validate-apply/helm/HelmOverrides";
+import { type ButtonStatus } from "../AppDataContainer";
+import AppSaveButton from "../AppSaveButton";
+import { useLatestRevision } from "../LatestRevisionContext";
 
 type Props = {
   buttonStatus: ButtonStatus;
   featureFlagEnabled: boolean;
 };
 
-const HelmEditorTab: React.FC<Props> = ({ buttonStatus, featureFlagEnabled }) => {
+const HelmEditorTab: React.FC<Props> = ({
+  buttonStatus,
+  featureFlagEnabled,
+}) => {
   const {
     watch,
-    formState: { isSubmitting, errors },
-    setValue,
+    formState: { isSubmitting },
   } = useFormContext<PorterAppFormData>();
 
   const overrides = watch("app.helmOverrides");
@@ -37,34 +41,34 @@ const HelmEditorTab: React.FC<Props> = ({ buttonStatus, featureFlagEnabled }) =>
 
   return (
     <>
-      {!featureFlagEnabled && <Text color="helper">This tab is only visible to Porter operators. Enable the feature flag to allow customers to view this.</Text>}
+      {!featureFlagEnabled && (
+        <Text color="helper">
+          This tab is only visible to Porter operators. Enable the feature flag
+          to allow customers to view this.
+        </Text>
+      )}
       <HelmOverrides
         projectId={projectId}
         clusterId={clusterId}
         appName={appName}
         deploymentTargetId={deploymentTarget.id}
         appId={porterApp.id}
-        overrideValues={overrides ? yaml.dump(JSON.parse( overrides)) : ""}
+        overrideValues={overrides ? yaml.dump(JSON.parse(overrides)) : ""}
         setError={setError}
       />
       {error !== "" && <Text color="helper">{error}</Text>}
       <Spacer y={1} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        disabled={
-          isSubmitting ||
-          latestRevision.status === "CREATED" ||
-          error !== ""
+        isDisabled={
+          isSubmitting || latestRevision.status === "CREATED" || error !== ""
         }
         disabledTooltipMessage={
           error !== ""
             ? "Error parsing yaml"
             : "Please wait for the new values to apply to complete before updating helm overrides again"
         }
-      >
-        Save Helm overrides
-      </Button>
+      />
     </>
   );
 };

+ 88 - 66
dashboard/src/main/home/app-dashboard/app-view/tabs/ImageSettingsTab.tsx

@@ -1,72 +1,94 @@
-import React, { useMemo } from "react";
+import React from "react";
 import { useFormContext } from "react-hook-form";
-import { PorterAppFormData } from "lib/porter-apps";
-import { useLatestRevision } from "../LatestRevisionContext";
-import Spacer from "components/porter/Spacer";
-import Button from "components/porter/Button";
 import styled from "styled-components";
-import copy from "assets/copy-left.svg"
+import { match } from "ts-pattern";
+
 import CopyToClipboard from "components/CopyToClipboard";
 import Link from "components/porter/Link";
+import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
+import { type PorterAppFormData } from "lib/porter-apps";
+
+import copy from "assets/copy-left.svg";
+
 import ImageSettings from "../../image-settings/ImageSettings";
-import { match } from "ts-pattern";
-import { ButtonStatus } from "../AppDataContainer";
+import { type ButtonStatus } from "../AppDataContainer";
+import AppSaveButton from "../AppSaveButton";
+import { useLatestRevision } from "../LatestRevisionContext";
 
 type Props = {
-    buttonStatus: ButtonStatus;
-}
+  buttonStatus: ButtonStatus;
+};
 
 const ImageSettingsTab: React.FC<Props> = ({ buttonStatus }) => {
-    const {
-        watch,
-        formState: { isSubmitting },
-        setValue,
-    } = useFormContext<PorterAppFormData>();
-    const { projectId, latestRevision, latestProto } = useLatestRevision();
+  const {
+    watch,
+    formState: { isSubmitting },
+    setValue,
+  } = useFormContext<PorterAppFormData>();
+  const { projectId, latestRevision, latestProto } = useLatestRevision();
 
-    const source = watch("source");
+  const source = watch("source");
 
-    return match(source)
-        .with({ type: "docker-registry" }, (source) => (
-            <ImageSettingsTabContainer>
-                <ImageSettings
-                    projectId={projectId}
-                    imageUri={source.image?.repository ?? ""}
-                    setImageUri={(uri: string) => setValue("source.image", { ...(source?.image ?? {}), repository: uri })}
-                    imageTag={source.image?.tag ?? ""}
-                    setImageTag={(tag: string) => setValue("source.image", { ...(source?.image ?? {}), tag })}
-                    resetImageInfo={() => setValue("source.image", { repository: "", tag: "" })}
-                />
-                <Spacer y={1} />
-                <Button
-                    type="submit"
-                    status={buttonStatus}
-                    disabled={
-                        isSubmitting
-                        || latestRevision.status === "CREATED"
-                        || !source.image?.repository
-                        || !source.image?.tag
-                    }
-                >
-                    Save image settings
-                </Button>
-                <Spacer y={1} />
-                <Text size={16}>Update command</Text>
-                <Spacer y={0.5} />
-                <Text color="helper">If you have the <Link to="https://docs.porter.run/standard/cli/command-reference/porter-update" target="_blank"><Text>Porter CLI</Text></Link> installed, you can update your application image tag by running the following command: </Text>
-                <Spacer y={0.5} />
-                <IdContainer>
-                    <Code>{`$ porter app update-tag ${latestProto.name} --tag latest`}</Code>
-                    <CopyContainer>
-                        <CopyToClipboard text={`porter app update-tag ${latestProto.name} --tag latest`}>
-                            <CopyIcon src={copy} alt="copy" />
-                        </CopyToClipboard>
-                    </CopyContainer>
-                </IdContainer>
-            </ImageSettingsTabContainer>
-        ))
-        .otherwise(() => null);
+  return match(source)
+    .with({ type: "docker-registry" }, (source) => (
+      <ImageSettingsTabContainer>
+        <ImageSettings
+          projectId={projectId}
+          imageUri={source.image?.repository ?? ""}
+          setImageUri={(uri: string) => {
+            setValue("source.image", {
+              ...(source?.image ?? {}),
+              repository: uri,
+            });
+          }}
+          imageTag={source.image?.tag ?? ""}
+          setImageTag={(tag: string) => {
+            setValue("source.image", { ...(source?.image ?? {}), tag });
+          }}
+          resetImageInfo={() => {
+            setValue("source.image", { repository: "", tag: "" });
+          }}
+        />
+        <Spacer y={1} />
+        <AppSaveButton
+          status={buttonStatus}
+          isDisabled={
+            isSubmitting ||
+            latestRevision.status === "CREATED" ||
+            !source.image?.repository ||
+            !source.image?.tag
+          }
+          disabledTooltipMessage="Please wait for the deploy to complete before updating image settings"
+        />
+        <Spacer y={1} />
+        <Text size={16}>Update command</Text>
+        <Spacer y={0.5} />
+        <Text color="helper">
+          If you have the{" "}
+          <Link
+            to="https://docs.porter.run/standard/cli/command-reference/porter-update"
+            target="_blank"
+          >
+            <Text>Porter CLI</Text>
+          </Link>{" "}
+          installed, you can update your application image tag by running the
+          following command:{" "}
+        </Text>
+        <Spacer y={0.5} />
+        <IdContainer>
+          <Code>{`$ porter app update-tag ${latestProto.name} --tag latest`}</Code>
+          <CopyContainer>
+            <CopyToClipboard
+              text={`porter app update-tag ${latestProto.name} --tag latest`}
+            >
+              <CopyIcon src={copy} alt="copy" />
+            </CopyToClipboard>
+          </CopyContainer>
+        </IdContainer>
+      </ImageSettingsTabContainer>
+    ))
+    .otherwise(() => null);
 };
 
 export default ImageSettingsTab;
@@ -80,14 +102,14 @@ const ImageSettingsTabContainer = styled.div`
 `;
 
 const IdContainer = styled.div`
-    background: #000000;  
-    border-radius: 5px;
-    padding: 10px;
-    display: flex;
-    width: 100%;
-    border-radius: 5px;
-    border: 1px solid ${({ theme }) => theme.border};
-    align-items: center;
+  background: #000000;
+  border-radius: 5px;
+  padding: 10px;
+  display: flex;
+  width: 100%;
+  border-radius: 5px;
+  border: 1px solid ${({ theme }) => theme.border};
+  align-items: center;
 `;
 
 const CopyContainer = styled.div`
@@ -105,4 +127,4 @@ const CopyIcon = styled.img`
   :hover {
     opacity: 0.8;
   }
-`;
+`;

+ 6 - 8
dashboard/src/main/home/app-dashboard/app-view/tabs/Overview.tsx

@@ -1,7 +1,6 @@
 import React from "react";
 import { useFormContext } from "react-hook-form";
 
-import Button from "components/porter/Button";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { useAppStatus } from "lib/hooks/useAppStatus";
@@ -17,6 +16,7 @@ import { useClusterResources } from "shared/ClusterResourcesContext";
 
 import ServiceList from "../../validate-apply/services-settings/ServiceList";
 import { type ButtonStatus } from "../AppDataContainer";
+import AppSaveButton from "../AppSaveButton";
 import { useLatestRevision } from "../LatestRevisionContext";
 
 type Props = {
@@ -84,15 +84,13 @@ const Overview: React.FC<Props> = ({ buttonStatus }) => {
         }}
       />
       <Spacer y={0.75} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        loadingText={"Updating..."}
-        disabled={formState.isSubmitting || latestRevision.status === "CREATED"}
+        isDisabled={
+          formState.isSubmitting || latestRevision.status === "CREATED"
+        }
         disabledTooltipMessage="Please wait for the deploy to complete before updating services"
-      >
-        Update app
-      </Button>
+      />
     </>
   );
 };