فهرست منبع

Added basic primitives

jnfrati 4 سال پیش
والد
کامیت
be250be504

+ 6 - 0
dashboard/src/main/home/new-project/NewProject.tsx

@@ -23,6 +23,12 @@ export default class NewProject extends Component<PropsType, StateType> {
     selectedProvider: null as string | null,
     selectedProvider: null as string | null,
   };
   };
 
 
+  componentDidMount() {
+    window.analytics.track("provision_new-project", {
+      userId: this.context.user?.id,
+    });
+  }
+
   render() {
   render() {
     let { capabilities } = this.context;
     let { capabilities } = this.context;
     let { projectName } = this.state;
     let { projectName } = this.state;

+ 13 - 7
dashboard/src/main/home/provisioner/AWSFormSection.tsx

@@ -24,6 +24,7 @@ type PropsType = RouteComponentProps & {
   projectName: string;
   projectName: string;
   infras: InfraType[];
   infras: InfraType[];
   highlightCosts?: boolean;
   highlightCosts?: boolean;
+  trackOnSave: () => void;
 };
 };
 
 
 type StateType = {
 type StateType = {
@@ -282,6 +283,7 @@ class AWSFormSection extends Component<PropsType, StateType> {
 
 
   // TODO: handle generically (with > 2 steps)
   // TODO: handle generically (with > 2 steps)
   onCreateAWS = () => {
   onCreateAWS = () => {
+    this.props?.trackOnSave();
     this.setState({ buttonStatus: "loading" });
     this.setState({ buttonStatus: "loading" });
     let { projectName } = this.props;
     let { projectName } = this.props;
     let { selectedInfras } = this.state;
     let { selectedInfras } = this.state;
@@ -362,6 +364,16 @@ class AWSFormSection extends Component<PropsType, StateType> {
     }
     }
   };
   };
 
 
+  goToGuide = () => {
+    window?.analytics?.track("provision_go-to-guide", {
+      hosting: "aws",
+    });
+
+    window.open(
+      "https://docs.getporter.dev/docs/getting-started-with-porter-on-aws"
+    );
+  };
+
   render() {
   render() {
     let { setSelectedProvisioner } = this.props;
     let { setSelectedProvisioner } = this.props;
     let {
     let {
@@ -380,13 +392,7 @@ class AWSFormSection extends Component<PropsType, StateType> {
           </CloseButton>
           </CloseButton>
           <Heading isAtTop={true}>
           <Heading isAtTop={true}>
             AWS Credentials
             AWS Credentials
-            <GuideButton
-              onClick={() =>
-                window.open(
-                  "https://docs.getporter.dev/docs/getting-started-with-porter-on-aws"
-                )
-              }
-            >
+            <GuideButton onClick={() => this.goToGuide()}>
               <i className="material-icons-outlined">help</i>
               <i className="material-icons-outlined">help</i>
               Guide
               Guide
             </GuideButton>
             </GuideButton>

+ 2 - 0
dashboard/src/main/home/provisioner/DOFormSection.tsx

@@ -23,6 +23,7 @@ type PropsType = {
   projectName: string;
   projectName: string;
   highlightCosts?: boolean;
   highlightCosts?: boolean;
   infras: InfraType[];
   infras: InfraType[];
+  trackOnSave: () => void;
 };
 };
 
 
 type StateType = {
 type StateType = {
@@ -177,6 +178,7 @@ export default class DOFormSection extends Component<PropsType, StateType> {
 
 
   // TODO: handle generically (with > 2 steps)
   // TODO: handle generically (with > 2 steps)
   onCreateDO = () => {
   onCreateDO = () => {
+    this.props?.trackOnSave();
     let { projectName } = this.props;
     let { projectName } = this.props;
     let { selectedInfras } = this.state;
     let { selectedInfras } = this.state;
     let { currentProject } = this.context;
     let { currentProject } = this.context;

+ 2 - 0
dashboard/src/main/home/provisioner/ExistingClusterSection.tsx

@@ -12,6 +12,7 @@ import { RouteComponentProps, withRouter } from "react-router";
 
 
 type PropsType = RouteComponentProps & {
 type PropsType = RouteComponentProps & {
   projectName: string;
   projectName: string;
+  trackOnSave: () => void;
 };
 };
 
 
 type StateType = {
 type StateType = {
@@ -24,6 +25,7 @@ class ExistingClusterSection extends Component<PropsType, StateType> {
   };
   };
 
 
   onCreateProject = () => {
   onCreateProject = () => {
+    this.props?.trackOnSave();
     let { projectName } = this.props;
     let { projectName } = this.props;
     let { user, setProjects, setCurrentProject } = this.context;
     let { user, setProjects, setCurrentProject } = this.context;
 
 

+ 11 - 7
dashboard/src/main/home/provisioner/GCPFormSection.tsx

@@ -25,6 +25,7 @@ type PropsType = RouteComponentProps & {
   projectName: string;
   projectName: string;
   highlightCosts?: boolean;
   highlightCosts?: boolean;
   infras: InfraType[];
   infras: InfraType[];
+  trackOnSave: () => void;
 };
 };
 
 
 type StateType = {
 type StateType = {
@@ -269,6 +270,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
 
 
   // TODO: handle generically (with > 2 steps)
   // TODO: handle generically (with > 2 steps)
   onCreateGCP = () => {
   onCreateGCP = () => {
+    this.props?.trackOnSave();
     this.setState({ buttonStatus: "loading" });
     this.setState({ buttonStatus: "loading" });
     let { projectName } = this.props;
     let { projectName } = this.props;
 
 
@@ -320,6 +322,14 @@ class GCPFormSection extends Component<PropsType, StateType> {
     }
     }
   };
   };
 
 
+  goToGuide = () => {
+    window?.analytics?.track("provision_go-to-guide", {
+      hosting: "gcp",
+    });
+
+    window.open("https://docs.getporter.dev/docs/getting-started-on-gcp");
+  };
+
   render() {
   render() {
     let { setSelectedProvisioner } = this.props;
     let { setSelectedProvisioner } = this.props;
     let { gcpRegion, gcpProjectId, gcpKeyData, selectedInfras } = this.state;
     let { gcpRegion, gcpProjectId, gcpKeyData, selectedInfras } = this.state;
@@ -331,13 +341,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
           </CloseButton>
           </CloseButton>
           <Heading isAtTop={true}>
           <Heading isAtTop={true}>
             GCP Credentials
             GCP Credentials
-            <GuideButton
-              onClick={() =>
-                window.open(
-                  "https://docs.getporter.dev/docs/getting-started-on-gcp"
-                )
-              }
-            >
+            <GuideButton onClick={() => this.goToGuide()}>
               <i className="material-icons-outlined">help</i>
               <i className="material-icons-outlined">help</i>
               Guide
               Guide
             </GuideButton>
             </GuideButton>

+ 183 - 181
dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

@@ -1,4 +1,4 @@
-import React, { Component } from "react";
+import React, { Component, useContext, useEffect, useState } from "react";
 import styled from "styled-components";
 import styled from "styled-components";
 
 
 import { Context } from "shared/Context";
 import { Context } from "shared/Context";
@@ -11,140 +11,171 @@ import GCPFormSection from "./GCPFormSection";
 import DOFormSection from "./DOFormSection";
 import DOFormSection from "./DOFormSection";
 import SaveButton from "components/SaveButton";
 import SaveButton from "components/SaveButton";
 import ExistingClusterSection from "./ExistingClusterSection";
 import ExistingClusterSection from "./ExistingClusterSection";
-import { RouteComponentProps, withRouter } from "react-router";
+import { useHistory, useLocation } from "react-router";
 import { pushFiltered } from "shared/routing";
 import { pushFiltered } from "shared/routing";
-import InfoTooltip from "../../../components/InfoTooltip";
 
 
-type PropsType = RouteComponentProps & {
+type Props = {
   isInNewProject?: boolean;
   isInNewProject?: boolean;
   projectName?: string;
   projectName?: string;
   infras?: InfraType[];
   infras?: InfraType[];
   provisioner?: boolean;
   provisioner?: boolean;
 };
 };
 
 
-type StateType = {
-  selectedProvider: string | null;
-  highlightCosts: boolean;
-  infras: InfraType[];
-};
-
 const providers = ["aws", "gcp", "do"];
 const providers = ["aws", "gcp", "do"];
 
 
-class NewProject extends Component<PropsType, StateType> {
-  state = {
-    selectedProvider: null as string | null,
-    highlightCosts: true,
-    infras: [] as InfraType[],
+const ProvisionerSettings: React.FC<Props> = ({
+  provisioner,
+  projectName,
+  infras,
+  isInNewProject,
+}) => {
+  const [selectedProvider, setSelectedProvider] = useState<string | null>(null);
+  const [highlightCosts, setHighlightCosts] = useState(true);
+
+  const { setCurrentError } = useContext(Context);
+  const location = useLocation();
+  const history = useHistory();
+
+  useEffect(() => {
+    if (!provisioner) {
+      handleSelectProvider("skipped");
+    }
+  }, [provisioner]);
+
+  const handleSelectProvider = (newSelectedProvider: string) => {
+    if (!isInNewProject) {
+      setSelectedProvider(selectedProvider);
+      return;
+    }
+    if (newSelectedProvider === selectedProvider) {
+      return;
+    }
+
+    if (selectedProvider && !newSelectedProvider) {
+      window?.analytics?.track("provision_unselect-provider", {
+        unselectedProvider: selectedProvider,
+      });
+      setSelectedProvider(newSelectedProvider);
+      return;
+    }
+
+    window?.analytics?.track("provision_select-provider", {
+      selectedProvider: newSelectedProvider,
+    });
+    setSelectedProvider(newSelectedProvider);
   };
   };
 
 
-  // Handle any submission (pre-status) error
-  handleError = () => {
-    let { setCurrentError } = this.context;
-    this.setState({ selectedProvider: null });
+  const handleError = () => {
+    handleSelectProvider(null);
+
     setCurrentError(
     setCurrentError(
       "Provisioning failed. Check your credentials and try again."
       "Provisioning failed. Check your credentials and try again."
     );
     );
-    pushFiltered(this.props, "/dashboard", ["project_id"], { tab: "overview" });
+    pushFiltered({ location, history }, "/dashboard", ["project_id"], {
+      tab: "overview",
+    });
   };
   };
 
 
-  renderSelectedProvider = (override?: string) => {
-    let { selectedProvider } = this.state;
-    let { projectName, infras } = this.props;
+  const trackOnSave = (provider: string) => {
+    window?.analytics?.track("provision_created-project", {
+      choosenProvider: provider,
+    });
+  };
 
 
-    if (override) {
-      selectedProvider = override;
+  const renderSkipHelper = () => {
+    if (!provisioner) {
+      return;
     }
     }
 
 
-    let renderSkipHelper = () => {
-      if (!this.props.provisioner) {
-        return;
-      }
-
-      return (
-        <>
-          {selectedProvider === "skipped" ? (
+    return (
+      <>
+        {selectedProvider === "skipped" ? (
+          <Helper>
+            Don't have a Kubernetes cluster?
+            <Highlight onClick={() => handleSelectProvider(null)}>
+              Provision through Porter
+            </Highlight>
+          </Helper>
+        ) : (
+          <PositionWrapper selectedProvider={selectedProvider}>
             <Helper>
             <Helper>
-              Don't have a Kubernetes cluster?
-              <Highlight
-                onClick={() => this.setState({ selectedProvider: null })}
-              >
-                Provision through Porter
+              Already have a Kubernetes cluster?
+              <Highlight onClick={() => handleSelectProvider("skipped")}>
+                Skip
               </Highlight>
               </Highlight>
             </Helper>
             </Helper>
-          ) : (
-            <PositionWrapper selectedProvider={selectedProvider}>
-              <Helper>
-                Already have a Kubernetes cluster?
-                <Highlight
-                  onClick={() =>
-                    this.setState({
-                      selectedProvider: "skipped",
-                    })
-                  }
-                >
-                  Skip
-                </Highlight>
-              </Helper>
-            </PositionWrapper>
-          )}
-        </>
+          </PositionWrapper>
+        )}
+      </>
+    );
+  };
+
+  const renderSelectedProvider = (override?: string) => {
+    let currentSelectedProvider = selectedProvider;
+    if (override) {
+      currentSelectedProvider = override;
+    }
+
+    if (selectedProvider === "aws") {
+      return (
+        <AWSFormSection
+          handleError={handleError}
+          projectName={projectName}
+          infras={infras}
+          highlightCosts={highlightCosts}
+          setSelectedProvisioner={(x: string | null) => {
+            handleSelectProvider(x);
+          }}
+          trackOnSave={() => trackOnSave(selectedProvider)}
+        >
+          {renderSkipHelper()}
+        </AWSFormSection>
       );
       );
-    };
-
-    switch (selectedProvider) {
-      case "aws":
-        return (
-          <AWSFormSection
-            handleError={this.handleError}
-            projectName={projectName}
-            infras={infras}
-            highlightCosts={this.state.highlightCosts}
-            setSelectedProvisioner={(x: string | null) => {
-              this.setState({ selectedProvider: x });
-            }}
-          >
-            {renderSkipHelper()}
-          </AWSFormSection>
-        );
-      case "gcp":
-        return (
-          <GCPFormSection
-            handleError={this.handleError}
-            projectName={projectName}
-            infras={infras}
-            highlightCosts={this.state.highlightCosts}
-            setSelectedProvisioner={(x: string | null) => {
-              this.setState({ selectedProvider: x });
-            }}
-          >
-            {renderSkipHelper()}
-          </GCPFormSection>
-        );
-      case "do":
-        return (
-          <DOFormSection
-            handleError={this.handleError}
-            projectName={projectName}
-            infras={infras}
-            highlightCosts={this.state.highlightCosts}
-            setSelectedProvisioner={(x: string | null) => {
-              this.setState({ selectedProvider: x });
-            }}
-          />
-        );
-      default:
-        return (
-          <ExistingClusterSection projectName={projectName}>
-            {renderSkipHelper()}
-          </ExistingClusterSection>
-        );
     }
     }
+
+    if (selectedProvider === "gcp") {
+      return (
+        <GCPFormSection
+          handleError={handleError}
+          projectName={projectName}
+          infras={infras}
+          highlightCosts={highlightCosts}
+          setSelectedProvisioner={(x: string | null) => {
+            handleSelectProvider(x);
+          }}
+          trackOnSave={() => trackOnSave(selectedProvider)}
+        >
+          {renderSkipHelper()}
+        </GCPFormSection>
+      );
+    }
+
+    if (selectedProvider === "do") {
+      return (
+        <DOFormSection
+          handleError={handleError}
+          projectName={projectName}
+          infras={infras}
+          highlightCosts={highlightCosts}
+          setSelectedProvisioner={(x: string | null) => {
+            handleSelectProvider(x);
+          }}
+          trackOnSave={() => trackOnSave(selectedProvider)}
+        />
+      );
+    }
+
+    return (
+      <ExistingClusterSection
+        projectName={projectName}
+        trackOnSave={() => trackOnSave(selectedProvider)}
+      >
+        {renderSkipHelper()}
+      </ExistingClusterSection>
+    );
   };
   };
 
 
-  renderFooter = () => {
-    let { selectedProvider } = this.state;
-    let { isInNewProject } = this.props;
-    let { provisioner } = this.props;
+  const renderFooter = () => {
     let helper = provisioner
     let helper = provisioner
       ? "Note: Provisioning can take up to 15 minutes"
       ? "Note: Provisioning can take up to 15 minutes"
       : "";
       : "";
@@ -154,9 +185,7 @@ class NewProject extends Component<PropsType, StateType> {
         <>
         <>
           <Helper>
           <Helper>
             Already have a Kubernetes cluster?
             Already have a Kubernetes cluster?
-            <Highlight
-              onClick={() => this.setState({ selectedProvider: "skipped" })}
-            >
+            <Highlight onClick={() => handleSelectProvider("skipped")}>
               Skip
               Skip
             </Highlight>
             </Highlight>
           </Helper>
           </Helper>
@@ -173,24 +202,7 @@ class NewProject extends Component<PropsType, StateType> {
     }
     }
   };
   };
 
 
-  componentDidMount() {
-    let { provisioner } = this.props;
-
-    if (!provisioner) {
-      this.setState({ selectedProvider: "skipped" });
-    }
-  }
-
-  componentDidUpdate(prevProps: PropsType) {
-    if (prevProps.provisioner !== this.props.provisioner) {
-      if (!this.props.provisioner) {
-        this.setState({ selectedProvider: "skipped" });
-      }
-    }
-  }
-
-  renderHelperText = () => {
-    let { isInNewProject, provisioner } = this.props;
+  const renderHelperText = () => {
     if (!provisioner) {
     if (!provisioner) {
       return;
       return;
     }
     }
@@ -206,61 +218,51 @@ class NewProject extends Component<PropsType, StateType> {
     }
     }
   };
   };
 
 
-  render() {
-    let { selectedProvider } = this.state;
-
-    return (
-      <StyledProvisionerSettings>
-        <Helper>{this.renderHelperText()}</Helper>
-        {!selectedProvider ? (
-          <BlockList>
-            {providers.map((provider: string, i: number) => {
-              let providerInfo = integrationList[provider];
-              return (
-                <Block
-                  key={i}
-                  onClick={() => {
-                    this.setState({
-                      selectedProvider: provider,
-                      highlightCosts: false,
-                    });
+  return (
+    <StyledProvisionerSettings>
+      <Helper>{renderHelperText()}</Helper>
+      {!selectedProvider ? (
+        <BlockList>
+          {providers.map((provider: string, i: number) => {
+            let providerInfo = integrationList[provider];
+            return (
+              <Block
+                key={i}
+                onClick={() => {
+                  handleSelectProvider(provider);
+                  setHighlightCosts(false);
+                }}
+              >
+                <Icon src={providerInfo.icon} />
+                <BlockTitle>{providerInfo.label}</BlockTitle>
+                <CostSection
+                  onClick={(e) => {
+                    e.stopPropagation();
+                    handleSelectProvider(provider);
+                    setHighlightCosts(true);
                   }}
                   }}
                 >
                 >
-                  <Icon src={providerInfo.icon} />
-                  <BlockTitle>{providerInfo.label}</BlockTitle>
-                  <CostSection
-                    onClick={(e) => {
-                      e.stopPropagation();
-                      this.setState({
-                        selectedProvider: provider,
-                        highlightCosts: true,
-                      });
-                    }}
-                  >
-                    {/*
-                    {provider == "aws" && "$205/Month"}
-                    {provider == "gcp" && "$250/Month"}
-                    {provider == "do" && "$90/Month"}
-                    <InfoTooltip text={""} />
-                    */}
-                  </CostSection>
-                  <BlockDescription>Hosted in your own cloud.</BlockDescription>
-                </Block>
-              );
-            })}
-          </BlockList>
-        ) : (
-          <>{this.renderSelectedProvider()}</>
-        )}
-        {this.renderFooter()}
-      </StyledProvisionerSettings>
-    );
-  }
-}
-
-NewProject.contextType = Context;
+                  {/*
+                  {provider == "aws" && "$205/Month"}
+                  {provider == "gcp" && "$250/Month"}
+                  {provider == "do" && "$90/Month"}
+                  <InfoTooltip text={""} />
+                  */}
+                </CostSection>
+                <BlockDescription>Hosted in your own cloud.</BlockDescription>
+              </Block>
+            );
+          })}
+        </BlockList>
+      ) : (
+        <>{renderSelectedProvider()}</>
+      )}
+      {renderFooter()}
+    </StyledProvisionerSettings>
+  );
+};
 
 
-export default withRouter(NewProject);
+export default ProvisionerSettings;
 
 
 const Br = styled.div`
 const Br = styled.div`
   width: 100%;
   width: 100%;