ソースを参照

fix bug with predeploy

Feroze Mohideen 2 年 前
コミット
03acf801ac

+ 14 - 0
dashboard/src/lib/porter-apps/index.ts

@@ -257,6 +257,7 @@ export function clientAppFromProto(
   proto: PorterApp,
   proto: PorterApp,
   overrides: DetectedServices | null
   overrides: DetectedServices | null
 ): ClientPorterApp {
 ): ClientPorterApp {
+  console.log("services", proto.services)
   const services = Object.entries(proto.services)
   const services = Object.entries(proto.services)
     .map(([name, service]) => serializedServiceFromProto({ name, service }))
     .map(([name, service]) => serializedServiceFromProto({ name, service }))
     .map((svc) => {
     .map((svc) => {
@@ -273,10 +274,21 @@ export function clientAppFromProto(
       return deserializeService({ service: svc });
       return deserializeService({ service: svc });
     });
     });
 
 
+  const predeployList = [];
+  if (proto.predeploy) {
+    predeployList.push(deserializeService({
+      service: serializedServiceFromProto({
+        name: "pre-deploy",
+        service: proto.predeploy,
+        isPredeploy: true,
+      })
+    }))
+  }
   if (!overrides?.predeploy) {
   if (!overrides?.predeploy) {
     return {
     return {
       name: proto.name,
       name: proto.name,
       services,
       services,
+      predeploy: predeployList,
       env: proto.env,
       env: proto.env,
       build: clientBuildFromProto(proto.build) ?? {
       build: clientBuildFromProto(proto.build) ?? {
         method: "pack",
         method: "pack",
@@ -299,6 +311,8 @@ export function clientAppFromProto(
     })]
     })]
     : undefined;
     : undefined;
 
 
+  console.log(predeploy)
+
   return {
   return {
     name: proto.name,
     name: proto.name,
     services,
     services,

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

@@ -109,6 +109,8 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
       },
       },
     },
     },
   });
   });
+  console.log("values", porterAppFormMethods.getValues())
+  console.log("client app from proto", clientAppFromProto(latestProto, servicesFromYaml))
   const {
   const {
     reset,
     reset,
     handleSubmit,
     handleSubmit,

+ 2 - 1
dashboard/src/main/home/app-dashboard/app-view/tabs/Overview.tsx

@@ -45,13 +45,14 @@ const Overview: React.FC = () => {
             })}
             })}
             existingServiceNames={Object.keys(latestProto.services)}
             existingServiceNames={Object.keys(latestProto.services)}
             isPredeploy
             isPredeploy
+            fieldArrayName={"app.predeploy"}
           />
           />
           <Spacer y={0.5} />
           <Spacer y={0.5} />
         </>
         </>
       )}
       )}
       <Text size={16}>Application services</Text>
       <Text size={16}>Application services</Text>
       <Spacer y={0.5} />
       <Spacer y={0.5} />
-      <ServiceList addNewText={"Add a new service"} />
+      <ServiceList addNewText={"Add a new service"} fieldArrayName={"app.services"} existingServiceNames={Object.keys(latestProto.services)} />
       <Spacer y={0.75} />
       <Spacer y={0.75} />
       <Button
       <Button
         type="submit"
         type="submit"

+ 10 - 3
dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx

@@ -121,6 +121,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
     setValue,
     setValue,
     handleSubmit,
     handleSubmit,
     setError,
     setError,
+    clearErrors,
     formState: { isSubmitting: isValidating, errors },
     formState: { isSubmitting: isValidating, errors },
   } = porterAppFormMethods;
   } = porterAppFormMethods;
 
 
@@ -302,6 +303,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
   // reset services when source changes
   // reset services when source changes
   useEffect(() => {
   useEffect(() => {
     setValue("app.services", []);
     setValue("app.services", []);
+    setValue("app.predeploy", []);
     setDetectedServices({
     setDetectedServices({
       detected: false,
       detected: false,
       count: 0,
       count: 0,
@@ -325,7 +327,8 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
   useEffect(() => {
   useEffect(() => {
     if (servicesFromYaml && !detectedServices.detected) {
     if (servicesFromYaml && !detectedServices.detected) {
       const { services, predeploy } = servicesFromYaml;
       const { services, predeploy } = servicesFromYaml;
-      setValue("app.services", [...services, predeploy].filter(valueExists));
+      setValue("app.services", services);
+      setValue("app.predeploy", [predeploy].filter(valueExists));
       setDetectedServices({
       setDetectedServices({
         detected: true,
         detected: true,
         count: services.length,
         count: services.length,
@@ -334,6 +337,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
 
 
     if (!servicesFromYaml && detectedServices.detected) {
     if (!servicesFromYaml && detectedServices.detected) {
       setValue("app.services", []);
       setValue("app.services", []);
+      setValue("app.predeploy", []);
       setDetectedServices({
       setDetectedServices({
         detected: false,
         detected: false,
         count: 0,
         count: 0,
@@ -346,7 +350,8 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
       setError("app.name", {
       setError("app.name", {
         message: "An app with this name already exists",
         message: "An app with this name already exists",
       });
       });
-      return;
+    } else {
+      clearErrors("app.name");
     }
     }
   }, [porterApps, name]);
   }, [porterApps, name]);
 
 
@@ -455,7 +460,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                       )}
                       )}
                     </Container>
                     </Container>
                     <Spacer y={0.5} />
                     <Spacer y={0.5} />
-                    <ServiceList addNewText={"Add a new service"} />
+                    <ServiceList addNewText={"Add a new service"} fieldArrayName={"app.services"} />
                   </>,
                   </>,
                   <>
                   <>
                     <Text size={16}>Environment variables (optional)</Text>
                     <Text size={16}>Environment variables (optional)</Text>
@@ -482,8 +487,10 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
                             name: "pre-deploy",
                             name: "pre-deploy",
                             type: "predeploy",
                             type: "predeploy",
                           }),
                           }),
+                          expanded: true,
                         })}
                         })}
                         isPredeploy
                         isPredeploy
+                        fieldArrayName={"app.predeploy"}
                       />
                       />
                     </>
                     </>
                   ),
                   ),

+ 4 - 10
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx

@@ -197,16 +197,10 @@ const ServiceContainer: React.FC<ServiceProps> = ({
       <ServiceHeader
       <ServiceHeader
         showExpanded={service.expanded}
         showExpanded={service.expanded}
         onClick={() => {
         onClick={() => {
-          try {
-            console.log(index);
-            update(index, {
-              ...service,
-              expanded: !service.expanded,
-            });
-          } catch (err) {
-            console.log(err);
-          }
-
+          update(index, {
+            ...service,
+            expanded: !service.expanded,
+          });
         }}
         }}
         chart={chart}
         chart={chart}
         bordersRounded={!getHasBuiltImage() && !service.expanded}
         bordersRounded={!getHasBuiltImage() && !service.expanded}

+ 6 - 1
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceList.tsx

@@ -44,6 +44,7 @@ type ServiceListProps = {
   prePopulateService?: ClientService;
   prePopulateService?: ClientService;
   isPredeploy?: boolean;
   isPredeploy?: boolean;
   existingServiceNames?: string[];
   existingServiceNames?: string[];
+  fieldArrayName: "app.services" | "app.predeploy";
 };
 };
 
 
 const ServiceList: React.FC<ServiceListProps> = ({
 const ServiceList: React.FC<ServiceListProps> = ({
@@ -51,6 +52,7 @@ const ServiceList: React.FC<ServiceListProps> = ({
   prePopulateService,
   prePopulateService,
   isPredeploy = false,
   isPredeploy = false,
   existingServiceNames = [],
   existingServiceNames = [],
+  fieldArrayName,
 }) => {
 }) => {
   // top level app form
   // top level app form
   const { control: appControl } = useFormContext<PorterAppFormData>();
   const { control: appControl } = useFormContext<PorterAppFormData>();
@@ -72,7 +74,7 @@ const ServiceList: React.FC<ServiceListProps> = ({
   });
   });
   const { append, remove, update, fields } = useFieldArray({
   const { append, remove, update, fields } = useFieldArray({
     control: appControl,
     control: appControl,
-    name: isPredeploy ? "app.predeploy" : "app.services",
+    name: fieldArrayName,
   });
   });
   const {
   const {
     append: appendDeletion,
     append: appendDeletion,
@@ -93,6 +95,9 @@ const ServiceList: React.FC<ServiceListProps> = ({
   const services = useMemo(() => {
   const services = useMemo(() => {
     // if predeploy, only show predeploy services
     // if predeploy, only show predeploy services
     // if not predeploy, only show non-predeploy services
     // if not predeploy, only show non-predeploy services
+    if (isPredeploy) {
+      console.log("fields", fields)
+    }
     return fields.map((svc, idx) => {
     return fields.map((svc, idx) => {
       const predeploy = isPredeployService(svc);
       const predeploy = isPredeployService(svc);
       return {
       return {

+ 9 - 8
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/JobTabs.tsx

@@ -39,14 +39,14 @@ const JobTabs: React.FC<Props> = ({
 
 
   const tabs = isPredeploy
   const tabs = isPredeploy
     ? [
     ? [
-        { label: "Main", value: "main" as const },
-        { label: "Resources", value: "resources" as const },
-      ]
+      { label: "Main", value: "main" as const },
+      { label: "Resources", value: "resources" as const },
+    ]
     : [
     : [
-        { label: "Main", value: "main" as const },
-        { label: "Resources", value: "resources" as const },
-        { label: "Advanced", value: "advanced" as const },
-      ];
+      { label: "Main", value: "main" as const },
+      { label: "Resources", value: "resources" as const },
+      { label: "Advanced", value: "advanced" as const },
+    ];
 
 
   return (
   return (
     <>
     <>
@@ -56,13 +56,14 @@ const JobTabs: React.FC<Props> = ({
         setCurrentTab={setCurrentTab}
         setCurrentTab={setCurrentTab}
       />
       />
       {match(currentTab)
       {match(currentTab)
-        .with("main", () => <MainTab index={index} service={service} />)
+        .with("main", () => <MainTab index={index} service={service} isPredeploy={isPredeploy} />)
         .with("resources", () => (
         .with("resources", () => (
           <Resources
           <Resources
             index={index}
             index={index}
             maxCPU={maxCPU}
             maxCPU={maxCPU}
             maxRAM={maxRAM}
             maxRAM={maxRAM}
             service={service}
             service={service}
+            isPredeploy={isPredeploy}
           />
           />
         ))
         ))
         .with("advanced", () => (
         .with("advanced", () => (

+ 3 - 2
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Main.tsx

@@ -12,9 +12,10 @@ import Link from "components/porter/Link";
 type MainTabProps = {
 type MainTabProps = {
   index: number;
   index: number;
   service: ClientService;
   service: ClientService;
+  isPredeploy?: boolean;
 };
 };
 
 
-const MainTab: React.FC<MainTabProps> = ({ index, service }) => {
+const MainTab: React.FC<MainTabProps> = ({ index, service, isPredeploy = false }) => {
   const { register, watch } = useFormContext<PorterAppFormData>();
   const { register, watch } = useFormContext<PorterAppFormData>();
   const cron = watch(`app.services.${index}.config.cron.value`);
   const cron = watch(`app.services.${index}.config.cron.value`);
 
 
@@ -45,7 +46,7 @@ const MainTab: React.FC<MainTabProps> = ({ index, service }) => {
         width="300px"
         width="300px"
         disabled={service.run.readOnly}
         disabled={service.run.readOnly}
         disabledTooltip={"You may only edit this field in your porter.yaml."}
         disabledTooltip={"You may only edit this field in your porter.yaml."}
-        {...register(`app.services.${index}.run.value`)}
+        {...register(isPredeploy ? `app.predeploy.${index}.run.value` : `app.services.${index}.run.value`)}
       />
       />
       {service.config.type === "job" && (
       {service.config.type === "job" && (
         <>
         <>

+ 98 - 0
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/PreDeployTabs.tsx

@@ -0,0 +1,98 @@
+import React from "react";
+import Text from "components/porter/Text";
+import Spacer from "components/porter/Spacer";
+import TabSelector from "components/TabSelector";
+import Checkbox from "components/porter/Checkbox";
+
+import { ClientService } from "lib/porter-apps/services";
+import { match } from "ts-pattern";
+import MainTab from "./Main";
+import Resources from "./Resources";
+import { Controller, useFormContext } from "react-hook-form";
+import { PorterAppFormData } from "lib/porter-apps";
+
+interface Props {
+    index: number;
+    service: ClientService & {
+        config: {
+            type: "job" | "predeploy";
+        };
+    };
+    chart?: any;
+    maxRAM: number;
+    maxCPU: number;
+    isPredeploy?: boolean;
+}
+
+const JobTabs: React.FC<Props> = ({
+    index,
+    service,
+    maxRAM,
+    maxCPU,
+    isPredeploy,
+}) => {
+    const { control } = useFormContext<PorterAppFormData>();
+    const [currentTab, setCurrentTab] = React.useState<
+        "main" | "resources" | "advanced"
+    >("main");
+
+    const tabs = isPredeploy
+        ? [
+            { label: "Main", value: "main" as const },
+            { label: "Resources", value: "resources" as const },
+        ]
+        : [
+            { label: "Main", value: "main" as const },
+            { label: "Resources", value: "resources" as const },
+            { label: "Advanced", value: "advanced" as const },
+        ];
+
+    return (
+        <>
+            <TabSelector
+                options={tabs}
+                currentTab={currentTab}
+                setCurrentTab={setCurrentTab}
+            />
+            {match(currentTab)
+                .with("main", () => <MainTab index={index} service={service} />)
+                .with("resources", () => (
+                    <Resources
+                        index={index}
+                        maxCPU={maxCPU}
+                        maxRAM={maxRAM}
+                        service={service}
+                    />
+                ))
+                .with("advanced", () => (
+                    <>
+                        <Spacer y={1} />
+                        <Controller
+                            name={`app.services.${index}.config.allowConcurrent`}
+                            control={control}
+                            render={({ field: { value, onChange } }) => (
+                                <Checkbox
+                                    checked={value.value}
+                                    toggleChecked={() => {
+                                        onChange({
+                                            ...value,
+                                            value: !value.value,
+                                        });
+                                    }}
+                                    disabled={value.readOnly}
+                                    disabledTooltip={
+                                        "You may only edit this field in your porter.yaml."
+                                    }
+                                >
+                                    <Text color="helper">Allow jobs to execute concurrently</Text>
+                                </Checkbox>
+                            )}
+                        />
+                    </>
+                ))
+                .exhaustive()}
+        </>
+    );
+};
+
+export default JobTabs;

+ 4 - 2
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Resources.tsx

@@ -14,6 +14,7 @@ type ResourcesProps = {
   maxCPU: number;
   maxCPU: number;
   maxRAM: number;
   maxRAM: number;
   service: ClientService;
   service: ClientService;
+  isPredeploy?: boolean;
 };
 };
 
 
 const Resources: React.FC<ResourcesProps> = ({
 const Resources: React.FC<ResourcesProps> = ({
@@ -21,6 +22,7 @@ const Resources: React.FC<ResourcesProps> = ({
   maxCPU,
   maxCPU,
   maxRAM,
   maxRAM,
   service,
   service,
+  isPredeploy = false,
 }) => {
 }) => {
   const { control, register, watch } = useFormContext<PorterAppFormData>();
   const { control, register, watch } = useFormContext<PorterAppFormData>();
 
 
@@ -32,7 +34,7 @@ const Resources: React.FC<ResourcesProps> = ({
     <>
     <>
       <Spacer y={1} />
       <Spacer y={1} />
       <Controller
       <Controller
-        name={`app.services.${index}.cpuCores`}
+        name={isPredeploy ? `app.predeploy.${index}.cpuCores` : `app.services.${index}.cpuCores`}
         control={control}
         control={control}
         render={({ field: { value, onChange } }) => (
         render={({ field: { value, onChange } }) => (
           <InputSlider
           <InputSlider
@@ -58,7 +60,7 @@ const Resources: React.FC<ResourcesProps> = ({
       />
       />
       <Spacer y={1} />
       <Spacer y={1} />
       <Controller
       <Controller
-        name={`app.services.${index}.ramMegabytes`}
+        name={isPredeploy ? `app.predeploy.${index}.ramMegabytes` : `app.services.${index}.ramMegabytes`}
         control={control}
         control={control}
         render={({ field: { value, onChange } }) => (
         render={({ field: { value, onChange } }) => (
           <InputSlider
           <InputSlider