Browse Source

adding more to the deployment form

Feroze Mohideen 3 years ago
parent
commit
5b776714e4

+ 6 - 4
dashboard/src/main/home/app-dashboard/new-app-flow/AdvancedBuildSettings.tsx

@@ -179,8 +179,13 @@ const AdvancedBuildSettings: React.FC<AdvancedBuildSettingsProps> = ({
 export default AdvancedBuildSettings
 
 const StyledAdvancedBuildSettings = styled.div`
-  color:  "#ffffff66";
+  color: ${({ showSettings }) => showSettings ? "white" : "#aaaabb"};
   background: #26292e;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
+    color:  white;
+  }
   display: flex;
   justify-content: space-between;
   align-items: center;
@@ -190,9 +195,6 @@ const StyledAdvancedBuildSettings = styled.div`
   width: 100%;
   padding-left: 10px;
   cursor: pointer;
-  :hover {
-    background: #7a7b80;
-  }
   border-bottom-left-radius: ${({ showSettings }) => showSettings && "0px"};
   border-bottom-right-radius: ${({ showSettings }) => showSettings && "0px"};
 

+ 0 - 92
dashboard/src/main/home/app-dashboard/new-app-flow/GitRepoSelector.tsx

@@ -1,92 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-interface GitRepoSelectorProps {
-
-}
-
-const GitRepoSelector: React.FC<GitRepoSelectorProps> = ({
-}) => {
-    return (
-        <StyledSourceBox>
-            <CloseButton
-                onClick={() => {
-                    setSourceType("");
-                    setDockerfilePath("");
-                    setFolderPath("");
-                    setProcfilePath("");
-                    setProcfileProcess("");
-                }}
-            >
-                <i className="material-icons">close</i>
-            </CloseButton>
-            <Subtitle>
-                Provide a repo folder to use as source.
-                <Highlight
-                    onClick={() => setCurrentModal("AccountSettingsModal", {})}
-                >
-                    Manage Git repos
-                </Highlight>
-                <Required>*</Required>
-            </Subtitle>
-            <DarkMatter antiHeight="-4px" />
-            <ActionConfEditor
-                actionConfig={actionConfig}
-                branch={branch}
-                setActionConfig={(actionConfig: ActionConfigType) => {
-                    setActionConfig((currentActionConfig: ActionConfigType) => ({
-                        ...currentActionConfig,
-                        ...actionConfig,
-                    }));
-                    setImageUrl(actionConfig.image_repo_uri);
-                    /*
-                    setParentState({ actionConfig }, () =>
-                      setParentState({ imageUrl: actionConfig.image_repo_uri })
-                    )
-                    */
-                }}
-                procfileProcess={procfileProcess}
-                setProcfileProcess={(procfileProcess: string) => {
-                    setProcfileProcess(procfileProcess);
-                    setValuesToOverride((v: any) => ({
-                        ...v,
-                        "container.command": procfileProcess || "",
-                        showStartCommand: !procfileProcess,
-                    }));
-                }}
-                setBranch={setBranch}
-                setDockerfilePath={setDockerfilePath}
-                setProcfilePath={setProcfilePath}
-                procfilePath={procfilePath}
-                dockerfilePath={dockerfilePath}
-                folderPath={folderPath}
-                setFolderPath={setFolderPath}
-                reset={() => {
-                    setActionConfig({ ...defaultActionConfig });
-                    setBranch("");
-                    setDockerfilePath(null);
-                    setFolderPath(null);
-                }}
-                setSelectedRegistry={setSelectedRegistry}
-                selectedRegistry={selectedRegistry}
-                setBuildConfig={setBuildConfig}
-            />
-            <br />
-        </StyledSourceBox>
-    )
-}
-
-export default GitRepoSelector;
-
-const StyledSourceBox = styled.div`
-  width: 100%;
-  color: #ffffff;
-  padding: 14px 35px 20px;
-  position: relative;
-  font-size: 13px;
-  margin-top: 6px;
-  margin-bottom: 25px;
-  border-radius: 5px;
-  background: ${props => props.theme.fg};
-  border: 1px solid #494b4f;
-`;

+ 44 - 13
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -21,22 +21,27 @@ import Button from "components/porter/Button";
 import { generateSlug } from "random-word-slugs";
 import { RouteComponentProps, withRouter } from "react-router";
 import Error from "components/porter/Error";
-import SourceSelector from "./SourceSelector";
+import SourceSelector, { SourceType } from "./SourceSelector";
 import SourceSettings from "./SourceSettings"
+import Services from "./Services";
+import EnvGroupArray, { KeyValueType } from "main/home/cluster-dashboard/env-groups/EnvGroupArray";
 
 type Props = RouteComponentProps & {
 };
 
-export type SourceType = "github" | "docker-registry";
 
 interface FormState {
   applicationName: string;
   selectedSourceType: SourceType | undefined;
+  serviceList: any[];
+  envVariables: KeyValueType[];
 }
 
 const INITIAL_STATE: FormState = {
   applicationName: "",
   selectedSourceType: undefined,
+  serviceList: [],
+  envVariables: [],
 };
 
 const Validators: {
@@ -44,6 +49,8 @@ const Validators: {
 } = {
   applicationName: (value: string) => value.trim().length > 0,
   selectedSourceType: (value: SourceType | undefined) => value !== undefined,
+  serviceList: (value: any[]) => value.length > 0,
+  envVariables: (value: KeyValueType[]) => true,
 };
 
 
@@ -56,7 +63,6 @@ const NewAppFlow: React.FC<Props> = ({
   const [currentStep, setCurrentStep] = useState<number>(0);
   const [formState, setFormState] = useState<FormState>(INITIAL_STATE);
 
-
   return (
     <StyledConfigureTemplate>
       <Back to="/apps" />
@@ -80,11 +86,11 @@ const NewAppFlow: React.FC<Props> = ({
             <Text color="helper">
               Lowercase letters, numbers, and "-" only.
             </Text>
-            <Spacer height="20px" />
+            <Spacer y={0.5} />
             <Input
               placeholder="ex: academic-sophon"
               value={formState.applicationName}
-              width="300px"
+              width="100%"
               setValue={(e) => {
                 setFormState({ ...formState, applicationName: e })
                 if (Validators.applicationName(e)) {
@@ -119,25 +125,50 @@ const NewAppFlow: React.FC<Props> = ({
           </>,
           <>
             <Text size={16}>Services</Text>
+            <Spacer y={1} />
+            <Services
+              setServices={
+                (services: any[]) => {
+                  setFormState({ ...formState, serviceList: services })
+                  if (Validators.serviceList(services)) {
+                    setCurrentStep(Math.max(currentStep, 4));
+                  }
+                }}
+              services={formState.serviceList}
+            />
+          </>,
+          <>
+            <Text size={16}>Environment variables</Text>
             <Spacer y={0.5} />
             <Text color="helper">
-              Add services to this application.
+              Specify environment variables shared among all services.
             </Text>
-            <Spacer y={1} />
-            SOME MORE STUFF HERE
+            <EnvGroupArray
+              values={formState.envVariables}
+              setValues={(x: any) => setFormState({ ...formState, envVariables: x })}
+              fileUpload={true}
+            />
           </>,
           <>
-            <Text size={16}>Services</Text>
+            <Text size={16}>Release command (optional)</Text>
             <Spacer y={0.5} />
             <Text color="helper">
-              Add services to this application.
+              If specified, this command will be run before every deployment.
             </Text>
-            <Spacer y={1} />
-            SOME MORE STUFF HERE
+            <Spacer y={0.5} />
+            <Input
+              placeholder="yarn ./scripts/run-migrations.js"
+              value={""}
+              width="100%"
+              setValue={(e) => { }}
+            />
           </>
         ]}
       />
-      <Spacer height="80px" />
+      <Spacer y={1} />
+      <Button onClick={() => ({})}>
+        DEPLYOY
+      </Button>
     </StyledConfigureTemplate>
   );
 };

+ 249 - 0
dashboard/src/main/home/app-dashboard/new-app-flow/Service.tsx

@@ -0,0 +1,249 @@
+import Input from "components/porter/Input";
+import React from "react"
+import AnimateHeight from "react-animate-height";
+import styled from "styled-components";
+import Text from "components/porter/Text";
+import Spacer from "components/porter/Spacer";
+import web from "assets/web.png";
+
+
+interface ServiceProps {
+    serviceData: ServiceType;
+    editService: (service: ServiceType) => void;
+    deleteService: () => void;
+}
+
+export type ServiceType = {
+    name: string;
+    type: string;
+    runCommand: string;
+    ram: number;
+    cpu: number;
+}
+
+export const DEFAULT_SERVICE: ServiceType = {
+    name: 'new-service',
+    type: '',
+    runCommand: '',
+    ram: 512,
+    cpu: 500,
+}
+
+const Service: React.FC<ServiceProps> = ({
+    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} />
+
+            </>
+        )
+    }
+
+    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>
+        </>
+    )
+}
+
+export default Service;
+
+const ServiceTitle = styled.div`
+    display: flex;
+    align-items: center;
+`;
+
+const StyledSourceBox = styled.div`
+  width: 100%;
+  color: #ffffff;
+  padding: 14px 35px 20px;
+  position: relative;
+  font-size: 13px;
+  border-radius: 5px;
+  background: ${props => props.theme.fg};
+  border: 1px solid #494b4f;
+  border-top: 0px;
+  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`
+  position: relative;
+  border: none;
+  background: none;
+  color: white;
+  padding: 5px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 50%;
+  cursor: pointer;
+  color: #aaaabb;
+
+  :hover {
+    color: white;
+  }
+
+  > span {
+    font-size: 20px;
+  }
+  margin-right: 5px;
+`;
+
+const SliderContainer = styled.div`
+    display: flex;
+    align-items: center;
+`;
+
+const ServiceHeader = styled.div`
+  flex-direction: row;
+  display: flex;
+  justify-content: space-between;
+  cursor: pointer;
+  padding: 20px;
+  color: ${props => props.theme.text.primary};
+  position: relative;
+  border-radius: 5px;
+  background: ${props => props.theme.clickable.bg};
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
+    border-bottom: ${({ showExpanded }) => showExpanded && "0px"};
+  }
+
+  border-bottom-left-radius: ${({ showExpanded }) => showExpanded && "0px"};
+  border-bottom-right-radius: ${({ showExpanded }) => showExpanded && "0px"};
+
+  .dropdown {
+    font-size: 30px;
+    cursor: pointer;
+    border-radius: 20px;
+    margin-left: -10px;
+    transform: ${(props: { showExpanded: boolean }) => props.showExpanded ? "" : "rotate(-90deg)"};
+  }
+  border-bottom: ${({ showExpanded }) => showExpanded && "0px"};
+
+  animation: fadeIn 0.3s 0s;
+  @keyframes fadeIn {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
+`;
+
+const Icon = styled.img`
+  height: 18px;
+  margin-right: 15px;
+  margin-left: 10px;
+
+  animation: fadeIn 0.3s 0s;
+  @keyframes fadeIn {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
+`;

+ 63 - 0
dashboard/src/main/home/app-dashboard/new-app-flow/Services.tsx

@@ -0,0 +1,63 @@
+import React from "react"
+import Service, { DEFAULT_SERVICE, ServiceType } from "./Service";
+import styled from "styled-components";
+
+interface ServicesProps {
+    services: ServiceType[];
+    setServices: (services: ServiceType[]) => void;
+}
+
+const Services: React.FC<ServicesProps> = ({
+    services,
+    setServices,
+}) => {
+    return (
+        <>
+            {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>
+        </>
+    )
+}
+
+export default Services
+
+const ServicesContainer = styled.div`
+    margin-bottom: 10px;
+`;
+
+const AddServiceButton = styled.div`
+  color:  #aaaabb;
+  background: #26292e;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
+    color: white;
+  }
+  display: flex;
+  align-items: center;
+  border-radius: 5px;
+  height: 40px;
+  font-size: 13px;
+  width: 100%;
+  padding-left: 10px;
+  cursor: pointer;
+  .add-icon {
+    width: 30px;
+    font-size: 20px;
+  }
+`;

+ 30 - 30
dashboard/src/main/home/app-dashboard/new-app-flow/SourceSelector.tsx

@@ -1,41 +1,42 @@
 import React from "react";
 import styled from "styled-components";
-import { SourceType } from "./NewAppFlow";
+
+export type SourceType = "github" | "docker-registry";
 
 interface SourceSelectorProps {
-    selectedSourceType: SourceType | undefined;
-    setSourceType: (sourceType: SourceType) => void;
+  selectedSourceType: SourceType | undefined;
+  setSourceType: (sourceType: SourceType) => void;
 }
 
 const SourceSelector: React.FC<SourceSelectorProps> = ({
-    selectedSourceType,
-    setSourceType
+  selectedSourceType,
+  setSourceType
 }) => {
-    return (
-        <BlockList>
-            <Block
-                selected={selectedSourceType === 'github'}
-                onClick={() => setSourceType('github')}
-            >
-                <BlockIcon src="https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png" />
-                <BlockTitle>Git repository</BlockTitle>
-                <BlockDescription>
-                    Deploy using source from a Git repo.
-                </BlockDescription>
-            </Block>
-            <Block
-                selected={selectedSourceType === 'docker-registry'}
-                onClick={() => setSourceType('docker-registry')}
-            >
-                <BlockIcon src="https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png" />
-                <BlockTitle>Docker registry</BlockTitle>
-                <BlockDescription>
-                    Deploy a container from an image registry.
-                </BlockDescription>
-            </Block>
+  return (
+    <BlockList>
+      <Block
+        selected={selectedSourceType === 'github'}
+        onClick={() => setSourceType('github')}
+      >
+        <BlockIcon src="https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png" />
+        <BlockTitle>Git repository</BlockTitle>
+        <BlockDescription>
+          Deploy using source from a Git repo.
+        </BlockDescription>
+      </Block>
+      <Block
+        selected={selectedSourceType === 'docker-registry'}
+        onClick={() => setSourceType('docker-registry')}
+      >
+        <BlockIcon src="https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png" />
+        <BlockTitle>Docker registry</BlockTitle>
+        <BlockDescription>
+          Deploy a container from an image registry.
+        </BlockDescription>
+      </Block>
 
-        </BlockList>
-    );
+    </BlockList>
+  );
 }
 
 export default SourceSelector;
@@ -77,7 +78,6 @@ const Block = styled.div<{ selected?: boolean }>`
 const BlockList = styled.div`
   overflow: visible;
   margin-top: 6px;
-  margin-bottom: 27px;
   display: grid;
   grid-column-gap: 25px;
   grid-row-gap: 25px;

+ 18 - 13
dashboard/src/main/home/app-dashboard/new-app-flow/SourceSettings.tsx

@@ -1,11 +1,11 @@
 import AnimateHeight from "react-animate-height";
-import { SourceType } from "./NewAppFlow";
 import React from "react";
 import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import Input from "components/porter/Input";
 import AdvancedBuildSettings from "./AdvancedBuildSettings";
 import styled from "styled-components";
+import { SourceType } from "./SourceSelector";
 
 interface SourceSettingsProps {
     source: SourceType | undefined;
@@ -26,7 +26,7 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
                 <Input
                     placeholder="ex: academic-sophon"
                     value=""
-                    width="300px"
+                    width="100%"
                     setValue={(e) => { }}
                 />
                 <Spacer y={0.5} />
@@ -37,7 +37,7 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
                 <Input
                     placeholder="ex: academic-sophon"
                     value=""
-                    width="300px"
+                    width="100%"
                     setValue={(e) => { }}
                 />
                 <Spacer y={0.5} />
@@ -48,7 +48,7 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
                 <Input
                     placeholder="ex: ./"
                     value=""
-                    width="300px"
+                    width="100%"
                     setValue={(e) => { }}
                 />
                 <Spacer y={0.5} />
@@ -59,7 +59,7 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
                 <Input
                     placeholder="ex: ./porter.yaml"
                     value=""
-                    width="300px"
+                    width="100%"
                     setValue={(e) => { }}
                 />
                 <Spacer y={1} />
@@ -85,7 +85,7 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
                 <Input
                     placeholder="ex: academic-sophon"
                     value=""
-                    width="300px"
+                    width="100%"
                     setValue={(e) => { }}
                 />
                 <Spacer y={0.5} />
@@ -97,18 +97,23 @@ const SourceSettings: React.FC<SourceSettingsProps> = ({
     }
 
     return (
-        <AnimateHeight
-            height={source ? 'auto' : 0}
-        >
-            <div >
-                {source === "github" ? renderGithubSettings() : renderDockerSettings()}
-            </div>
-        </AnimateHeight >
+        <SourceSettingsContainer source={source}>
+            <AnimateHeight
+                height={source ? 'auto' : 0}
+            >
+                <div >
+                    {source === "github" ? renderGithubSettings() : renderDockerSettings()}
+                </div>
+            </AnimateHeight >
+        </SourceSettingsContainer>
     )
 }
 
 export default SourceSettings;
 
+const SourceSettingsContainer = styled.div`
+    margin-top: ${(props: { source: SourceType | undefined }) => props.source && "20px"};
+`;
 const DetectedBuildMessage = styled.div`
   color: #0f872b;
   display: flex;