Просмотр исходного кода

Initialized component to display and select buildpack

jnfrati 4 лет назад
Родитель
Сommit
9ee82d512d
1 измененных файлов с 215 добавлено и 41 удалено
  1. 215 41
      dashboard/src/components/repo-selector/ActionDetails.tsx

+ 215 - 41
dashboard/src/components/repo-selector/ActionDetails.tsx

@@ -1,4 +1,10 @@
-import React, { Component, useContext, useEffect, useState } from "react";
+import React, {
+  Component,
+  useContext,
+  useEffect,
+  useMemo,
+  useState,
+} from "react";
 import styled, { keyframes } from "styled-components";
 
 import { integrationList } from "shared/common";
@@ -26,6 +32,23 @@ type PropsType = {
   setFolderPath: (x: string) => void;
 };
 
+type Buildpack = {
+  name: string;
+  buildpack: string;
+  config: {
+    [key: string]: string;
+  };
+};
+
+type DetectedBuildpack = {
+  name: string;
+  builders: string[];
+  detected: Buildpack[];
+  others: Buildpack[];
+};
+
+type DetectBuildpackResponse = DetectedBuildpack[];
+
 const ActionDetails: React.FC<PropsType> = (props) => {
   const {
     actionConfig,
@@ -43,13 +66,14 @@ const ActionDetails: React.FC<PropsType> = (props) => {
   } = props;
 
   const { currentProject } = useContext(Context);
-
-  const [dockerRepo, setDockerRepo] = useState("");
-  const [error, setError] = useState(false);
   const [registries, setRegistries] = useState<any[]>(null);
   const [loading, setLoading] = useState(true);
-  const [builders, setBuilders] = useState<any[]>(null);
+  const [buildersOptions, setBuildersOptions] = useState<[]>(null);
   const [currentBuilder, setCurrentBuilder] = useState(null);
+  const [availableBuildpacks, setAvailableBuildpacks] = useState(null);
+  const [availableStacks, setAvailableStacks] = useState(null);
+  const [selectedStack, setSelectedStack] = useState(null);
+  const [selectedBuildpacks, setSelectedBuildpacks] = useState(null);
 
   useEffect(() => {
     const project_id = currentProject.id;
@@ -114,29 +138,6 @@ const ActionDetails: React.FC<PropsType> = (props) => {
     }
   };
 
-  const renderBuildpacksList = () => {
-    const buildpackName = "Node.js";
-    return (
-      <StyledCard onClick={() => console.log("some")} status={"some"}>
-        <ContentContainer>
-          <Icon className="devicon-nodejs-plain colored" />
-
-          <EventInformation>
-            <EventName>
-              <Helper></Helper>
-              {buildpackName}
-            </EventName>
-          </EventInformation>
-        </ContentContainer>
-        <ActionContainer>
-          <DeleteButton>
-            <span className="material-icons">delete</span>
-          </DeleteButton>
-        </ActionContainer>
-      </StyledCard>
-    );
-  };
-
   return (
     <>
       <DarkMatter />
@@ -171,19 +172,14 @@ const ActionDetails: React.FC<PropsType> = (props) => {
         value={folderPath}
       />
       {renderRegistrySection()}
-
-      <Selector
-        activeValue={currentBuilder}
-        width="100%"
-        options={builders}
-        setActiveValue={(option) => setCurrentBuilder(option)}
-      />
-
-      <Heading>Buildpacks</Heading>
-      <Helper>
-        These are automatically detected buildpacks but you can change them if
-        you want
-      </Helper>
+      {!dockerfilePath && (
+        <BuildpackSelection
+          actionConfig={actionConfig}
+          branch={branch}
+          folderPath={folderPath}
+          onChange={(config) => {}}
+        />
+      )}
       <Br />
 
       <Flex>
@@ -217,6 +213,184 @@ const ActionDetails: React.FC<PropsType> = (props) => {
 
 export default ActionDetails;
 
+const DEFAULT_BUILDER_NAME = "paketo";
+const DEFAULT_PAKETO_STACK = "paketobuildpacks/builder:full";
+const DEFAULT_HEROKU_STACK = "heroku:20";
+
+type BuildConfig = {
+  builder: string;
+  buildpacks: string[];
+  config: null | {
+    [key: string]: string;
+  };
+};
+
+const BuildpackSelection: React.FC<{
+  actionConfig: ActionConfigType;
+  folderPath: string;
+  branch: string;
+  onChange: (config: BuildConfig) => void;
+}> = ({ actionConfig, folderPath, branch }) => {
+  const { currentProject } = useContext(Context);
+
+  const [builders, setBuilders] = useState<DetectedBuildpack[]>(null);
+  const [selectedBuilder, setSelectedBuilder] = useState<string>(null);
+
+  const [stacks, setStacks] = useState<string[]>(null);
+  const [selectedStack, setSelectedStack] = useState<string>(null);
+
+  const [selectedBuildpacks, setSelectedBuildpacks] = useState<Buildpack[]>(
+    null
+  );
+  const [availableBuildpacks, setAvailableBuildpacks] = useState<Buildpack[]>(
+    null
+  );
+
+  useEffect(() => {
+    api
+      .detectBuildpack<DetectBuildpackResponse>(
+        "<token>",
+        {
+          dir: folderPath || ".",
+        },
+        {
+          project_id: currentProject.id,
+          git_repo_id: actionConfig.git_repo_id,
+          kind: "github",
+          owner: actionConfig.git_repo.split("/")[0],
+          name: actionConfig.git_repo.split("/")[1],
+          branch: branch,
+        }
+      )
+      .then(({ data }) => {
+        const builders = data;
+
+        const defaultBuilder = builders.find(
+          (builder) => builder.name.toLowerCase() === DEFAULT_BUILDER_NAME
+        );
+
+        const detectedBuildpacks = defaultBuilder.detected;
+        const availableBuildpacks = defaultBuilder.others;
+        const defaultStack = defaultBuilder.builders.find((stack) => {
+          return (
+            stack === DEFAULT_HEROKU_STACK || stack === DEFAULT_PAKETO_STACK
+          );
+        });
+
+        setBuilders(builders);
+        setSelectedBuilder(defaultBuilder.name);
+
+        setStacks(defaultBuilder.builders);
+        setSelectedStack(defaultStack);
+
+        setSelectedBuildpacks(detectedBuildpacks);
+        setAvailableBuildpacks(availableBuildpacks);
+      })
+      .catch((err) => {
+        console.error(err);
+      });
+  }, [currentProject, actionConfig]);
+
+  const builderOptions = useMemo(() => {
+    if (!Array.isArray(builders)) {
+      return;
+    }
+
+    return builders.map((builder) => ({
+      label: builder.name,
+      value: builder.name.toLowerCase(),
+    }));
+  }, [builders]);
+
+  const stackOptions = useMemo(() => {
+    if (!Array.isArray(stacks)) {
+      return;
+    }
+
+    return stacks.map((stack) => ({
+      label: stack,
+      value: stack.toLowerCase(),
+    }));
+  }, [stacks]);
+
+  const renderBuildpacksList = (buildpacks: Buildpack[]) => {
+    return buildpacks.map((buildpack) => {
+      const icon = `devicon-${buildpack?.name?.toLowerCase()}-plain colored`;
+
+      return (
+        <StyledCard onClick={() => console.log("some")} status={"some"}>
+          <ContentContainer>
+            <Icon className={icon} />
+            <EventInformation>
+              <EventName>{buildpack?.name}</EventName>
+            </EventInformation>
+          </ContentContainer>
+          <ActionContainer>
+            <DeleteButton
+              onClick={() => handleRemoveBuildpack(buildpack.buildpack)}
+            >
+              <span className="material-icons">delete</span>
+            </DeleteButton>
+          </ActionContainer>
+        </StyledCard>
+      );
+    });
+  };
+
+  const handleRemoveBuildpack = (buildpackToRemove: string) => {
+    setSelectedBuildpacks((selBuildpacks) => {
+      const tmpSelectedBuildpacks = [...selBuildpacks];
+
+      const indexBuildpackToRemove = tmpSelectedBuildpacks.findIndex(
+        (buildpack) => buildpack.buildpack === buildpackToRemove
+      );
+      const buildpack = tmpSelectedBuildpacks[indexBuildpackToRemove];
+
+      setAvailableBuildpacks((availableBuildpacks) => [
+        ...availableBuildpacks,
+        buildpack,
+      ]);
+
+      tmpSelectedBuildpacks.splice(indexBuildpackToRemove, 1);
+
+      return [...tmpSelectedBuildpacks];
+    });
+  };
+
+  // const handleAddBuildpack = (buildpackToAdd: string) => {
+  //   setAvailableBuildpacks((avBuildpacks) => {
+  //     const tmpAvailableBuildpacks = [...avBuildpacks];
+  //     return []
+  //   })
+  // }
+
+  return (
+    <>
+      <>
+        <Selector
+          activeValue={selectedBuilder}
+          width="100%"
+          options={builderOptions}
+          setActiveValue={(option) => setSelectedBuilder(option)}
+        />
+        <Selector
+          activeValue={selectedStack}
+          width="100%"
+          options={stackOptions}
+          setActiveValue={(option) => setSelectedStack(option)}
+        />
+        <Heading>Buildpacks</Heading>
+        <Helper>
+          These are automatically detected buildpacks but you can change them if
+          you want
+        </Helper>
+
+        {renderBuildpacksList(availableBuildpacks)}
+      </>
+    </>
+  );
+};
+
 const Required = styled.div`
   margin-left: 8px;
   color: #fc4976;