Ver Fonte

POR-1584 add env and build tabs (#3460)

ianedwards há 2 anos atrás
pai
commit
ac9daab81d

+ 48 - 2
dashboard/src/main/home/app-dashboard/app-view/AppDataContainer.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from "react";
+import React, { useEffect, useMemo, useState } from "react";
 import { FormProvider, useForm } from "react-hook-form";
 import {
   PorterAppFormData,
@@ -18,6 +18,8 @@ import { useAppValidation } from "lib/hooks/useAppValidation";
 import api from "shared/api";
 import { useQueryClient } from "@tanstack/react-query";
 import Settings from "./tabs/Settings";
+import BuildSettings from "./tabs/BuildSettings";
+import Environment from "./tabs/Environment";
 
 // commented out tabs are not yet implemented
 // will be included as support is available based on data from app revisions rather than helm releases
@@ -44,6 +46,8 @@ type AppDataContainerProps = {
 const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
   const history = useHistory();
   const queryClient = useQueryClient();
+  const [redeployOnSave, setRedeployOnSave] = useState(false);
+
   const {
     porterApp,
     latestProto,
@@ -94,7 +98,11 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
       source: latestSource,
     },
   });
-  const { reset, handleSubmit } = porterAppFormMethods;
+  const {
+    reset,
+    handleSubmit,
+    formState: { dirtyFields },
+  } = porterAppFormMethods;
 
   const onSubmit = handleSubmit(async (data) => {
     try {
@@ -111,6 +119,28 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
         }
       );
 
+      if (
+        redeployOnSave &&
+        latestSource.type === "github" &&
+        dirtyFields.app?.build
+      ) {
+        await api.reRunGHWorkflow(
+          "<token>",
+          {},
+          {
+            project_id: projectId,
+            cluster_id: clusterId,
+            git_installation_id: latestSource.git_repo_id,
+            owner: latestSource.git_repo_name.split("/")[0],
+            name: latestSource.git_repo_name.split("/")[1],
+            branch: porterApp.git_branch,
+            filename: "porter_stack_" + porterApp.name + ".yml",
+          }
+        );
+
+        setRedeployOnSave(false);
+      }
+
       await queryClient.invalidateQueries([
         "getLatestRevision",
         projectId,
@@ -146,6 +176,15 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
           noBuffer
           options={[
             { label: "Overview", value: "overview" },
+            { label: "Environment", value: "environment" },
+            ...(latestProto.build
+              ? [
+                  {
+                    label: "Build Settings",
+                    value: "build-settings",
+                  },
+                ]
+              : []),
             { label: "Settings", value: "settings" },
           ]}
           currentTab={currentTab}
@@ -156,6 +195,13 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
         <Spacer y={1} />
         {match(currentTab)
           .with("overview", () => <Overview />)
+          .with("build-settings", () => (
+            <BuildSettings
+              redeployOnSave={redeployOnSave}
+              setRedeployOnSave={setRedeployOnSave}
+            />
+          ))
+          .with("environment", () => <Environment />)
           .with("settings", () => <Settings />)
           .otherwise(() => null)}
         <Spacer y={2} />

+ 69 - 0
dashboard/src/main/home/app-dashboard/app-view/tabs/BuildSettings.tsx

@@ -0,0 +1,69 @@
+import React, { Dispatch, SetStateAction, useMemo } from "react";
+import RepoSettings from "../../create-app/RepoSettings";
+import { useFormContext } from "react-hook-form";
+import { PorterAppFormData } from "lib/porter-apps";
+import { useLatestRevision } from "../LatestRevisionContext";
+import Spacer from "components/porter/Spacer";
+import Checkbox from "components/porter/Checkbox";
+import Text from "components/porter/Text";
+import Button from "components/porter/Button";
+import Error from "components/porter/Error";
+
+type Props = {
+  redeployOnSave: boolean;
+  setRedeployOnSave: Dispatch<SetStateAction<boolean>>;
+};
+
+const BuildSettings: React.FC<Props> = ({
+  redeployOnSave,
+  setRedeployOnSave,
+}) => {
+  const {
+    watch,
+    formState: { isSubmitting, errors },
+  } = useFormContext<PorterAppFormData>();
+  const { projectId } = useLatestRevision();
+
+  const build = watch("app.build");
+  const source = watch("source");
+
+  const buttonStatus = useMemo(() => {
+    if (isSubmitting) {
+      return "loading";
+    }
+
+    if (Object.keys(errors).length > 0) {
+      return <Error message="Unable to update app" />;
+    }
+
+    return "";
+  }, [isSubmitting, errors]);
+
+  if (source.type !== "github") {
+    return null;
+  }
+
+  return (
+    <>
+      <RepoSettings
+        build={build}
+        source={source}
+        projectId={projectId}
+        appExists
+      />
+      <Spacer y={1} />
+      <Checkbox
+        checked={redeployOnSave}
+        toggleChecked={() => setRedeployOnSave(!redeployOnSave)}
+      >
+        <Text>Re-run build and deploy on save</Text>
+      </Checkbox>
+      <Spacer y={1} />
+      <Button type="submit" status={buttonStatus}>
+        Save build settings
+      </Button>
+    </>
+  );
+};
+
+export default BuildSettings;

+ 41 - 0
dashboard/src/main/home/app-dashboard/app-view/tabs/Environment.tsx

@@ -0,0 +1,41 @@
+import Spacer from "components/porter/Spacer";
+import Text from "components/porter/Text";
+import React, { useMemo } from "react";
+import EnvVariables from "../../validate-apply/app-settings/EnvVariables";
+import Button from "components/porter/Button";
+import Error from "components/porter/Error";
+import { useFormContext } from "react-hook-form";
+import { PorterAppFormData } from "lib/porter-apps";
+
+const Environment: React.FC = () => {
+  const {
+    formState: { isSubmitting, errors },
+  } = useFormContext<PorterAppFormData>();
+
+  const buttonStatus = useMemo(() => {
+    if (isSubmitting) {
+      return "loading";
+    }
+
+    if (Object.keys(errors).length > 0) {
+      return <Error message="Unable to update app" />;
+    }
+
+    return "";
+  }, [isSubmitting, errors]);
+
+  return (
+    <>
+      <Text size={16}>Environment variables</Text>
+      <Spacer y={0.5} />
+      <Text color="helper">Shared among all services.</Text>
+      <EnvVariables />
+      <Spacer y={0.5} />
+      <Button type="submit" status={buttonStatus} loadingText={"Updating..."}>
+        Update app
+      </Button>
+    </>
+  );
+};
+
+export default Environment;

+ 53 - 47
dashboard/src/main/home/app-dashboard/create-app/RepoSettings.tsx

@@ -18,11 +18,13 @@ import {
 import RepositorySelector from "../build-settings/RepositorySelector";
 import BranchSelector from "../build-settings/BranchSelector";
 import BuildpackSettings from "../validate-apply/build-settings/buildpacks/BuildpackSettings";
+import { match } from "ts-pattern";
 
 type Props = {
   projectId: number;
   source: SourceOptions & { type: "github" };
   build: BuildOptions;
+  appExists?: boolean;
 };
 
 const branchContentsSchema = z
@@ -35,15 +37,14 @@ const branchContentsSchema = z
 type BranchContents = z.infer<typeof branchContentsSchema>;
 type BuildView = "docker" | "pack";
 
-const RepoSettings: React.FC<Props> = ({ projectId, source, build }) => {
-  const {
-    watch,
-    control,
-    register,
-    setValue,
-  } = useFormContext<PorterAppFormData>();
+const RepoSettings: React.FC<Props> = ({
+  projectId,
+  source,
+  build,
+  appExists,
+}) => {
+  const { control, register, setValue } = useFormContext<PorterAppFormData>();
   const [showSettings, setShowSettings] = useState<boolean>(false);
-  const method = watch("app.build.method");
 
   const repoIsSet = useMemo(() => source.git_repo_name !== "", [
     source.git_repo_name,
@@ -129,23 +130,25 @@ const RepoSettings: React.FC<Props> = ({ projectId, source, build }) => {
             setValue={() => {}}
             placeholder=""
           />
-          <BackButton
-            width="135px"
-            onClick={() => {
-              setValue("source", {
-                type: "github",
-                git_repo_name: "",
-                git_branch: "",
-                git_repo_id: 0,
-                porter_yaml_path: "./porter.yaml",
-              });
+          {!appExists && (
+            <BackButton
+              width="135px"
+              onClick={() => {
+                setValue("source", {
+                  type: "github",
+                  git_repo_name: "",
+                  git_branch: "",
+                  git_repo_id: 0,
+                  porter_yaml_path: "./porter.yaml",
+                });
 
-              setValue("app.build.context", "./");
-            }}
-          >
-            <i className="material-icons">keyboard_backspace</i>
-            Select repo
-          </BackButton>
+                setValue("app.build.context", "./");
+              }}
+            >
+              <i className="material-icons">keyboard_backspace</i>
+              Select repo
+            </BackButton>
+          )}
           <Spacer y={0.5} />
           <Spacer y={0.5} />
           <Text color="helper">Specify your GitHub branch.</Text>
@@ -208,7 +211,7 @@ const RepoSettings: React.FC<Props> = ({ projectId, source, build }) => {
                   setShowSettings(!showSettings);
                 }}
               >
-                {method == "docker" ? (
+                {build.method == "docker" ? (
                   <AdvancedBuildTitle>
                     <i className="material-icons dropdown">arrow_drop_down</i>
                     Configure Dockerfile settings
@@ -224,7 +227,7 @@ const RepoSettings: React.FC<Props> = ({ projectId, source, build }) => {
               <AnimateHeight height={showSettings ? "auto" : 0} duration={1000}>
                 <StyledSourceBox>
                   <Select
-                    value={method}
+                    value={build.method}
                     width="300px"
                     options={[
                       { value: "docker", label: "Docker" },
@@ -235,28 +238,31 @@ const RepoSettings: React.FC<Props> = ({ projectId, source, build }) => {
                     }
                     label="Build method"
                   />
-                  {method === "docker" ? (
-                    <>
-                      <Spacer y={0.5} />
-                      <Text color="helper">
-                        Dockerfile path (absolute path)
-                      </Text>
-                      <Spacer y={0.5} />
-                      <ControlledInput
-                        width="300px"
-                        placeholder="ex: ./Dockerfile"
-                        type="text"
-                        {...register("app.build.dockerfile")}
+                  {match(build)
+                    .with({ method: "docker" }, () => (
+                      <>
+                        <Spacer y={0.5} />
+                        <Text color="helper">
+                          Dockerfile path (absolute path)
+                        </Text>
+                        <Spacer y={0.5} />
+                        <ControlledInput
+                          width="300px"
+                          placeholder="ex: ./Dockerfile"
+                          type="text"
+                          {...register("app.build.dockerfile")}
+                        />
+                        <Spacer y={0.5} />
+                      </>
+                    ))
+                    .with({ method: "pack" }, (b) => (
+                      <BuildpackSettings
+                        projectId={projectId}
+                        build={b}
+                        source={source}
                       />
-                      <Spacer y={0.5} />
-                    </>
-                  ) : (
-                    <BuildpackSettings
-                      projectId={projectId}
-                      build={build}
-                      source={source}
-                    />
-                  )}
+                    ))
+                    .exhaustive()}
                 </StyledSourceBox>
               </AnimateHeight>
             </>