瀏覽代碼

fix merge conflicts

Alexander Belanger 4 年之前
父節點
當前提交
6d9b7f4bf8

+ 40 - 37
dashboard/src/components/ProvisionerStatus.tsx

@@ -6,7 +6,7 @@ import loading from "assets/loading.gif";
 import styled from "styled-components";
 
 type Props = {
-  modules : TFModule[]
+  modules: TFModule[];
 };
 
 export interface TFModule {
@@ -28,12 +28,12 @@ export interface TFResource {
   errored: TFResourceError,
 }
 
-const nameMap : { [key: string]: string } = {
-  "eks": "Elastic Kubernetes Service (EKS)",
-  "ecr": "Elastic Container Registry (ECR)",
-  "doks": "DigitalOcean Kubernetes Service (DOKS)",
-  "docr": "DigitalOcean Container Registry (DOCR)",
-}
+const nameMap: { [key: string]: string } = {
+  eks: "Elastic Kubernetes Service (EKS)",
+  ecr: "Elastic Container Registry (ECR)",
+  doks: "DigitalOcean Kubernetes Service (DOKS)",
+  docr: "DigitalOcean Container Registry (DOCR)",
+};
 
 const ProvisionerStatus: React.FC<Props> = (props) => {
   const { modules } = props;
@@ -62,12 +62,12 @@ const ProvisionerStatus: React.FC<Props> = (props) => {
 
   const renderModules = () => {
     return modules.map((val) => {
-      const totalResources = val.resources?.length
+      const totalResources = val.resources?.length;
       const provisionedResources = val.resources?.filter((resource) => {
-        return resource.provisioned
-      }).length
+        return resource.provisioned;
+      }).length;
 
-      var errors : string[] = []
+      var errors: string[] = [];
 
       const hasError = val.resources?.filter((resource) => {
         if (resource.errored?.errored_out) {
@@ -79,7 +79,7 @@ const ProvisionerStatus: React.FC<Props> = (props) => {
 
       const width = 100 * (provisionedResources / (totalResources * 1.0)) || 100
 
-      var error = null
+      var error = null;
 
       if (hasError) {
         error = errors.map((error) => {
@@ -89,32 +89,32 @@ const ProvisionerStatus: React.FC<Props> = (props) => {
         error = <ExpandedError>This infrastructure was destroyed.</ExpandedError>
       }
 
-      var loadingFill 
-      var status 
+      var loadingFill;
+      var status;
 
       if (hasError || val.status == "destroyed") {
         loadingFill = <LoadingFill status="error" width={width + "%"} />
         status = renderStatus("error")
       } else if (width == 100) {
-        loadingFill = <LoadingFill status="successful" width={width + "%"} />
-        status = renderStatus("successful")
+        loadingFill = <LoadingFill status="successful" width={width + "%"} />;
+        status = renderStatus("successful");
       } else {
-        loadingFill = <LoadingFill status="loading" width={width + "%"} />
-        status = renderStatus("loading")
+        loadingFill = <LoadingFill status="loading" width={width + "%"} />;
+        status = renderStatus("loading");
       }
 
-      return <InfraObject key={val.id}>
-        <InfraHeader>
-          {status}
-          {nameMap[val.kind]}
-        </InfraHeader>
-        <LoadingBar>
-          {loadingFill}
-        </LoadingBar>
-        {error}
-      </InfraObject>
-    })
-  }
+      return (
+        <InfraObject key={val.id}>
+          <InfraHeader>
+            {status}
+            {nameMap[val.kind]}
+          </InfraHeader>
+          <LoadingBar>{loadingFill}</LoadingBar>
+          {error}
+        </InfraObject>
+      );
+    });
+  };
 
   return (
     <StyledProvisionerStatus>
@@ -135,11 +135,14 @@ const ExpandedError = styled.div`
   margin-top: 17px;
 `;
 
-const LoadingFill = styled.div<{ width: string, status: string }>`
-  width: ${props => props.width};
-  background: ${props => props.status === "successful" ? "rgb(56, 168, 138)" : (
-    props.status === "error" ? "#fcba03" : "linear-gradient(to right, #8ce1ff, #616FEE)"
-  )};
+const LoadingFill = styled.div<{ width: string; status: string }>`
+  width: ${(props) => props.width};
+  background: ${(props) =>
+    props.status === "successful"
+      ? "rgb(56, 168, 138)"
+      : props.status === "error"
+      ? "#fcba03"
+      : "linear-gradient(to right, #8ce1ff, #616FEE)"};
   height: 100%;
   background-size: 250% 100%;
   animation: moving-gradient 2s infinite;
@@ -171,7 +174,7 @@ const StatusIcon = styled.div<{ successful?: boolean }>`
     font-size: 18px;
     margin-right: 10px;
     float: left;
-    color: ${props => props.successful ? "rgb(56, 168, 138)" : "#fcba03"};
+    color: ${(props) => (props.successful ? "rgb(56, 168, 138)" : "#fcba03")};
   }
 `;
 
@@ -209,4 +212,4 @@ const InfraHeader = styled.div`
   font-weight: 500;
   display: flex;
   align-items: center;
-`;
+`;

+ 2 - 1
dashboard/src/main/home/Home.tsx

@@ -234,6 +234,7 @@ class Home extends Component<PropsType, StateType> {
   // 3. Make sure initializing from URL (DO oauth) displays the appropriate initial view
   componentDidUpdate(prevProps: PropsType) {
     if (prevProps.currentProject?.id !== this.props.currentProject?.id) {
+      this.checkOnboarding();
       this.checkIfProjectHasBilling(this?.context?.currentProject?.id)
         .then((isBillingEnabled) => {
           if (isBillingEnabled) {
@@ -333,7 +334,7 @@ class Home extends Component<PropsType, StateType> {
   };
 
   redirectToOnboarding = () => {
-    pushFiltered(this.props, "/onboarding", ["project_id"]);
+    pushFiltered(this.props, "/onboarding", []);
   };
 
   render() {

+ 4 - 6
dashboard/src/main/home/onboarding/Onboarding.tsx

@@ -12,7 +12,7 @@ import { Onboarding as OnboardingSaveType } from "./types";
 const Onboarding = () => {
   const context = useContext(Context);
   const [isLoading, setIsLoading] = useState(true);
-  useSteps();
+  useSteps(isLoading);
 
   useEffect(() => {
     let unsub = devtools(OFState, "Onboarding flow state");
@@ -92,8 +92,8 @@ const Onboarding = () => {
       project_id,
       project_name,
       ...(odata || {}),
-      ...(registry_connection_data || {}),
-      ...(provision_connection_data || {}),
+      ...({ registry_connection_data } || {}),
+      ...({ provision_connection_data } || {}),
     };
   };
 
@@ -110,9 +110,7 @@ const Onboarding = () => {
   }, [context.currentProject]);
 
   return (
-    <StyledOnboarding>
-      {isLoading ? <Loading /> : <Routes />}
-    </StyledOnboarding>
+    <StyledOnboarding>{isLoading ? <Loading /> : <Routes />}</StyledOnboarding>
   );
 };
 

+ 4 - 4
dashboard/src/main/home/onboarding/components/ProviderSelector.tsx

@@ -15,17 +15,17 @@ export type ProviderSelectorProps = {
 const baseOptions = [
   {
     value: "aws",
-    icon: integrationList["aws"].icon,
+    icon: integrationList["aws"]?.icon,
     label: "Amazon Elastic Container Registry (ECR)",
   },
   {
     value: "gcp",
-    icon: integrationList["gcp"].icon,
+    icon: integrationList["gcp"]?.icon,
     label: "Google Cloud Registry (GCR)",
   },
   {
     value: "do",
-    icon: integrationList["do"].icon,
+    icon: integrationList["do"]?.icon,
     label: "DigitalOcean Container Registry (DOCR)",
   },
 ];
@@ -38,7 +38,7 @@ const skipOption = {
 
 const externalOption = {
   value: "external",
-  icon: integrationList["kubernetes"].icon,
+  icon: integrationList["kubernetes"]?.icon,
   label: "Link to an existing cluster",
 };
 

+ 50 - 21
dashboard/src/main/home/onboarding/state/StepHandler.ts

@@ -139,7 +139,7 @@ const flow: FlowType = {
         settings: {
           url: "/onboarding/provision/settings",
           on: {
-            continue: "clean_up",
+            continue: "provision_resources.status",
             go_back: "provision_resources.credentials",
           },
           execute: {
@@ -148,6 +148,13 @@ const flow: FlowType = {
             },
           },
         },
+        status: {
+          url: "/onboarding/provision/status",
+          on: {
+            continue: "clean_up",
+            go_back: "provision_resources.credentials",
+          },
+        },
       },
     },
     clean_up: {
@@ -162,12 +169,13 @@ type StepHandlerType = {
   currentStepName: string;
   currentStep: Step;
   canGoBack?: boolean;
+  isSubFlow?: boolean;
   actions: {
     nextStep: (action?: Action) => void;
     clearState: () => void;
     restoreState: (prevState: Partial<StepHandlerType>) => void;
-    getStep: (nextStepName: string) => Step;
     goTo: (step: string) => void;
+    setNewCurrentStep: (stepName: string) => { hasError: boolean };
   };
 };
 
@@ -175,6 +183,7 @@ export const StepHandler: StepHandlerType = proxy({
   flow,
   currentStepName: flow.initial,
   currentStep: flow.steps[flow.initial],
+  isSubFlow: false,
   actions: {
     nextStep: (action: Action = "continue") => {
       const cs = StepHandler.currentStep;
@@ -190,10 +199,7 @@ export const StepHandler: StepHandlerType = proxy({
           "No next step name found, fix the action triggering nextStep"
         );
       }
-      const newStep = StepHandler.actions.getStep(nextStepName);
-      StepHandler.currentStepName = nextStepName;
-      StepHandler.currentStep = newStep;
-      StepHandler.canGoBack = !!newStep?.on?.go_back;
+      StepHandler.actions.setNewCurrentStep(nextStepName);
       return;
     },
     getStep: (nextStepName: string) => {
@@ -206,23 +212,18 @@ export const StepHandler: StepHandlerType = proxy({
       if (substep) {
         nextStep = step.substeps[substep];
       }
-      return nextStep;
+      return { step: nextStep, isChild: !!substep };
     },
     goTo: (step: string) => {
-      const newStep = StepHandler.actions.getStep(step);
-      if (!newStep) {
+      const status = StepHandler.actions.setNewCurrentStep(step);
+      if (status.hasError) {
         throw new Error(
           "No next step name found, fix the action triggering nextStep"
         );
       }
-      StepHandler.currentStepName = step;
-      StepHandler.currentStep = newStep;
-      StepHandler.canGoBack = !!newStep?.on?.go_back;
-      return;
     },
     clearState: () => {
-      StepHandler.currentStepName = flow.initial;
-      StepHandler.currentStep = flow.steps[flow.initial];
+      StepHandler.actions.setNewCurrentStep(flow.initial);
     },
     restoreState: (prevState) => {
       if (
@@ -231,22 +232,50 @@ export const StepHandler: StepHandlerType = proxy({
       ) {
         return;
       }
-      StepHandler.currentStepName = prevState.currentStepName;
-      StepHandler.currentStep = StepHandler.actions.getStep(
-        prevState.currentStepName
-      );
+      const stepName = prevState.currentStepName;
+
+      StepHandler.actions.setNewCurrentStep(stepName);
+    },
+    setNewCurrentStep: (newStepName: string) => {
+      const [stepName, substep] = newStepName?.split(".");
+
+      const isChild = !!substep;
+      const step = flow.steps[stepName as Steps];
+
+      let nextStep: Step = step;
+
+      if (isChild) {
+        nextStep = step.substeps[substep];
+      }
+
+      if (!nextStep) {
+        return {
+          hasError: true,
+        };
+      }
+
+      StepHandler.currentStepName = newStepName;
+      StepHandler.currentStep = nextStep;
+      StepHandler.canGoBack = !!nextStep?.on?.go_back;
+      StepHandler.isSubFlow = isChild;
+      return {
+        hasError: false,
+      };
     },
   },
 });
 
-export const useSteps = () => {
+export const useSteps = (isParentLoading?: boolean) => {
   const snap = useSnapshot(StepHandler);
   const location = useLocation();
   const { pushFiltered } = useRouting();
   useEffect(() => {
+    if (isParentLoading) {
+      return;
+    }
     if (snap.currentStepName === "clean_up") {
       StepHandler.actions.clearState();
     }
     pushFiltered(snap.currentStep.url, ["tab"]);
-  }, [location.pathname, snap.currentStep?.url]);
+  }, [location.pathname, snap.currentStep?.url, isParentLoading]);
 };

+ 4 - 4
dashboard/src/main/home/onboarding/state/index.ts

@@ -105,17 +105,17 @@ const decompressState = (prev_state: any) => {
     skip: state.skip_registry_connection,
     provider: state.registry_connection_provider,
     credentials: {
-      id: state.registry_connection_credential_id,
+      id: state?.registry_connection_data?.id,
     },
     settings: {
-      registry_name: state.registry_connection_settings_name,
+      registry_name: state?.registry_connection_data?.name,
     },
   };
 
   if (registry.provider === "gcp") {
-    registry.settings.gcr_url = state.registry_connection_settings_url;
+    registry.settings.gcr_url = state.registry_connection_data?.url;
   } else if (registry.provider === "do") {
-    registry.settings.registry_url = state.registry_connection_settings_url;
+    registry.settings.registry_url = state.registry_connection_data?.url;
   }
 
   let provision: any = {

+ 3 - 3
dashboard/src/main/home/onboarding/steps/ConnectRegistry/ConnectRegistryWrapper.tsx

@@ -9,9 +9,9 @@ const ConnectRegistryWrapper = () => {
     <ConnectRegistry
       provider={snap.StateHandler.connected_registry?.provider}
       project={snap.StateHandler.project}
-      onSelectProvider={(provider) =>
-        provider !== "skip" && OFState.actions.nextStep("continue", provider)
-      }
+      onSelectProvider={(provider) => {
+        provider !== "skip" && OFState.actions.nextStep("continue", provider);
+      }}
       onSaveCredentials={(data) => OFState.actions.nextStep("continue", data)}
       onSaveSettings={(data) => OFState.actions.nextStep("continue", data)}
       onSuccess={() => OFState.actions.nextStep("continue")}

+ 48 - 24
dashboard/src/main/home/onboarding/steps/ProvisionResources/ProvisionResources.tsx

@@ -10,6 +10,7 @@ import FormFlowWrapper from "./forms/FormFlow";
 import ConnectExternalCluster from "./forms/_ConnectExternalCluster";
 import { SupportedProviders } from "../../types";
 import backArrow from "assets/back_arrow.png";
+import { SharedStatus } from "./forms/Status";
 
 type Props = {
   provider: SupportedProviders | "external";
@@ -41,6 +42,52 @@ const ProvisionResources: React.FC<Props> = ({
 }) => {
   const { step } = useParams<{ step: any }>();
 
+  const Content = () => {
+    switch (step) {
+      case "credentials":
+      case "settings":
+        return (
+          <>
+            <FormFlowWrapper
+              provider={provider}
+              currentStep={step}
+              onSaveCredentials={onSaveCredentials}
+              onSaveSettings={onSaveSettings}
+              project={project}
+            />
+          </>
+        );
+      case "status":
+        return (
+          <>
+            <SharedStatus
+              project={project}
+              filter={[]}
+              nextFormStep={console.log}
+            />
+          </>
+        );
+      case "connect_own_cluster":
+        return (
+          <>
+            <ConnectExternalCluster nextStep={onSuccess} project={project} />
+          </>
+        );
+      default:
+        return (
+          <>
+            <ProviderSelector
+              selectProvider={(provider) => {
+                onSelectProvider(provider);
+              }}
+              enableSkip={false}
+              enableExternal={!shouldProvisionRegistry}
+            />
+          </>
+        );
+    }
+  };
+
   return (
     <div>
       {enable_go_back && (
@@ -58,30 +105,7 @@ const ProvisionResources: React.FC<Props> = ({
         Porter automatically creates a cluster and registry in your cloud to run
         applications.
       </Helper>
-
-      {provider ? (
-        provider !== "external" ? (
-          <FormFlowWrapper
-            provider={provider}
-            currentStep={step}
-            onSaveCredentials={onSaveCredentials}
-            onSaveSettings={onSaveSettings}
-            project={project}
-          />
-        ) : (
-          <ConnectExternalCluster nextStep={onSuccess} project={project} />
-        )
-      ) : (
-        <>
-          <ProviderSelector
-            selectProvider={(provider) => {
-              onSelectProvider(provider);
-            }}
-            enableSkip={false}
-            enableExternal={!shouldProvisionRegistry}
-          />
-        </>
-      )}
+      {Content()}
     </div>
   );
 };

+ 7 - 3
dashboard/src/main/home/onboarding/steps/ProvisionResources/ProvisionResourcesWrapper.tsx

@@ -10,9 +10,13 @@ const ProvisionResourcesWrapper = () => {
       shouldProvisionRegistry={snap.StateHandler.connected_registry?.skip}
       provider={snap.StateHandler.provision_resources?.provider}
       project={snap.StateHandler.project}
-      onSelectProvider={(provider: string) =>
-        provider !== "dummy" && OFState.actions.nextStep("continue", provider)
-      }
+      onSelectProvider={(provider: string) => {
+        if (provider !== "external") {
+          OFState.actions.nextStep("continue", provider);
+          return;
+        }
+        OFState.actions.nextStep("skip");
+      }}
       onSaveCredentials={(data) => OFState.actions.nextStep("continue", data)}
       onSaveSettings={(data) => OFState.actions.nextStep("continue", data)}
       onSuccess={() => OFState.actions.nextStep("continue")}

+ 3 - 9
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/FormFlow.tsx

@@ -3,43 +3,37 @@ import {
   SkipProvisionConfig,
   SupportedProviders,
 } from "main/home/onboarding/types";
-import React, { useContext, useMemo } from "react";
+import React, { useMemo } from "react";
 import styled from "styled-components";
 import Breadcrumb from "components/Breadcrumb";
 import { integrationList } from "shared/common";
 import {
   CredentialsForm as AWSCredentialsForm,
   SettingsForm as AWSSettingsForm,
-  Status as AWSProvisionerStatus,
 } from "./_AWSProvisionerForm";
 
 import {
   CredentialsForm as DOCredentialsForm,
   SettingsForm as DOSettingsForm,
-  Status as DOProvisionerStatus,
 } from "./_DOProvisionerForm";
 
 import {
   CredentialsForm as GCPCredentialsForm,
   SettingsForm as GCPSettingsForm,
-  Status as GCPProvisionerStatus,
 } from "./_GCPProvisionerForm";
 
 const Forms = {
   aws: {
     credentials: AWSCredentialsForm,
     settings: AWSSettingsForm,
-    status: AWSProvisionerStatus,
   },
   gcp: {
     credentials: GCPCredentialsForm,
     settings: GCPSettingsForm,
-    status: GCPProvisionerStatus,
   },
   do: {
     credentials: DOCredentialsForm,
     settings: DOSettingsForm,
-    status: DOProvisionerStatus,
   },
 };
 
@@ -59,14 +53,14 @@ const FormTitle = {
   external: {
     label: "Connect an existing cluster",
     icon: integrationList["kubernetes"],
-  }
+  },
 };
 
 type Props = {
   onSaveCredentials: (credentials: any) => void;
   onSaveSettings: (settings: any) => void;
   provider: SupportedProviders | "external";
-  currentStep: "credentials" | "settings" | "status";
+  currentStep: "credentials" | "settings";
   project: { id: number; name: string };
 };
 

+ 1 - 5
dashboard/src/main/home/onboarding/steps/ProvisionResources/forms/_ConnectExternalCluster.tsx

@@ -131,7 +131,7 @@ const PageCount = styled.div`
 `;
 
 const PageSection = styled.div`
-  position: absolute;
+  position: relative;
   bottom: 22px;
   right: 20px;
   display: flex;
@@ -237,11 +237,7 @@ const CloseButtonImg = styled.img`
 
 const StyledClusterInstructionsModal = styled.div`
   width: 100%;
-  position: absolute;
-  left: 0;
-  top: 0;
   height: 100%;
-  padding: 25px 32px;
   overflow: hidden;
   border-radius: 6px;
   background: #202227;