Jo Chuang 5 лет назад
Родитель
Сommit
410e44a43b

+ 19 - 15
dashboard/src/main/home/integrations/Integrations.tsx

@@ -1,6 +1,6 @@
 import GHIcon from "assets/GithubIcon";
 import React, { Component } from "react";
-import { RouteComponentProps, withRouter } from "react-router";
+import { Route, RouteComponentProps, Switch, withRouter } from "react-router";
 
 import api from "shared/api";
 import { integrationList } from "shared/common";
@@ -159,6 +159,24 @@ class Integrations extends Component<PropsType, StateType> {
       this.props.history.push("integrations");
     }
 
+    return (<Switch>
+      <Route path="/integrations/create/:integration" children={({ match }: any) => <div>{match.integration}</div>} />
+      <Route path="/integrations/category/:category" children={({ match }: any) => <div>{match.category}</div>} />
+      <Route>
+        <div>
+          <TitleSection>
+            <Title>Integrations</Title>
+          </TitleSection>
+
+          <IntegrationList
+            currentCategory={""}
+            integrations={["kubernetes", "registry", "repo"]}
+            setCurrent={(x: any) => this.props.history.push(setSearchParam(this.props.location, "category", x))}
+            isCategory={true}
+          />
+        </div>
+      </Route>
+    </Switch>)
     // TODO: Split integration page into separate component / deprecate this flow
     if (currentIntegration) {
       let icon =
@@ -279,20 +297,6 @@ class Integrations extends Component<PropsType, StateType> {
         );
       }
     }
-    return (
-      <div>
-        <TitleSection>
-          <Title>Integrations</Title>
-        </TitleSection>
-
-        <IntegrationList
-          currentCategory={""}
-          integrations={["kubernetes", "registry", "repo"]}
-          setCurrent={(x: any) => this.props.history.push(setSearchParam(this.props.location, "category", x))}
-          isCategory={true}
-        />
-      </div>
-    );
   };
 
   render() {

+ 105 - 0
dashboard/src/main/home/integrations/edit-integration/DockerHubForm.tsx

@@ -0,0 +1,105 @@
+import React, { Component } from "react";
+import styled from "styled-components";
+
+import InputRow from "components/values-form/InputRow";
+import SaveButton from "components/SaveButton";
+
+type PropsType = {
+  closeForm: () => void;
+};
+
+type StateType = {
+  registryURL: string;
+  dockerEmail: string;
+  dockerUsername: string;
+  dockerPassword: string;
+};
+
+export default class DockerHubForm extends Component<PropsType, StateType> {
+  state = {
+    registryURL: "",
+    dockerEmail: "",
+    dockerUsername: "",
+    dockerPassword: "",
+  };
+
+  isDisabled = (): boolean => {
+    let {
+      registryURL,
+      dockerEmail,
+      dockerUsername,
+      dockerPassword,
+    } = this.state;
+    if (
+      registryURL === "" ||
+      dockerEmail === "" ||
+      dockerUsername === "" ||
+      dockerPassword === ""
+    ) {
+      return true;
+    }
+    return false;
+  };
+
+  handleSubmit = () => {
+    // TODO: implement once api is restructured
+  };
+
+  render() {
+    return (
+      <StyledForm>
+        <CredentialWrapper>
+          <InputRow
+            type="text"
+            value={this.state.registryURL}
+            setValue={(x: string) => this.setState({ registryURL: x })}
+            label="📦 Registry URL"
+            placeholder="ex: index.docker.io"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.dockerEmail}
+            setValue={(x: string) => this.setState({ dockerEmail: x })}
+            label="✉️ Docker Email"
+            placeholder="ex: captain@ahab.com"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.dockerUsername}
+            setValue={(x: string) => this.setState({ dockerUsername: x })}
+            label="👤 Docker Username"
+            placeholder="ex: whale_watcher_2000"
+            width="100%"
+          />
+          <InputRow
+            type="password"
+            value={this.state.dockerPassword}
+            setValue={(x: string) => this.setState({ dockerPassword: x })}
+            label="🔒 Docker Password"
+            placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
+            width="100%"
+          />
+        </CredentialWrapper>
+        <SaveButton
+          text="Save Settings"
+          makeFlush={true}
+          disabled={this.isDisabled()}
+          onClick={this.isDisabled() ? null : this.handleSubmit}
+        />
+      </StyledForm>
+    );
+  }
+}
+
+const CredentialWrapper = styled.div`
+  padding: 5px 40px 25px;
+  background: #ffffff11;
+  border-radius: 5px;
+`;
+
+const StyledForm = styled.div`
+  position: relative;
+  padding-bottom: 75px;
+`;

+ 139 - 0
dashboard/src/main/home/integrations/edit-integration/ECRForm.tsx

@@ -0,0 +1,139 @@
+import React, { Component } from "react";
+import styled from "styled-components";
+
+import { Context } from "shared/Context";
+import api from "shared/api";
+
+import InputRow from "components/values-form/InputRow";
+import SaveButton from "components/SaveButton";
+import Heading from "components/values-form/Heading";
+import Helper from "components/values-form/Helper";
+
+type PropsType = {
+  closeForm: () => void;
+};
+
+type StateType = {
+  credentialsName: string;
+  awsRegion: string;
+  awsAccessId: string;
+  awsSecretKey: string;
+};
+
+export default class ECRForm extends Component<PropsType, StateType> {
+  state = {
+    credentialsName: "",
+    awsRegion: "",
+    awsAccessId: "",
+    awsSecretKey: "",
+  };
+
+  isDisabled = (): boolean => {
+    let { awsRegion, awsAccessId, awsSecretKey, credentialsName } = this.state;
+    if (
+      awsRegion === "" ||
+      awsAccessId === "" ||
+      awsSecretKey === "" ||
+      credentialsName === ""
+    ) {
+      return true;
+    }
+    return false;
+  };
+
+  catchErr = (err: any) => console.log(err);
+
+  handleSubmit = () => {
+    let { awsRegion, awsAccessId, awsSecretKey, credentialsName } = this.state;
+    let { currentProject } = this.context;
+
+    api
+      .createAWSIntegration(
+        "<token>",
+        {
+          aws_region: awsRegion,
+          aws_access_key_id: awsAccessId,
+          aws_secret_access_key: awsSecretKey,
+        },
+        { id: currentProject.id }
+      )
+      .then((res) =>
+        api.connectECRRegistry(
+          "<token>",
+          {
+            name: credentialsName,
+            aws_integration_id: res.data.id,
+          },
+          { id: currentProject.id }
+        )
+      )
+      .then(() => this.props.closeForm())
+      .catch(this.catchErr);
+  };
+
+  render() {
+    return (
+      <StyledForm>
+        <CredentialWrapper>
+          <Heading>Porter Settings</Heading>
+          <Helper>
+            Give a name to this set of registry credentials (just for Porter).
+          </Helper>
+          <InputRow
+            type="text"
+            value={this.state.credentialsName}
+            setValue={(x: string) => this.setState({ credentialsName: x })}
+            label="🏷️ Registry Name"
+            placeholder="ex: paper-straw"
+            width="100%"
+          />
+          <Heading>AWS Settings</Heading>
+          <Helper>AWS access credentials.</Helper>
+          <InputRow
+            type="text"
+            value={this.state.awsRegion}
+            setValue={(x: string) => this.setState({ awsRegion: x })}
+            label="📍 AWS Region"
+            placeholder="ex: mars-north-12"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.awsAccessId}
+            setValue={(x: string) => this.setState({ awsAccessId: x })}
+            label="👤 AWS Access ID"
+            placeholder="ex: AKIAIOSFODNN7EXAMPLE"
+            width="100%"
+          />
+          <InputRow
+            type="password"
+            value={this.state.awsSecretKey}
+            setValue={(x: string) => this.setState({ awsSecretKey: x })}
+            label="🔒 AWS Secret Key"
+            placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
+            width="100%"
+          />
+        </CredentialWrapper>
+        <SaveButton
+          text="Save Settings"
+          makeFlush={true}
+          disabled={this.isDisabled()}
+          onClick={this.isDisabled() ? null : this.handleSubmit}
+        />
+      </StyledForm>
+    );
+  }
+}
+
+ECRForm.contextType = Context;
+
+const CredentialWrapper = styled.div`
+  padding: 5px 40px 25px;
+  background: #ffffff11;
+  border-radius: 5px;
+`;
+
+const StyledForm = styled.div`
+  position: relative;
+  padding-bottom: 75px;
+`;

+ 124 - 0
dashboard/src/main/home/integrations/edit-integration/EKSForm.tsx

@@ -0,0 +1,124 @@
+import React, { Component } from "react";
+import styled from "styled-components";
+
+import InputRow from "components/values-form/InputRow";
+import TextArea from "components/values-form/TextArea";
+import SaveButton from "components/SaveButton";
+import Heading from "components/values-form/Heading";
+import Helper from "components/values-form/Helper";
+
+type PropsType = {
+  closeForm: () => void;
+};
+
+type StateType = {
+  clusterName: string;
+  clusterEndpoint: string;
+  clusterCA: string;
+  awsAccessId: string;
+  awsSecretKey: string;
+};
+
+export default class EKSForm extends Component<PropsType, StateType> {
+  state = {
+    clusterName: "",
+    clusterEndpoint: "",
+    clusterCA: "",
+    awsAccessId: "",
+    awsSecretKey: "",
+  };
+
+  isDisabled = (): boolean => {
+    let {
+      clusterName,
+      clusterEndpoint,
+      clusterCA,
+      awsAccessId,
+      awsSecretKey,
+    } = this.state;
+    if (
+      clusterName === "" ||
+      clusterEndpoint === "" ||
+      clusterCA === "" ||
+      awsAccessId === "" ||
+      awsSecretKey === ""
+    ) {
+      return true;
+    }
+    return false;
+  };
+
+  handleSubmit = () => {
+    // TODO: implement once api is restructured
+  };
+
+  render() {
+    return (
+      <StyledForm>
+        <CredentialWrapper>
+          <Heading>Cluster Settings</Heading>
+          <Helper>Credentials for accessing your GKE cluster.</Helper>
+          <InputRow
+            type="text"
+            value={this.state.clusterName}
+            setValue={(x: string) => this.setState({ clusterName: x })}
+            label="🏷️ Cluster Name"
+            placeholder="ex: briny-pagelet"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.clusterEndpoint}
+            setValue={(x: string) => this.setState({ clusterEndpoint: x })}
+            label="🌐 Cluster Endpoint"
+            placeholder="ex: 00.00.000.00"
+            width="100%"
+          />
+          <TextArea
+            value={this.state.clusterCA}
+            setValue={(x: string) => this.setState({ clusterCA: x })}
+            label="🔏 Cluster Certificate"
+            placeholder="(Paste your certificate here)"
+            width="100%"
+          />
+
+          <Heading>AWS Settings</Heading>
+          <Helper>AWS access credentials.</Helper>
+          <InputRow
+            type="text"
+            value={this.state.awsAccessId}
+            setValue={(x: string) => this.setState({ awsAccessId: x })}
+            label="👤 AWS Access ID"
+            placeholder="ex: AKIAIOSFODNN7EXAMPLE"
+            width="100%"
+          />
+          <InputRow
+            type="password"
+            value={this.state.awsSecretKey}
+            setValue={(x: string) => this.setState({ awsSecretKey: x })}
+            label="🔒 AWS Secret Key"
+            placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
+            width="100%"
+          />
+        </CredentialWrapper>
+        <SaveButton
+          text="Save Settings"
+          makeFlush={true}
+          disabled={this.isDisabled()}
+          onClick={this.isDisabled() ? null : this.handleSubmit}
+        />
+      </StyledForm>
+    );
+  }
+}
+
+const CredentialWrapper = styled.div`
+  padding: 5px 40px 25px;
+  background: #ffffff11;
+  border-radius: 5px;
+`;
+
+const StyledForm = styled.div`
+  position: relative;
+  padding-bottom: 75px;
+`;

+ 35 - 0
dashboard/src/main/home/integrations/edit-integration/EditIntegrationForm.tsx

@@ -0,0 +1,35 @@
+import React, { Component } from "react";
+
+import DockerHubForm from "./DockerHubForm";
+import GKEForm from "./GKEForm";
+import EKSForm from "./EKSForm";
+import GCRForm from "./GCRForm";
+import ECRForm from "./ECRForm";
+
+type PropsType = {
+  integrationName: string;
+  closeForm: () => void;
+};
+
+type StateType = {};
+
+export default class CreateIntegrationForm extends Component<PropsType, StateType> {
+  state = {};
+
+  render = () => {
+    switch (this.props.integrationName) {
+      case "docker-hub":
+        return <DockerHubForm closeForm={this.props.closeForm} />;
+      case "gke":
+        return <GKEForm closeForm={this.props.closeForm} />;
+      case "eks":
+        return <EKSForm closeForm={this.props.closeForm} />;
+      case "ecr":
+        return <ECRForm closeForm={this.props.closeForm} />;
+      case "gcr":
+        return <GCRForm closeForm={this.props.closeForm} />;
+      default:
+        return null;
+    }
+  }
+}

+ 165 - 0
dashboard/src/main/home/integrations/edit-integration/GCRForm.tsx

@@ -0,0 +1,165 @@
+import React, { Component } from "react";
+import styled from "styled-components";
+
+import { Context } from "shared/Context";
+import api from "shared/api";
+
+import InputRow from "components/values-form/InputRow";
+import TextArea from "components/values-form/TextArea";
+import SaveButton from "components/SaveButton";
+import Heading from "components/values-form/Heading";
+import Helper from "components/values-form/Helper";
+
+type PropsType = {
+  closeForm: () => void;
+};
+
+type StateType = {
+  credentialsName: string;
+  gcpRegion: string;
+  serviceAccountKey: string;
+  gcpProjectID: string;
+  url: string;
+};
+
+export default class GCRForm extends Component<PropsType, StateType> {
+  state = {
+    credentialsName: "",
+    gcpRegion: "",
+    serviceAccountKey: "",
+    gcpProjectID: "",
+    url: "",
+  };
+
+  isDisabled = (): boolean => {
+    let {
+      credentialsName,
+      gcpRegion,
+      gcpProjectID,
+      serviceAccountKey,
+    } = this.state;
+    if (
+      credentialsName === "" ||
+      gcpRegion === "" ||
+      serviceAccountKey === "" ||
+      gcpProjectID === ""
+    ) {
+      return true;
+    }
+    return false;
+  };
+
+  catchError = (err: any) => console.log(err);
+
+  handleSubmit = () => {
+    let { currentProject } = this.context;
+
+    api
+      .createGCPIntegration(
+        "<token>",
+        {
+          gcp_region: this.state.gcpRegion,
+          gcp_key_data: this.state.serviceAccountKey,
+          gcp_project_id: this.state.gcpProjectID,
+        },
+        {
+          project_id: currentProject.id,
+        }
+      )
+      .then((res) =>
+        api.connectGCRRegistry(
+          "<token>",
+          {
+            name: this.state.credentialsName,
+            gcp_integration_id: res.data.id,
+            url: this.state.url,
+          },
+          {
+            id: currentProject.id,
+          }
+        )
+      )
+      .then((res) => {
+        console.log(res.data);
+        this.props.closeForm();
+      })
+      .catch(this.catchError);
+  };
+
+  render() {
+    return (
+      <StyledForm>
+        <CredentialWrapper>
+          <Heading>Porter Settings</Heading>
+          <Helper>
+            Give a name to this set of registry credentials (just for Porter).
+          </Helper>
+          <InputRow
+            type="text"
+            value={this.state.credentialsName}
+            setValue={(credentialsName: string) =>
+              this.setState({ credentialsName })
+            }
+            label="🏷️ Registry Name"
+            placeholder="ex: paper-straw"
+            width="100%"
+          />
+          <Heading>GCP Settings</Heading>
+          <Helper>Service account credentials for GCP permissions.</Helper>
+          <InputRow
+            type="text"
+            value={this.state.gcpRegion}
+            setValue={(gcpRegion: string) => this.setState({ gcpRegion })}
+            label="📍 GCP Region"
+            placeholder="ex: uranus-north3"
+            width="100%"
+          />
+          <TextArea
+            value={this.state.serviceAccountKey}
+            setValue={(serviceAccountKey: string) =>
+              this.setState({ serviceAccountKey })
+            }
+            label="🔑 Service Account Key (JSON)"
+            placeholder="(Paste your JSON service account key here)"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.gcpProjectID}
+            setValue={(gcpProjectID: string) => this.setState({ gcpProjectID })}
+            label="📝 GCP Project ID"
+            placeholder="ex: skynet-dev-172969"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.url}
+            setValue={(url: string) => this.setState({ url })}
+            label="🔗 GCR URL"
+            placeholder="ex: gcr.io/skynet-dev-172969"
+            width="100%"
+          />
+        </CredentialWrapper>
+        <SaveButton
+          text="Save Settings"
+          makeFlush={true}
+          disabled={this.isDisabled()}
+          onClick={this.isDisabled() ? null : this.handleSubmit}
+        />
+      </StyledForm>
+    );
+  }
+}
+
+GCRForm.contextType = Context;
+
+const CredentialWrapper = styled.div`
+  padding: 5px 40px 25px;
+  background: #ffffff11;
+  border-radius: 5px;
+`;
+
+const StyledForm = styled.div`
+  position: relative;
+  padding-bottom: 75px;
+`;

+ 111 - 0
dashboard/src/main/home/integrations/edit-integration/GKEForm.tsx

@@ -0,0 +1,111 @@
+import React, { Component } from "react";
+import styled from "styled-components";
+
+import InputRow from "components/values-form/InputRow";
+import TextArea from "components/values-form/TextArea";
+import SaveButton from "components/SaveButton";
+import Heading from "components/values-form/Heading";
+import Helper from "components/values-form/Helper";
+
+type PropsType = {
+  closeForm: () => void;
+};
+
+type StateType = {
+  clusterName: string;
+  clusterEndpoint: string;
+  clusterCA: string;
+  serviceAccountKey: string;
+};
+
+export default class GKEForm extends Component<PropsType, StateType> {
+  state = {
+    clusterName: "",
+    clusterEndpoint: "",
+    clusterCA: "",
+    serviceAccountKey: "",
+  };
+
+  isDisabled = (): boolean => {
+    let {
+      clusterName,
+      clusterEndpoint,
+      clusterCA,
+      serviceAccountKey,
+    } = this.state;
+    if (
+      clusterName === "" ||
+      clusterEndpoint === "" ||
+      clusterCA === "" ||
+      serviceAccountKey === ""
+    ) {
+      return true;
+    }
+    return false;
+  };
+
+  handleSubmit = () => {
+    // TODO: implement once api is restructured
+  };
+
+  render() {
+    return (
+      <StyledForm>
+        <CredentialWrapper>
+          <Heading>Cluster Settings</Heading>
+          <Helper>Credentials for accessing your GKE cluster.</Helper>
+          <InputRow
+            type="text"
+            value={this.state.clusterName}
+            setValue={(x: string) => this.setState({ clusterName: x })}
+            label="🏷️ Cluster Name"
+            placeholder="ex: briny-pagelet"
+            width="100%"
+          />
+          <InputRow
+            type="text"
+            value={this.state.clusterEndpoint}
+            setValue={(x: string) => this.setState({ clusterEndpoint: x })}
+            label="🌐 Cluster Endpoint"
+            placeholder="ex: 00.00.000.00"
+            width="100%"
+          />
+          <TextArea
+            value={this.state.clusterCA}
+            setValue={(x: string) => this.setState({ clusterCA: x })}
+            label="🔏 Cluster Certificate"
+            placeholder="(Paste your certificate here)"
+            width="100%"
+          />
+
+          <Heading>GCP Settings</Heading>
+          <Helper>Service account credentials for GCP permissions.</Helper>
+          <TextArea
+            value={this.state.serviceAccountKey}
+            setValue={(x: string) => this.setState({ serviceAccountKey: x })}
+            label="🔑 Service Account Key (JSON)"
+            placeholder="(Paste your JSON service account key here)"
+            width="100%"
+          />
+        </CredentialWrapper>
+        <SaveButton
+          text="Save Settings"
+          makeFlush={true}
+          disabled={this.isDisabled()}
+          onClick={this.isDisabled() ? null : this.handleSubmit}
+        />
+      </StyledForm>
+    );
+  }
+}
+
+const CredentialWrapper = styled.div`
+  padding: 5px 40px 25px;
+  background: #ffffff11;
+  border-radius: 5px;
+`;
+
+const StyledForm = styled.div`
+  position: relative;
+  padding-bottom: 75px;
+`;