Преглед на файлове

[POR-1925] make service error apparent in create form (#3812)

Feroze Mohideen преди 2 години
родител
ревизия
ff7f11af2a

+ 5 - 2
dashboard/src/components/porter/Error.tsx

@@ -9,6 +9,7 @@ type Props = {
   ctaText?: string;
   ctaOnClick?: () => void;
   errorModalContents?: React.ReactNode;
+  maxWidth?: string;
 };
 
 export const Error: React.FC<Props> = ({
@@ -16,12 +17,13 @@ export const Error: React.FC<Props> = ({
   ctaText,
   ctaOnClick,
   errorModalContents,
+  maxWidth,
 }) => {
   const [errorModalOpen, setErrorModalOpen] = useState(false);
 
   return (
     <>
-      <StyledError>
+      <StyledError maxWidth={maxWidth}>
         <i className="material-icons">error_outline</i>
         <Block>
           <Bold>Error:</Bold>
@@ -77,7 +79,7 @@ const Bold = styled.span`
   margin-right: 5px;
 `;
 
-const StyledError = styled.div`
+const StyledError = styled.div<{ maxWidth?: string }>`
   line-height: 1.5;
   color: #ff385d;
   font-size: 13px;
@@ -95,4 +97,5 @@ const StyledError = styled.div`
     top: 1px;
     left: 0;
   }
+  max-width: ${(props) => props.maxWidth || "100%"};
 `;

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

@@ -104,7 +104,16 @@ export const porterAppFormValidator = z
 
       return true;
     },
-    { message: "All services must include a run command" }
+    { message: "if building with buildpacks, all services must include a run command. Make sure all services contain a run command or change your build method to Docker in build settings", path: ["app", "services"] }
+  ).refine(
+    ({ app, source }) => {
+      if (source.type === "docker-registry" || app.build.method === "docker") {
+        return app.services.every((svc) => !svc.run.value.startsWith("docker run"));
+      }
+
+      return true;
+    },
+    { message: "if using Docker registry or building via a Dockerfile, service must not include `docker run` in its start command; instead, leave the start command empty", path: ["app", "services"] }
   );
 export type PorterAppFormData = z.infer<typeof porterAppFormValidator>;
 

+ 34 - 11
dashboard/src/main/home/app-dashboard/app-view/AppDataContainer.tsx

@@ -362,21 +362,44 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
     onSubmit();
   }, [onSubmit, setConfirmDeployModalOpen]);
 
-  const errorMessagesDeep = useMemo(() => {
-    return Object.values(_.mapValues(errors, (error) => error?.message));
-  }, [JSON.stringify(errors)]);
-
   const buttonStatus = useMemo(() => {
     if (isSubmitting) {
       return "loading";
     }
 
-    if (errorMessagesDeep.length > 0) {
-      return (
-        <ErrorComponent
-          message={`App update failed. ${errorMessagesDeep[0]}`}
-        />
-      );
+    // TODO: create a more unified way of parsing form/apply errors, unified with the logic in CreateApp
+    const errorKeys = Object.keys(errors);
+    if (errorKeys.length > 0) {
+      console.log("errors", errors)
+      let errorMessage = "App update failed. Please try again. If the error persists, please contact support@porter.run."
+      if (errorKeys.includes("app")) {
+        const appErrors = Object.keys(errors.app ?? {});
+        if (appErrors.includes("build")) {
+          errorMessage = "Build settings are not properly configured."
+        }
+
+        if (appErrors.includes("services")) {
+          errorMessage = "Service settings are not properly configured";
+          if (errors.app?.services?.root?.message || errors.app?.services?.message) {
+            const serviceErrorMessage = errors.app?.services?.root?.message ?? errors.app?.services?.message;
+            errorMessage = `${errorMessage} - ${serviceErrorMessage}`;
+          }
+          errorMessage = `${errorMessage}.`;
+        }
+
+        // this is the high level error message coming from the apply
+        if (appErrors.includes("message")) {
+          errorMessage = errors.app?.message ?? errorMessage;
+        }
+      }
+
+      updateAppStep({
+        step: "porter-app-update-failure",
+        errorMessage: `Form validation error: ${errorMessage}`,
+        appName: latestProto.name,
+      });
+
+      return <ErrorComponent message={errorMessage} maxWidth="600px" />;
     }
 
     if (isSubmitSuccessful) {
@@ -384,7 +407,7 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
     }
 
     return "";
-  }, [isSubmitting, errorMessagesDeep]);
+  }, [isSubmitting, JSON.stringify(errors)]);
 
   const tabs = useMemo(() => {
     const base = [

+ 17 - 8
dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx

@@ -385,23 +385,32 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
       return <Error message={deployError} />;
     }
 
+    // TODO: create a more unified way of parsing form/apply errors, unified with the logic in AppDataContainer
     const errorKeys = Object.keys(errors);
     if (errorKeys.length > 0) {
+      let errorMessage = "App could not be deployed as defined."
       if (errorKeys.includes("app")) {
-        const appErrors = Object.keys(errors?.app ?? {});
+        const appErrors = Object.keys(errors.app ?? {});
         if (appErrors.includes("build")) {
-          return (
-            <Error message={"Build settings are not properly configured."} />
-          );
+          errorMessage = "Build settings are not properly configured."
         }
 
         if (appErrors.includes("services")) {
-          return (
-            <Error message={"Service settings are not properly configured."} />
-          );
+          errorMessage = "Service settings are not properly configured";
+          if (errors.app?.services?.root?.message) {
+            errorMessage = `${errorMessage} - ${errors?.app?.services?.root?.message}`;
+          }
+          errorMessage = `${errorMessage}.`;
         }
       }
-      return <Error message={"App could not be deployed as defined."} />;
+
+      updateAppStep({
+        step: "stack-launch-failure",
+        errorMessage: `Form validation error: ${errorMessage}`,
+        appName: name.value,
+      });
+
+      return <Error message={errorMessage} maxWidth="600px" />;
     }
 
     return;