소스 검색

properly handle front-end defaults; show warning for multiple command run commands (#3741)

Co-authored-by: David Townley <davidtownley@Davids-MacBook-Air.local>
Co-authored-by: ianedwards <ianedwards559@gmail.com>
d-g-town 2 년 전
부모
커밋
51fd807b19

+ 2 - 0
dashboard/src/components/porter/Text.tsx

@@ -22,6 +22,8 @@ const Text: React.FC<Props> = ({
     switch (color) {
       case "helper":
         return "#aaaabb";
+      case "warner":
+        return "#ff5a52";
       default:
         return color;
     }

+ 2 - 1
dashboard/src/lib/porter-apps/index.ts

@@ -110,10 +110,11 @@ export function serviceOverrides({
           }),
           override: svc,
           expanded: true,
+          setDefaults: false,
         });
       }
 
-      return deserializeService({ service: svc });
+      return deserializeService({ service: svc,  setDefaults: false});
     });
 
   const validatedBuild = buildValidator

+ 11 - 7
dashboard/src/lib/porter-apps/services.ts

@@ -286,10 +286,12 @@ export function deserializeService({
   service,
   override,
   expanded,
+  setDefaults = true,
 }: {
   service: SerializedService;
   override?: SerializedService;
   expanded?: boolean;
+  setDefaults?: boolean;
 }): ClientService {
   const baseService = {
     expanded,
@@ -326,10 +328,12 @@ export function deserializeService({
           autoscaling: deserializeAutoscaling({
             autoscaling: config.autoscaling,
             override: overrideWebConfig?.autoscaling,
+              setDefaults: setDefaults,
           }),
           healthCheck: deserializeHealthCheck({
             health: config.healthCheck,
             override: overrideWebConfig?.healthCheck,
+              setDefaults: setDefaults,
           }),
 
           domains: uniqueDomains.map((domain) => ({
@@ -344,7 +348,7 @@ export function deserializeService({
             typeof config.private === "boolean" ||
               typeof overrideWebConfig?.private === "boolean"
               ? ServiceField.boolean(config.private, overrideWebConfig?.private)
-              : ServiceField.boolean(false, undefined),
+              : (setDefaults ? ServiceField.boolean(false, undefined) : undefined),
         },
       };
     })
@@ -359,6 +363,7 @@ export function deserializeService({
           autoscaling: deserializeAutoscaling({
             autoscaling: config.autoscaling,
             override: overrideWorkerConfig?.autoscaling,
+              setDefaults: setDefaults,
           }),
         },
       };
@@ -378,7 +383,7 @@ export function deserializeService({
                 config.allowConcurrent,
                 overrideJobConfig?.allowConcurrent
               )
-              : ServiceField.boolean(false, undefined),
+              : (setDefaults ? ServiceField.boolean(false, undefined) : undefined),
           cron: ServiceField.string(config.cron, overrideJobConfig?.cron),
           suspendCron:
             typeof config.suspendCron === "boolean" ||
@@ -387,14 +392,13 @@ export function deserializeService({
                 config.suspendCron,
                 overrideJobConfig?.suspendCron
               )
-              : ServiceField.boolean(false, undefined),
+              : (setDefaults ? ServiceField.boolean(false, undefined) : undefined),
           timeoutSeconds:
-            config.timeoutSeconds == 0
-              ? ServiceField.number(3600, overrideJobConfig?.timeoutSeconds)
-              : ServiceField.number(
+            config.timeoutSeconds != 0
+             ? ServiceField.number(
                 config.timeoutSeconds,
                 overrideJobConfig?.timeoutSeconds
-              ),
+              ) : (setDefaults ? ServiceField.number(3600, overrideJobConfig?.timeoutSeconds) : ServiceField.number(0, overrideJobConfig?.timeoutSeconds)),
         },
       };
     })

+ 17 - 4
dashboard/src/lib/porter-apps/values.ts

@@ -111,12 +111,14 @@ export function serializeAutoscaling({
 export function deserializeAutoscaling({
   autoscaling,
   override,
+  setDefaults,
 }: {
   autoscaling?: SerializedAutoscaling;
   override?: SerializedAutoscaling;
+    setDefaults: boolean;
 }): ClientAutoscaling | undefined {
   return (
-    autoscaling && {
+    autoscaling ? {
       enabled: ServiceField.boolean(autoscaling.enabled, override?.enabled),
       minInstances: autoscaling.minInstances
         ? ServiceField.number(autoscaling.minInstances, override?.minInstances)
@@ -136,7 +138,13 @@ export function deserializeAutoscaling({
             override?.memoryThresholdPercent
           )
         : ServiceField.number(50, undefined),
-    }
+    } : (setDefaults ?  {
+        enabled: ServiceField.boolean(false, undefined),
+        minInstances: ServiceField.number(1, undefined),
+        maxInstances: ServiceField.number(10, undefined),
+        cpuThresholdPercent: ServiceField.number(50, undefined),
+        memoryThresholdPercent: ServiceField.number(50, undefined),
+    } : undefined )
   );
 }
 
@@ -166,17 +174,22 @@ export function serializeHealth({
 export function deserializeHealthCheck({
   health,
   override,
+  setDefaults,
 }: {
   health?: SerializedHealthcheck;
   override?: SerializedHealthcheck;
+  setDefaults: boolean;
 }): ClientHealthCheck | undefined {
   return (
-    health && {
+    health ? {
       enabled: ServiceField.boolean(health.enabled, override?.enabled),
       httpPath: health.httpPath
         ? ServiceField.string(health.httpPath, override?.httpPath)
         :  ServiceField.string("", undefined),
-    }
+    } : (setDefaults ? {
+        enabled: ServiceField.boolean(false, undefined),
+        httpPath: ServiceField.string("", undefined),
+    } : undefined)
   );
 }
 

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

@@ -19,6 +19,8 @@ type MainTabProps = {
 const MainTab: React.FC<MainTabProps> = ({ index, service, isPredeploy = false }) => {
   const { register, control, watch } = useFormContext<PorterAppFormData>();
   const cron = watch(`app.services.${index}.config.cron.value`);
+  const run = watch(`app.services.${index}.run.value`);
+  const predeployRun = watch(`app.predeploy.${index}.run.value`);
 
   const getScheduleDescription = useCallback((cron: string) => {
     try {
@@ -37,6 +39,21 @@ const MainTab: React.FC<MainTabProps> = ({ index, service, isPredeploy = false }
     }
   }, []);
 
+    const getValidStartCommand = useCallback((run: string) => {
+        if (run && (run.includes("&&") || run.includes(";"))) {
+            return (
+                <>
+                <Spacer y={0.5} />
+                <Text color="warner">Multiple commands are not supported at this time. To run multiple commands, move all commands into a script that can be run from a single endpoint.</Text>
+                </>
+            );
+        } else {
+            return (
+                <></>
+            );
+        }
+    }, []);
+
   return (
     <>
       <Spacer y={1} />
@@ -49,6 +66,8 @@ const MainTab: React.FC<MainTabProps> = ({ index, service, isPredeploy = false }
         disabledTooltip={"You may only edit this field in your porter.yaml."}
         {...register(isPredeploy ? `app.predeploy.${index}.run.value` : `app.services.${index}.run.value`)}
       />
+
+      {getValidStartCommand(isPredeploy ? predeployRun :run)}
       {service.config.type === "job" && (
         <>
           <Spacer y={1} />