Ver Fonte

autodetecting services

Feroze Mohideen há 3 anos atrás
pai
commit
6f4ff99906

+ 4 - 7
dashboard/src/components/repo-selector/DetectContentsList.tsx

@@ -48,13 +48,11 @@ const DetectContentsList: React.FC<PropsType> = (props) => {
   const [showingBuildContextPrompt, setShowingBuildContextPrompt] = useState(
     "buildpacks"
   );
-  const [porterYaml, setPorterYaml] = useState("");
-
   const context = useContext(Context);
   const fetchAndSetPorterYaml = useCallback(async (fileName: string) => {
     try {
       const response = await fetchPorterYamlContent(fileName);
-      setPorterYaml(atob(response.data));
+      props.setPorterYaml(atob(response.data));
     } catch (error) {
       console.error("Error fetching porter.yaml content:", error);
     }
@@ -67,9 +65,8 @@ const DetectContentsList: React.FC<PropsType> = (props) => {
 
     if (porterYamlItem) {
       fetchAndSetPorterYaml("porter.yaml");
-    } else {
-      setPorterYaml("");
     }
+
   }, [contents, fetchAndSetPorterYaml]);
 
   useEffect(() => {
@@ -460,7 +457,7 @@ const Item = styled.div`
   font-size: 13px;
   border-bottom: 1px solid
     ${(props: { lastItem: boolean; isSelected?: boolean }) =>
-      props.lastItem ? "#00000000" : "#606166"};
+    props.lastItem ? "#00000000" : "#606166"};
   color: #ffffff;
   user-select: none;
   align-items: center;
@@ -491,7 +488,7 @@ const FileItem = styled(Item)`
     props.isADocker ? "#fff" : "#ffffff55"};
   :hover {
     background: ${(props: { isADocker?: boolean }) =>
-      props.isADocker ? "#ffffff22" : "#ffffff11"};
+    props.isADocker ? "#ffffff22" : "#ffffff11"};
   }
 `;
 

+ 57 - 2
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -1,6 +1,7 @@
 import React, { useEffect, useState, useContext, useMemo } from "react";
 import styled from "styled-components";
 import _ from "lodash";
+import yaml from "js-yaml";
 
 import { hardcodedNames, hardcodedIcons } from "shared/hardcodedNameDict";
 import { Context } from "shared/Context";
@@ -35,6 +36,9 @@ import {
   FullGithubActionConfigType,
   GithubActionConfigType,
 } from "shared/types";
+import { z } from "zod";
+import { PorterYamlSchema } from "./schema";
+import { createDefaultService } from "./serviceTypes";
 
 type Props = RouteComponentProps & {};
 
@@ -109,6 +113,34 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
     };
   };
   const [showGHAModal, setShowGHAModal] = useState<boolean>(false);
+  const [porterJson, setPorterJson] = useState<z.infer<typeof PorterYamlSchema>>(null);
+
+  const validatePorterYaml = (yamlString: string) => {
+    let parsedYaml;
+    try {
+      parsedYaml = yaml.load(yamlString);
+      const parsedData = PorterYamlSchema.parse(parsedYaml);
+      const porterYaml = parsedData as z.infer<typeof PorterYamlSchema>;
+      setPorterJson(porterYaml)
+      // go through key value pairs and create services from them
+      const newServices = [];
+      for (const [name, app] of Object.entries(porterYaml.apps)) {
+        if (app.type) {
+          newServices.push(createDefaultService(name, app.type))
+        } else if (name.includes('web')) {
+          newServices.push(createDefaultService(name, 'web'))
+        } else {
+          newServices.push(createDefaultService(name, 'worker'))
+        }
+      }
+      setFormState({ ...formState, serviceList: [...formState.serviceList, ...newServices] });
+      if (Validators.serviceList(formState.serviceList)) {
+        setCurrentStep(Math.max(currentStep, 4));
+      }
+    } catch (error) {
+      console.log("Error converting porter yaml file to input: " + error)
+    }
+  }
 
   // Deploys a Helm chart and writes build settings to the DB
   const deployPorterApp = async () => {
@@ -209,12 +241,20 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
                   setProcfilePath={setProcfilePath}
                   setBuildConfig={setBuildConfig}
                   porterYaml={porterYaml}
-                  setPorterYaml={setPorterYaml}
+                  setPorterYaml={(newYaml: string) => {
+                    validatePorterYaml(newYaml)
+                  }}
                 />
               </>,
               <>
                 <Text size={16}>Application services</Text>
-                <Spacer y={1} />
+                <Spacer y={0.5} />
+                {porterJson && porterJson.apps && Object.keys(porterJson.apps).length > 0 &&
+                  <AppearingDiv>
+                    <Text size={16} color={"green"}>Autodetected {Object.keys(porterJson.apps).length} services from porter.yml</Text>
+                    <Spacer y={1} />
+                  </AppearingDiv>
+                }
                 <Services
                   setServices={(services: any[]) => {
                     setFormState({ ...formState, serviceList: services });
@@ -331,6 +371,21 @@ const Icon = styled.img`
   }
 `;
 
+const AppearingDiv = styled.div`
+  animation: floatIn 0.5s;
+  animation-fill-mode: forwards;
+  @keyframes floatIn {
+    from {
+      opacity: 0;
+      transform: translateY(20px);
+    }
+    to {
+      opacity: 1;
+      transform: translateY(0px);
+    }
+  }
+`;
+
 const StyledConfigureTemplate = styled.div`
   height: 100%;
 `;

+ 4 - 3
dashboard/src/main/home/app-dashboard/new-app-flow/schema.tsx

@@ -28,13 +28,14 @@ const buildSchema = z.object({
         return value.image != null;
     }
     return false;
-}, { message: "Invalid build configuration" });
+},
+    { message: "Invalid build configuration" });
 
 
 export const PorterYamlSchema = z.object({
     version: z.string().optional(),
-    build: buildSchema,
-    env: envSchema,
+    build: buildSchema.optional(),
+    env: envSchema.optional(),
     apps: appsSchema,
     release: z.string().optional(),
 });