فهرست منبع

updated error handling for creds preflight check

Justin Rhee 3 سال پیش
والد
کامیت
ffc5fb05fb

+ 50 - 4
dashboard/src/components/CloudFormationForm.tsx

@@ -15,6 +15,9 @@ import Fieldset from "./porter/Fieldset";
 import Input from "./porter/Input";
 import Button from "./porter/Button";
 import DocsHelper from "./DocsHelper";
+import Error from "./porter/Error";
+import Step from "./porter/Step";
+import Link from "./porter/Link";
 
 type Props = {
   goBack: () => void;
@@ -48,6 +51,7 @@ const CloudFormationForm: React.FC<Props> = ({
   const checkIfRoleExists = async () => {
     let externalId = getExternalId();
     let targetARN = `arn:aws:iam::${AWSAccountID}:role/porter-role`
+
     setRoleStatus("loading");
     setErrorMessage(undefined)
     try {
@@ -122,8 +126,11 @@ const CloudFormationForm: React.FC<Props> = ({
                 setGrantPermissionsError("Invalid AWS account ID");
               }
             }}
-            status={grantPermissionsError}
-            errorText={grantPermissionsError}
+            status={
+              grantPermissionsError && (
+                <Error message={grantPermissionsError} />
+              )
+            }
             color="#1E2631"
             withBorder
           >
@@ -135,7 +142,47 @@ const CloudFormationForm: React.FC<Props> = ({
           onClick={() => {
             checkIfRoleExists()
           }}
-          status={roleStatus}
+          status={
+            errorMessage ? (
+              <Error 
+                message={errorMessage}
+                ctaText="Troubleshooting steps"
+                errorModalContents={
+                  <>
+                    <Text size={16} weight={500}>Granting Porter access to AWS</Text>
+                    <Spacer y={1} />
+                    <Text color="helper">
+                      Porter needs access to your AWS account in order to create infrastructure. You can grant Porter access to AWS by following these steps:
+                    </Text>
+                    <Spacer y={1} />
+                    <Step number={1}>
+                      <Link to="https://aws.amazon.com/resources/create-account/" target="_blank">
+                        Create an AWS account
+                      </Link>
+                      <Spacer inline width="5px" />
+                      if you don't already have one.
+                    </Step>
+                    <Spacer y={1} />
+                    <Step number={2}>
+                      Once you are logged in to your AWS account,
+                      <Spacer inline width="5px" />
+                      <Link to="https://console.aws.amazon.com/billing/home?region=us-east-1#/account" target="_blank">
+                        copy your account ID
+                      </Link>.
+                    </Step>
+                    <Spacer y={1} />
+                    <Step number={3}>Fill in your account ID on Porter and select "Grant permissions".</Step>
+                    <Spacer y={1} />
+                    <Step number={4}>After being redirected to AWS, select "Create stack" on the AWS console.</Step>
+                    <Spacer y={1} />
+                    <Step number={5}>Return to Porter and select "Continue".</Step>
+                  </>
+                }
+              />
+            ) : (
+              roleStatus
+            )
+          }
         >
           Continue
         </Button>
@@ -159,7 +206,6 @@ const CloudFormationForm: React.FC<Props> = ({
         Grant Porter permissions to create infrastructure in your AWS account.
       </Text>
       {renderContent()}
-      {errorMessage && <ErrorContainer>{errorMessage}</ErrorContainer>}
     </>
   );
 };

+ 2 - 2
dashboard/src/components/SaveButton.tsx

@@ -117,7 +117,7 @@ const StatusWrapper = styled.div<{
   align-items: center;
   font-family: "Work Sans", sans-serif;
   font-size: 13px;
-  color: #ff385d;
+  color: #ffffff55;
   ${(props) => {
     if (props.position !== "right") {
       return "margin-right: 25px;";
@@ -132,7 +132,7 @@ const StatusWrapper = styled.div<{
     font-size: 18px;
     margin-right: 10px;
     float: left;
-    color: ${(props) => (props.successful ? "#4797ff" : "#ff385d")};
+    color: ${(props) => (props.successful ? "#4797ff" : "#fcba03")};
   }
 
   animation-fill-mode: forwards;

+ 0 - 1
dashboard/src/components/porter/Button.tsx

@@ -106,7 +106,6 @@ const StatusWrapper = styled.div<{
   font-size: 13px;
   color: #ffffff55;
   margin-left: 15px;
-  max-width: 500px;
   text-overflow: ellipsis;
   animation: ${floatIn} 0.5s;
   animation-fill-mode: forwards;

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

@@ -24,8 +24,9 @@ const Error: React.FC<Props> = ({
     <>
       <StyledError>
         <i className="material-icons">error_outline</i>
+        <Block>
         <Bold>Error:</Bold>
-        {message}
+        <Text>{message}</Text>
         {ctaText && (
           <Cta onClick={() => {
             errorModalContents ? setErrorModalOpen(true) : ctaOnClick();
@@ -34,6 +35,7 @@ const Error: React.FC<Props> = ({
             <i className="material-icons">open_in_new</i>
           </Cta>
         )}
+        </Block>
       </StyledError>
       {errorModalOpen && createPortal(
         <Modal closeModal={() => setErrorModalOpen(false)}>
@@ -47,6 +49,14 @@ const Error: React.FC<Props> = ({
 
 export default Error;
 
+const Text = styled.span`
+  display: inline;
+`;
+
+const Block = styled.div`
+  display: block;
+`;
+
 const Underline = styled.span`
   text-decoration: underline;
 `;
@@ -54,7 +64,7 @@ const Underline = styled.span`
 const Cta = styled.span`
   margin-left: 5px;
   cursor: pointer;
-  display: flex;
+  display: inline-flex;
   align-items: center;
   
   > i {
@@ -65,6 +75,7 @@ const Cta = styled.span`
 
 const Bold = styled.span`
   font-weight: 600;
+  display: inline-block;
   margin-right: 5px;
 `;
 
@@ -74,11 +85,16 @@ const StyledError = styled.div`
   font-size: 13px;
   display: flex; 
   align-items: center;
+  position: relative;
+  padding-left: 25px;
   > i {
     font-size: 18px;
     margin-top: -1px;
     margin-right: 7px;
     float: left;
     font-weight: 600;
+    position: absolute;
+    top: 1px;
+    left: 0;
   }
 `;

+ 3 - 1
dashboard/src/components/porter/Link.tsx

@@ -6,17 +6,19 @@ type Props = {
   to?: string;
   onClick?: () => void;
   children: React.ReactNode;
+  target?: string;
 };
 
 const Link: React.FC<Props> = ({
   to,
   onClick,
   children,
+  target,
 }) => {
   return (
     <>
       {to ? (
-        <StyledLink to={to}>{children}</StyledLink>
+        <StyledLink to={to} target={target}>{children}</StyledLink>
       ) : (
         <Div onClick={onClick}>{children}</Div>
       )}

+ 1 - 0
dashboard/src/components/porter/Modal.tsx

@@ -78,6 +78,7 @@ const ModalBg = styled.div`
 const StyledModal = styled.div`
   position: relative;
   padding: 25px;
+  padding-bottom: 30px;
   border-radius: 10px;
   border: 1px solid #494b4f;
   font-size: 13px;

+ 45 - 0
dashboard/src/components/porter/Step.tsx

@@ -0,0 +1,45 @@
+import React, { useEffect, useState } from "react";
+import styled from "styled-components";
+
+type Props = {
+  number: number;
+  children: any;
+};
+
+const Step: React.FC<Props> = ({
+  number,
+  children
+}) => {  
+  return (
+    <StyledStep>
+      <StepNumber>{number}</StepNumber>
+      {children}
+    </StyledStep>
+  );
+};
+
+export default Step;
+
+const StepNumber = styled.div`
+  height: 20px;
+  min-width: 20px;
+  max-width: 20px;
+  margin-right: 15px;
+  background-color: #ffffff22;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: absolute;
+  left: 0;
+  top: 0;
+`;
+
+const StyledStep = styled.div<{ 
+}>`
+  font-size: 13px;
+  position: relative;
+  padding-left: 35px;
+  display: flex;
+  align-items: center;
+  line-height: 1.5;
+`;