Soham Dessai 3 лет назад
Родитель
Сommit
5bb2a7e73e

+ 6 - 1
dashboard/src/components/repo-selector/BuildpackStack.tsx

@@ -53,6 +53,7 @@ export const BuildpackStack: React.FC<{
   hide: boolean;
   hide: boolean;
   onChange: (config: BuildConfig) => void;
   onChange: (config: BuildConfig) => void;
   currentBuildConfig?: BuildConfig;
   currentBuildConfig?: BuildConfig;
+  setBuildConfig?: (config: BuildConfig) => void;
 }> = ({
 }> = ({
   actionConfig,
   actionConfig,
   folderPath,
   folderPath,
@@ -60,6 +61,7 @@ export const BuildpackStack: React.FC<{
   hide,
   hide,
   onChange,
   onChange,
   currentBuildConfig,
   currentBuildConfig,
+  setBuildConfig,
 }) => {
 }) => {
   const { currentProject } = useContext(Context);
   const { currentProject } = useContext(Context);
 
 
@@ -76,7 +78,6 @@ export const BuildpackStack: React.FC<{
     []
     []
   );
   );
   const renderModalContent = () => {
   const renderModalContent = () => {
-    console.log(selectedBuildpacks);
     return (
     return (
       <>
       <>
         <Text size={16}>Buildpack Configuration</Text>
         <Text size={16}>Buildpack Configuration</Text>
@@ -118,6 +119,10 @@ export const BuildpackStack: React.FC<{
 
 
     if (typeof onChange === "function") {
     if (typeof onChange === "function") {
       onChange(buildConfig);
       onChange(buildConfig);
+
+      if (currentBuildConfig) {
+        setBuildConfig(buildConfig);
+      }
     }
     }
   }, [selectedStack, selectedBuildpacks]);
   }, [selectedStack, selectedBuildpacks]);
 
 

+ 3 - 1
dashboard/src/components/repo-selector/DetectContentsList.tsx

@@ -224,7 +224,9 @@ const DetectContentsList: React.FC<PropsType> = (props) => {
   };
   };
   return (
   return (
     <>
     <>
-      {renderContentList() && props.dockerfilePath != "" ? (
+      {renderContentList() &&
+      props.dockerfilePath != "" &&
+      props.dockerfilePath != null ? (
         <AdvancedBuildSettings
         <AdvancedBuildSettings
           dockerfilePath={props.dockerfilePath}
           dockerfilePath={props.dockerfilePath}
           setDockerfilePath={props.setDockerfilePath}
           setDockerfilePath={props.setDockerfilePath}

+ 189 - 27
dashboard/src/main/home/app-dashboard/expanded-app/BuildSettingsTabStack.tsx

@@ -1,5 +1,13 @@
 import AnimateHeight from "react-animate-height";
 import AnimateHeight from "react-animate-height";
-import React, { Component, Dispatch, useMemo, useRef, useState } from "react";
+import React, {
+  Component,
+  Dispatch,
+  useContext,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import Text from "components/porter/Text";
 import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import Spacer from "components/porter/Spacer";
 import Input from "components/porter/Input";
 import Input from "components/porter/Input";
@@ -24,12 +32,21 @@ import Loading from "components/Loading";
 import { BuildpackSelection } from "components/repo-selector/BuildpackSelection";
 import { BuildpackSelection } from "components/repo-selector/BuildpackSelection";
 import BuildpackConfigSection from "main/home/cluster-dashboard/expanded-chart/build-settings/_BuildpackConfigSection";
 import BuildpackConfigSection from "main/home/cluster-dashboard/expanded-chart/build-settings/_BuildpackConfigSection";
 import { BuildpackStack } from "components/repo-selector/BuildpackStack";
 import { BuildpackStack } from "components/repo-selector/BuildpackStack";
+import MultiSaveButton from "components/MultiSaveButton";
+import api from "shared/api";
+import { AxiosError } from "axios";
 type Props = {
 type Props = {
   appData: any;
   appData: any;
   setAppData: Dispatch<any>;
   setAppData: Dispatch<any>;
+  onTabSwitch: () => void;
 };
 };
 
 
-const BuildSettingsTabStack: React.FC<Props> = ({ appData, setAppData }) => {
+const BuildSettingsTabStack: React.FC<Props> = ({
+  appData,
+  setAppData,
+  onTabSwitch,
+}) => {
+  const { setCurrentError } = useContext(Context);
   const [updated, setUpdated] = useState(null);
   const [updated, setUpdated] = useState(null);
   const [branch, setBranch] = useState(appData.app.git_branch);
   const [branch, setBranch] = useState(appData.app.git_branch);
   const [showSettings, setShowSettings] = useState(false);
   const [showSettings, setShowSettings] = useState(false);
@@ -52,28 +69,161 @@ const BuildSettingsTabStack: React.FC<Props> = ({ appData, setAppData }) => {
   const [buildConfig, setBuildConfig] = useState<BuildConfig>({
   const [buildConfig, setBuildConfig] = useState<BuildConfig>({
     ...defaultBuildConfig,
     ...defaultBuildConfig,
   });
   });
+  const [runningWorkflowURL, setRunningWorkflowURL] = useState("");
+
   const [actionConfig, setActionConfig] = useState<ActionConfigType>({
   const [actionConfig, setActionConfig] = useState<ActionConfigType>({
     ...defaultActionConfig,
     ...defaultActionConfig,
   });
   });
+  const [buttonStatus, setButtonStatus] = useState<
+    "loading" | "successful" | string
+  >("");
 
 
   const [imageUrl, setImageUrl] = useState(appData.chart.image_uri);
   const [imageUrl, setImageUrl] = useState(appData.chart.image_uri);
 
 
-  const buildpackConfigRef = useRef<{
-    isLoading: boolean;
-    getBuildConfig: () => BuildConfig;
-  }>(null);
+  const clearButtonStatus = (time: number = 800) => {
+    setTimeout(() => {
+      setButtonStatus("");
+    }, time);
+  };
+  const triggerWorkflow = async () => {
+    try {
+      await api.reRunGHWorkflow(
+        "",
+        {},
+        {
+          project_id: appData.app.project_id,
+          cluster_id: appData.app.cluster_id,
+          git_installation_id: appData.app.git_repo_id,
+          owner: appData.app.repo_name?.split("/")[0],
+          name: appData.app.repo_name?.split("/")[1],
+          branch: branch,
+          release_name: "stack_" + appData.chart.name,
+        }
+      );
+    } catch (error) {
+      if (!error?.response) {
+        throw error;
+      }
+
+      let tmpError: AxiosError = error;
+
+      /**
+       * @smell
+       * Currently the expanded chart is clearing all the state when a chart update is triggered (saveEnvVariables).
+       * Temporary usage of setCurrentError until a context is applied to keep the state of the ReRunError during re renders.
+       */
+
+      if (tmpError.response.status === 400) {
+        // setReRunError({
+        //   title: "No previous run found",
+        //   description:
+        //     "There are no previous runs for this workflow, please trigger manually a run before changing the build settings.",
+        // });
+        setCurrentError(
+          "There are no previous runs for this workflow. Please manually trigger a run before changing build settings."
+        );
+        return;
+      }
+
+      if (tmpError.response.status === 409) {
+        // setReRunError({
+        //   title: "The workflow is still running",
+        //   description:
+        //     'If you want to make more changes, please choose the option "Save" until the workflow finishes.',
+        // });
 
 
-  const currentActionConfig = useMemo(() => {
-    console.log(appData.chart.config);
+        if (typeof tmpError.response.data === "string") {
+          setRunningWorkflowURL(tmpError.response.data);
+        }
+        setCurrentError(
+          'The workflow is still running. You can "Save" the current build settings for the next workflow run and view the current status of the workflow here: ' +
+            tmpError.response.data
+        );
+        return;
+      }
+
+      if (tmpError.response.status === 404) {
+        let description = "No action file matching this deployment was found.";
+        if (typeof tmpError.response.data === "string") {
+          const filename = tmpError.response.data;
+          description = description.concat(
+            `Please check that the file "${filename}" exists in your repository.`
+          );
+        }
+        // setReRunError({
+        //   title: "The action doesn't seem to exist",
+        //   description,
+        // });
+
+        setCurrentError(description);
+        return;
+      }
+      throw error;
+    }
+  };
+  const saveConfig = async () => {
     console.log(appData);
     console.log(appData);
-    const actionConf = appData.chart.config;
+    try {
+      await api.updatePorterApp(
+        "<token>",
+        {
+          repo_name: appData.app.repo_name,
+          git_branch: branch,
+          build_context: appData.app.build_context,
+          builder: buildConfig.builder,
+          buildpacks: buildConfig.buildpacks?.join(","),
+          dockerfile: appData.app.dockerfile,
+          image_repo_uri: appData.chart.image_repo_uri,
+        },
+        {
+          project_id: appData.app.project_id,
+          cluster_id: appData.app.cluster_id,
+          name: appData.app.name,
+        }
+      );
+      onTabSwitch();
+    } catch (err) {
+      throw err;
+    }
+  };
+  const handleSave = async () => {
+    setButtonStatus("loading");
+
+    try {
+      console.log(buildConfig.builder);
 
 
-    return {
-      kind: "github",
-      ...actionConf,
-    } as FullActionConfigType;
-  }, [appData.chart]);
+      await saveConfig();
+      setAppData(appData);
 
 
+      onTabSwitch();
+      setButtonStatus("successful");
+    } catch (error) {
+      setButtonStatus("Something went wrong");
+      console.log(error);
+    } finally {
+      clearButtonStatus();
+    }
+  };
+  const handleSaveAndReDeploy = async () => {
+    setButtonStatus("loading");
+
+    try {
+      console.log(buildConfig.builder);
+
+      await saveConfig();
+      setAppData(appData);
+
+      await triggerWorkflow();
+
+      onTabSwitch();
+      setButtonStatus("successful");
+    } catch (error) {
+      setButtonStatus("Something went wrong");
+      console.log(error);
+    } finally {
+      clearButtonStatus();
+    }
+  };
   return (
   return (
     <>
     <>
       <Text size={16}>Build settings</Text>
       <Text size={16}>Build settings</Text>
@@ -145,10 +295,35 @@ const BuildSettingsTabStack: React.FC<Props> = ({ appData, setAppData }) => {
               }}
               }}
               hide={!showSettings}
               hide={!showSettings}
               currentBuildConfig={buildConfig}
               currentBuildConfig={buildConfig}
+              setBuildConfig={setBuildConfig}
             />
             />
           )}
           )}
         </StyledSourceBox>
         </StyledSourceBox>
       </AnimateHeight>
       </AnimateHeight>
+
+      <MultiSaveButton
+        options={[
+          {
+            text: "Save",
+            onClick: handleSave,
+            description:
+              "Save the build settings to be used in the next workflow run",
+          },
+          {
+            text: "Save and Redeploy",
+            onClick: handleSaveAndReDeploy,
+            description:
+              "Immediately trigger a workflow run with updated build settings",
+          },
+        ]}
+        disabled={false}
+        makeFlush={true}
+        clearPosition={true}
+        statusPosition="left"
+        expandTo="left"
+        saveText=""
+        status={buttonStatus}
+      ></MultiSaveButton>
     </>
     </>
   );
   );
 };
 };
@@ -162,19 +337,6 @@ const DarkMatter = styled.div<{ antiHeight?: string }>`
   margin-top: ${(props) => props.antiHeight || "-15px"};
   margin-top: ${(props) => props.antiHeight || "-15px"};
 `;
 `;
 
 
-const Subtitle = styled.div`
-  padding: 11px 0px 16px;
-  font-family: "Work Sans", sans-serif;
-  font-size: 13px;
-  color: #aaaabb;
-  line-height: 1.6em;
-`;
-
-const Required = styled.div`
-  margin-left: 8px;
-  color: #fc4976;
-  display: inline-block;
-`;
 const AdvancedBuildTitle = styled.div`
 const AdvancedBuildTitle = styled.div`
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;

+ 6 - 2
dashboard/src/main/home/app-dashboard/expanded-app/ExpandedApp.tsx

@@ -294,7 +294,11 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
         return <div>TODO: service list</div>;
         return <div>TODO: service list</div>;
       case "build-settings":
       case "build-settings":
         return (
         return (
-          <BuildSettingsTabStack appData={appData} setAppData={setAppData} />
+          <BuildSettingsTabStack
+            appData={appData}
+            setAppData={setAppData}
+            onTabSwitch={getPorterApp}
+          />
         );
         );
       case "settings":
       case "settings":
         return (
         return (
@@ -404,7 +408,7 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
           <Spacer y={1} />
           <Spacer y={1} />
           <TabSelector
           <TabSelector
             options={
             options={
-              appData.app.build_packs
+              appData.app.git_repo_id
                 ? [
                 ? [
                     { label: "Events", value: "events" },
                     { label: "Events", value: "events" },
                     { label: "Logs", value: "logs" },
                     { label: "Logs", value: "logs" },

+ 0 - 1
dashboard/src/main/home/app-dashboard/new-app-flow/AdvancedBuildSettings.tsx

@@ -66,7 +66,6 @@ const AdvancedBuildSettings: React.FC<AdvancedBuildSettingsProps> = (props) => {
         <BuildpackStack
         <BuildpackStack
           actionConfig={props.actionConfig}
           actionConfig={props.actionConfig}
           branch={props.branch}
           branch={props.branch}
-          defaultBuildConfig={props.buildConfig}
           folderPath={props.folderPath}
           folderPath={props.folderPath}
           onChange={(config) => {
           onChange={(config) => {
             props.setBuildConfig(config);
             props.setBuildConfig(config);