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

call stack create and add service modal stub

Justin Rhee 3 лет назад
Родитель
Сommit
317b40a26a

+ 1 - 0
api/server/handlers/stacks/create.go

@@ -31,6 +31,7 @@ func NewCreateStackHandler(
 }
 
 func (c *CreateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	fmt.Println("welcome to create stack handler")
 	ctx := r.Context()
 	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
 

+ 2 - 1
dashboard/src/components/YamlEditor.tsx

@@ -44,7 +44,7 @@ class YamlEditor extends Component<PropsType, StateType> {
       <Holder>
         <Editor onSubmit={this.handleSubmit} border={this.props.border}>
           <AceEditor
-            mode="yaml"
+            // mode="yaml"
             value={this.props.value}
             theme="porter"
             onChange={this.props.onChange}
@@ -79,6 +79,7 @@ const Holder = styled.div`
   }
   .ace_editor,
   .ace_editor * {
+    color: #aaaabb;
     font-family: "Monaco", "Menlo", "Ubuntu Mono", "Droid Sans Mono", "Consolas",
       monospace !important;
     font-size: 12px !important;

+ 12 - 3
dashboard/src/components/porter/Modal.tsx

@@ -81,18 +81,27 @@ const ModalBg = styled.div`
   width: 100vw;
   height: 100vh;
   background-color: rgba(0, 0, 0, 0.6);
+  animation: fadeInModal 0.5s 0s;
+  @keyframes fadeInModal {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
 `;
 
 const StyledModal = styled.div`
   position: relative;
   padding: 25px;
-  padding-bottom: 30px;
+  padding-bottom: 35px;
   border-radius: 10px;
   border: 1px solid #494b4f;
   font-size: 13px;
   width: 600px;
-  background: #42444944;
-  backdrop-filter: saturate(150%) blur(10px);
+  background: #42444933;
+  backdrop-filter: saturate(150%) blur(8px);
 
   animation: floatInModal 0.5s 0s;
   @keyframes floatInModal {

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

@@ -114,6 +114,7 @@ const StyledSelect = styled.select<{
   color: #ffffff;
   font-size: 13px;
   outline: none;
+  cursor: pointer;
   border-radius: 5px;
   background: none;
   appearance: none;

+ 2 - 1
dashboard/src/main/home/add-on-dashboard/ConfigureTemplate.tsx

@@ -75,7 +75,8 @@ const ConfigureTemplate: React.FC<Props> = ({
     for (let key in wildcard) {
       _.set(values, key, wildcard[key]);
     }
-
+    console.log("values", values)
+    console.log("wildcard", wildcard)
     api
       .deployAddon(
         "<token>",

+ 95 - 17
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -68,7 +68,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
   const [templateName, setTemplateName] = useState("");
 
   const [imageUrl, setImageUrl] = useState("");
-  const [imageTag, setImageTag] = useState("");
+  const [imageTag, setImageTag] = useState("latest");
   const { currentCluster, currentProject } = useContext(Context);
   const [isLoading, setIsLoading] = useState<boolean>(true);
   const [currentStep, setCurrentStep] = useState<number>(0);
@@ -101,6 +101,81 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
   };
   const [showGHAModal, setShowGHAModal] = useState<boolean>(false);
 
+  const deployPorterApp = async () => {
+    const dummyPorterAppConfig = {
+      "daft-web": {                        
+        image: {
+          repository: "public.ecr.aws/o1j4x7p4/hello-porter",
+          tag: "latest"
+        },  
+        ingress: {
+          enabled: false
+        },
+      },
+      "daft-worker-1": {                        
+        image: {
+          repository: "public.ecr.aws/o1j4x7p4/hello-porter",
+          tag: "latest"
+        },  
+      },
+      "daft-worker-2": {                        
+        image: {
+          repository: "public.ecr.aws/o1j4x7p4/hello-porter",
+          tag: "latest"
+        },  
+      },
+      "daft-release": {                        
+        image: {
+          repository: "public.ecr.aws/o1j4x7p4/hello-porter",
+          tag: "latest"
+        },  
+      },
+    };
+    
+    try {
+      const res = await api.updatePorterStack(
+        '<token>',
+        {
+          stack_name: formState.applicationName,
+          values: dummyPorterAppConfig,
+          dependencies: [
+            {
+              name: "web",
+              alias: "daft-web",
+              version: "0.88",
+              repository: "https://charts.getporter.dev"
+            },
+            {
+              name: "web",
+              alias: "daft-worker-1",
+              version: "0.38",
+              repository: "https://charts.getporter.dev"
+            },
+            {
+              name: "web",
+              alias: "daft-worker-2",
+              version: "0.38",
+              repository: "https://charts.getporter.dev"
+            },
+            {
+              name: "job",
+              alias: "daft-release",
+              version: "0.37",
+              repository: "https://charts.getporter.dev"
+            },
+          ],
+        },
+        {
+          cluster_id: currentCluster.id,
+          project_id: currentProject.id,
+        }
+      );
+      console.log(res);
+    } catch (error) {
+      console.log(error);
+    }
+  };
+
   return (
     <CenterWrapper>
       <Div>
@@ -152,17 +227,15 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
                   selectedSourceType={formState.selectedSourceType}
                   setSourceType={(type) => {
                     setFormState({ ...formState, selectedSourceType: type });
-                    if (Validators.selectedSourceType(type)) {
-                      setCurrentStep(Math.max(currentStep, 2));
-                    }
                   }}
                 />
                 <SourceSettings
                   source={formState.selectedSourceType}
-                  templateName={templateName}
-                  setTemplateName={setTemplateName}
                   imageUrl={imageUrl}
-                  setImageUrl={setImageUrl}
+                  setImageUrl={(x) => {
+                    setImageUrl(x);
+                    setCurrentStep(Math.max(currentStep, 2));
+                  }}
                   imageTag={imageTag}
                   setImageTag={setImageTag}
                   actionConfig={actionConfig}
@@ -171,17 +244,12 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
                   setBranch={setBranch}
                   procfileProcess={procfileProcess}
                   setProcfileProcess={setProcfileProcess}
-                  repoType={repoType}
-                  setRepoType={setRepoType}
                   dockerfilePath={dockerfilePath}
                   setDockerfilePath={setDockerfilePath}
                   folderPath={folderPath}
                   setFolderPath={setFolderPath}
                   procfilePath={procfilePath}
                   setProcfilePath={setProcfilePath}
-                  selectedRegistry={selectedRegistry}
-                  setSelectedRegistry={setSelectedRegistry}
-                  setBuildConfig={setBuildConfig}
                 />
               </>,
               <>
@@ -198,19 +266,20 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
                 />
               </>,
               <>
-                <Text size={16}>Environment variables</Text>
+                <Text size={16}>Environment variables (optional)</Text>
                 <Spacer y={0.5} />
                 <Text color="helper">
                   Specify environment variables shared among all services.
                 </Text>
                 <EnvGroupArray
                   values={formState.envVariables}
-                  setValues={(x: any) =>
-                    setFormState({ ...formState, envVariables: x })
-                  }
+                  setValues={(x: any) => {
+                    setFormState({ ...formState, envVariables: x });
+                  }}
                   fileUpload={true}
                 />
               </>,
+              /*
               <>
                 <Text size={16}>Release command (optional)</Text>
                 <Spacer y={0.5} />
@@ -226,7 +295,16 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
                   setValue={(e) => {}}
                 />
               </>,
-              <Button onClick={() => setShowGHAModal(true)}>Deploy app</Button>
+              */
+              <Button onClick={() => {
+                if (imageUrl) {
+                  deployPorterApp();
+                } else {
+                  setShowGHAModal(true);
+                }
+              }}>
+                Deploy app
+              </Button>
             ]}
           />
           <Spacer y={3} />

+ 64 - 124
dashboard/src/main/home/app-dashboard/new-app-flow/Service.tsx

@@ -5,137 +5,83 @@ import styled from "styled-components";
 import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import web from "assets/web.png";
+import TabSelector from "components/TabSelector";
 
 
 interface ServiceProps {
-    serviceData: ServiceType;
-    editService: (service: ServiceType) => void;
-    deleteService: () => void;
+  serviceData: ServiceType;
+  editService: (service: ServiceType) => void;
+  deleteService: () => void;
 }
 
 export type ServiceType = {
-    name: string;
-    type: string;
-    runCommand: string;
-    ram: number;
-    cpu: number;
+  name: string;
+  type: string;
+  runCommand: string;
+  ram: number;
+  cpu: number;
 }
 
 export const DEFAULT_SERVICE: ServiceType = {
-    name: 'new-service',
-    type: '',
-    runCommand: '',
-    ram: 512,
-    cpu: 500,
+  name: 'new-service',
+  type: '',
+  runCommand: '',
+  ram: 512,
+  cpu: 500,
 }
 
 const Service: React.FC<ServiceProps> = ({
-    serviceData,
-    deleteService,
-    editService,
+  serviceData,
+  deleteService,
+  editService,
 }) => {
-    const [showExpanded, setShowExpanded] = React.useState<boolean>(true)
-
-    const renderServiceSettings = () => {
-        return (
-            <>
-                <Text color="helper">
-                    Name your service.
-                </Text>
-                <Spacer y={0.5} />
-                <Input
-                    placeholder="ex: web-service"
-                    value={serviceData.name}
-                    width="300px"
-                    setValue={(e) => {
-                        editService({ ...serviceData, name: e })
-                    }}
-                />
-                <Spacer y={0.5} />
-                <Text color="helper">
-                    Specify your service type.&nbsp;<a>What is this?</a>
-                </Text>
-                <Spacer y={0.5} />
-                <Input
-                    placeholder="ex: academic-sophon"
-                    value={serviceData.type}
-                    width="300px"
-                    setValue={(e) => {
-                        editService({ ...serviceData, type: e })
-                    }}
-                />
-                <Spacer y={0.5} />
-                <Text color="helper">
-                    Specify a run command.
-                </Text>
-                <Spacer y={0.5} />
-                <Input
-                    placeholder="ex: yarn run start"
-                    value={serviceData.runCommand}
-                    width="300px"
-                    setValue={(e) => {
-                        editService({ ...serviceData, runCommand: e })
-                    }}
-                />
-                <Spacer y={0.5} />
-                <Text color="helper">
-                    Specify resources.
-                </Text>
-                <Spacer y={0.5} />
-                <SliderContainer>
-                    RAM <Input
-                        placeholder="ex: yarn run start"
-                        value="TURN THESE INTO SLIDERS"
-                        width="300px"
-                        setValue={(e) => { }}
-                    />
-                </SliderContainer>
-                <Spacer y={0.5} />
-
-                <SliderContainer>
-                    CPU <Input
-                        placeholder="ex: yarn run start"
-                        value="TURN THESE INTO SLIDERS"
-                        width="300px"
-                        setValue={(e) => { }}
-                    />
-                </SliderContainer>
-                <Spacer y={0.5} />
-
-            </>
-        )
-    }
+  const [showExpanded, setShowExpanded] = React.useState<boolean>(true)
 
+  const renderServiceSettings = () => {
     return (
-        <>
-            <ServiceHeader
-                showExpanded={showExpanded}
-                onClick={() => setShowExpanded(!showExpanded)}
-            >
-                <ServiceTitle>
-                    <ActionButton >
-                        <span className="material-icons dropdown">arrow_drop_down</span>
-                    </ActionButton>
-                    {serviceData.name !== DEFAULT_SERVICE.name && serviceData.name.trim().length > 0 ? serviceData.name : "New Service"}
-                    {serviceData.type === 'web' && <Icon src={web} />}
-                </ServiceTitle>
-                <ActionButton onClick={(e) => {
-                    deleteService();
-                }}>
-                    <span className="material-icons">delete</span>
-                </ActionButton>
-            </ServiceHeader>
-            <AnimateHeight
-                height={showExpanded ? "auto" : 0}
-            >
-                <StyledSourceBox
-                    showExpanded={showExpanded}
-                >
-                    {renderServiceSettings()}
-                </StyledSourceBox>
-            </AnimateHeight>
-        </>
+      <>
+        <TabSelector
+          options={[
+            { label: 'Web', value: 'web' },
+            { label: 'Worker', value: 'worker' },
+            { label: 'Cron', value: 'cron' },
+          ]}
+          currentTab="web"
+          setCurrentTab={(e) => {}}
+        />
+      </>
     )
+  }
+
+  return (
+    <>
+      <ServiceHeader
+        showExpanded={showExpanded}
+        onClick={() => setShowExpanded(!showExpanded)}
+      >
+        <ServiceTitle>
+          <ActionButton >
+            <span className="material-icons dropdown">arrow_drop_down</span>
+          </ActionButton>
+          {serviceData.name !== DEFAULT_SERVICE.name && serviceData.name.trim().length > 0 ? serviceData.name : "New Service"}
+          {serviceData.type === 'web' && <Icon src={web} />}
+        </ServiceTitle>
+        <ActionButton onClick={(e) => {
+          deleteService();
+        }}>
+          <span className="material-icons">delete</span>
+        </ActionButton>
+      </ServiceHeader>
+      <AnimateHeight
+        height={showExpanded ? "auto" : 0}
+      >
+        <StyledSourceBox showExpanded={showExpanded}>
+          {renderServiceSettings()}
+        </StyledSourceBox>
+      </AnimateHeight>
+      <Spacer y={0.5} />
+    </>
+  )
 }
 
 export default Service;
@@ -145,10 +91,10 @@ const ServiceTitle = styled.div`
     align-items: center;
 `;
 
-const StyledSourceBox = styled.div`
+const StyledSourceBox = styled.div<{ showExpanded: boolean }>`
   width: 100%;
   color: #ffffff;
-  padding: 14px 35px 20px;
+  padding: 14px 25px 20px;
   position: relative;
   font-size: 13px;
   border-radius: 5px;
@@ -158,11 +104,6 @@ const StyledSourceBox = styled.div`
   border-top-left-radius: 0px;
   border-top-right-radius: 0px;
   height: 400px;
-  :hover {
-    border-bottom: ${(props: { showExpanded: boolean }) => props.showExpanded && "#7a7b80"};
-    border-left: ${({ showExpanded }) => showExpanded && "#7a7b80"};
-    border-right: ${({ showExpanded }) => showExpanded && "#7a7b80"};
-  }
 `;
 
 const ActionButton = styled.button`
@@ -196,6 +137,7 @@ const SliderContainer = styled.div`
 const ServiceHeader = styled.div`
   flex-direction: row;
   display: flex;
+  height: 60px;
   justify-content: space-between;
   cursor: pointer;
   padding: 20px;
@@ -206,7 +148,6 @@ const ServiceHeader = styled.div`
   border: 1px solid #494b4f;
   :hover {
     border: 1px solid #7a7b80;
-    border-bottom: ${({ showExpanded }) => showExpanded && "0px"};
   }
 
   border-bottom-left-radius: ${({ showExpanded }) => showExpanded && "0px"};
@@ -219,7 +160,6 @@ const ServiceHeader = styled.div`
     margin-left: -10px;
     transform: ${(props: { showExpanded: boolean }) => props.showExpanded ? "" : "rotate(-90deg)"};
   }
-  border-bottom: ${({ showExpanded }) => showExpanded && "0px"};
 
   animation: fadeIn 0.3s 0s;
   @keyframes fadeIn {

+ 95 - 25
dashboard/src/main/home/app-dashboard/new-app-flow/Services.tsx

@@ -1,43 +1,113 @@
-import React from "react"
+import React, { useState } from "react"
 import Service, { DEFAULT_SERVICE, ServiceType } from "./Service";
 import styled from "styled-components";
+import Spacer from "components/porter/Spacer";
+import Modal from "components/porter/Modal";
+import Text from "components/porter/Text";
+import Select from "components/porter/Select";
+import Input from "components/porter/Input";
+import Container from "components/porter/Container";
+import Button from "components/porter/Button";
+
+import web from "assets/web.png";
+import worker from "assets/worker.png";
+import job from "assets/job.png";
 
 interface ServicesProps {
-    services: ServiceType[];
-    setServices: (services: ServiceType[]) => void;
+  services: ServiceType[];
+  setServices: (services: ServiceType[]) => void;
 }
 
 const Services: React.FC<ServicesProps> = ({
-    services,
-    setServices,
+  services,
+  setServices,
 }) => {
-    return (
+  const [showAddServiceModal, setShowAddServiceModal] = useState<boolean>(false);
+  const [serviceName, setServiceName] = useState<string>('');
+
+  return (
+    <>
+      {services.length > 0 &&
         <>
-            {services.length > 0 &&
-                <ServicesContainer>
-                    {services.map((service, index) => {
-                        return (
-                            <Service
-                                serviceData={service}
-                                editService={(newService: ServiceType) => setServices(services.map((s, i) => i === index ? newService : s))}
-                                deleteService={() => setServices(services.filter((_, i) => i !== index))}
-                            />
-                        )
-                    })}
-                </ServicesContainer>
-            }
-            <AddServiceButton onClick={() => setServices([...services, DEFAULT_SERVICE])}>
-                <i className="material-icons add-icon">add_icon</i>
-                Add a new service
-            </AddServiceButton>
+          <ServicesContainer>
+            {services.map((service, index) => {
+              return (
+                <Service
+                  serviceData={service}
+                  editService={(newService: ServiceType) => setServices(services.map((s, i) => i === index ? newService : s))}
+                  deleteService={() => setServices(services.filter((_, i) => i !== index))}
+                />
+              )
+            })}
+          </ServicesContainer>
+          <Spacer y={0.5} />
         </>
-    )
+      }
+      <AddServiceButton onClick={() => setShowAddServiceModal(true)}>
+        <i className="material-icons add-icon">add_icon</i>
+        Add a new service
+      </AddServiceButton>
+      {showAddServiceModal && (
+        <Modal closeModal={() => setShowAddServiceModal(false)}>
+          <Text size={16}>Add a new service</Text>
+          <Spacer y={1} />
+          <Text color="helper">Select a service type:</Text>
+          <Spacer y={0.5} />
+          <Container row>
+            <ServiceIcon>
+              <img src={web} />
+            </ServiceIcon>
+            <Select 
+              options={[
+                { label: 'Web', value: 'web' },
+                { label: 'Worker', value: 'worker' },
+                { label: 'Job', value: 'job' }
+              ]}
+            />
+          </Container>
+          <Spacer y={1} />
+          <Text color="helper">Name this service:</Text>
+          <Spacer y={0.5} />
+          <Input
+            placeholder="ex: my-service"
+            width="300px"
+            value={serviceName}
+            setValue={setServiceName}
+          />
+          <Spacer y={1} />
+          <Button onClick={() => {
+             setServices([...services, DEFAULT_SERVICE])
+          }}>
+            <I className="material-icons">add</I> Add service
+          </Button>
+        </Modal>
+      )}
+    </>
+  )
 }
 
 export default Services
 
+const ServiceIcon = styled.div`
+  border: 1px solid #494b4f;
+  height: 36px;
+  > img {
+    height: 20px;
+    margin-right: 15px;
+    padding-left: 10px;
+  }
+`;
+
+const I = styled.i`
+  color: white;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  margin-right: 7px;
+  justify-content: center;
+`;
+
 const ServicesContainer = styled.div`
-    margin-bottom: 10px;
 `;
 
 const AddServiceButton = styled.div`

+ 1 - 24
dashboard/src/main/home/app-dashboard/new-app-flow/SourceSettings.tsx

@@ -15,20 +15,10 @@ import DetectContentsList from "components/repo-selector/DetectContentsList";
 
 type Props = {
   source: SourceType | undefined;
-  templateName: string;
-  setTemplateName: (x: string) => void;
-  setValuesToOverride: (x: any) => void;
-  setPage: (x: string) => void;
-  sourceType: string;
-  setSourceType: (x: string) => void;
-
   imageUrl: string;
   setImageUrl: (x: string) => void;
   imageTag: string;
   setImageTag: (x: string) => void;
-
-  hasSource?: string;
-
   actionConfig: ActionConfigType;
   setActionConfig: (
     x: ActionConfigType | ((prevState: ActionConfigType) => ActionConfigType)
@@ -37,25 +27,12 @@ type Props = {
   setProcfileProcess: (x: string) => void;
   branch: string;
   setBranch: (x: string) => void;
-  repoType: string;
-  setRepoType: (x: string) => void;
   dockerfilePath: string | null;
   setDockerfilePath: (x: string) => void;
   procfilePath: string | null;
   setProcfilePath: (x: string) => void;
   folderPath: string | null;
   setFolderPath: (x: string) => void;
-  selectedRegistry: any;
-  setSelectedRegistry: (x: string) => void;
-  setBuildConfig: (x: any) => void;
-};
-
-const defaultActionConfig: ActionConfigType = {
-  git_repo: "",
-  image_repo_uri: "",
-  git_branch: "",
-  git_repo_id: 0,
-  kind: "github",
 };
 
 const SourceSettings: React.FC<Props> = ({
@@ -166,7 +143,7 @@ const SourceSettings: React.FC<Props> = ({
         <Input
           placeholder="ex: nginx"
           value={imageUrl}
-          width="100%"
+          width="300px"
           setValue={setImageUrl}
         />
       </>

+ 16 - 0
dashboard/src/shared/api.tsx

@@ -177,6 +177,21 @@ const createPorterApp = baseApi<
   return `/api/projects/${project_id}/clusters/${cluster_id}/stacks/update_config`;
 });
 
+const updatePorterStack = baseApi<
+  {
+    stack_name: string;
+    dependencies: { name: string; alias: string; version: string; repository: string }[];
+    values: any;
+  },
+  {
+    project_id: number;
+    cluster_id: number;
+  }
+>("POST", (pathParams) => {
+  let { project_id, cluster_id } = pathParams;
+  return `/api/projects/${project_id}/clusters/${cluster_id}/stacks`;
+});
+
 const createEnvironment = baseApi<
   {
     name: string;
@@ -2457,6 +2472,7 @@ export default {
   createPasswordResetFinalize,
   createProject,
   createPorterApp,
+  updatePorterStack,
   createConfigMap,
   deleteCluster,
   deleteConfigMap,

+ 1 - 0
dashboard/src/shared/themes/midnight.ts

@@ -6,6 +6,7 @@ const theme = {
   clickable: {
     bg: "linear-gradient(180deg, #171B21, #121212)",
   },
+  modalBg: "#171B2111",
   text: {
     primary: "#DFDFE1",
   },