Bläddra i källkod

application services write to form state

Feroze Mohideen 3 år sedan
förälder
incheckning
4a4410f53e

+ 19 - 14
dashboard/src/main/home/app-dashboard/new-app-flow/JobTabs.tsx

@@ -4,11 +4,16 @@ import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import TabSelector from "components/TabSelector";
 import Checkbox from "components/porter/Checkbox";
+import { JobService } from "./serviceTypes";
 
 interface Props {
+  service: JobService
+  editService: (service: JobService) => void
 }
 
 const JobTabs: React.FC<Props> = ({
+  service,
+  editService
 }) => {
   const [currentTab, setCurrentTab] = React.useState<string>('main');
 
@@ -16,20 +21,20 @@ const JobTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Start command"
           placeholder="ex: sh start.sh"
-          value=""
+          value={service.startCommand}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, startCommand: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Cron schedule (leave blank to run manually)"
           placeholder="ex: */5 * * * *"
-          value=""
+          value={service.cronSchedule}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, cronSchedule: e }) }}
         />
       </>
     )
@@ -39,20 +44,20 @@ const JobTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="CPUs"
           placeholder="ex: 0.5"
-          value=""
+          value={service.cpu}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, cpu: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="RAM (GB)"
           placeholder="ex: 1"
-          value=""
+          value={service.ram}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, ram: e }) }}
         />
       </>
     )
@@ -63,8 +68,8 @@ const JobTabs: React.FC<Props> = ({
       <>
         <Spacer y={1} />
         <Checkbox
-          checked={true}
-          toggleChecked={() => {}}
+          checked={service.jobsExecuteConcurrently}
+          toggleChecked={() => { editService({ ...service, jobsExecuteConcurrently: !service.jobsExecuteConcurrently }) }}
         >
           <Text color="helper">Allow jobs to execute concurrently</Text>
         </Checkbox>

+ 31 - 28
dashboard/src/main/home/app-dashboard/new-app-flow/Service.tsx → dashboard/src/main/home/app-dashboard/new-app-flow/ServiceContainer.tsx

@@ -10,36 +10,43 @@ import Spacer from "components/porter/Spacer";
 import WebTabs from "./WebTabs";
 import WorkerTabs from "./WorkerTabs";
 import JobTabs from "./JobTabs";
+import { Service } from "./serviceTypes";
 
 interface ServiceProps {
-  serviceData: ServiceType;
-  editService: (service: ServiceType) => void;
+  service: Service;
+  editService: (service: Service) => 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,
+const ServiceContainer: React.FC<ServiceProps> = ({
+  service,
   deleteService,
   editService,
 }) => {
   const [showExpanded, setShowExpanded] = React.useState<boolean>(true)
 
+  const renderTabs = (service: Service) => {
+    switch (service.type) {
+      case 'web':
+        return <WebTabs service={service} editService={editService} />
+      case 'worker':
+        return <WorkerTabs service={service} editService={editService} />
+      case 'job':
+        return <JobTabs service={service} editService={editService} />
+    }
+  }
+
+  const renderIcon = (service: Service) => {
+    switch (service.type) {
+      case 'web':
+        return <Icon src={web} />
+      case 'worker':
+        return <Icon src={worker} />
+      case 'job':
+        return <Icon src={job} />
+    }
+  }
+
   return (
     <>
       <ServiceHeader
@@ -50,10 +57,8 @@ const Service: React.FC<ServiceProps> = ({
           <ActionButton >
             <span className="material-icons dropdown">arrow_drop_down</span>
           </ActionButton>
-          {serviceData.type === 'web' && <Icon src={web} />}
-          {serviceData.type === 'worker' && <Icon src={worker} />}
-          {serviceData.type === 'job' && <Icon src={job} />}
-          {serviceData.name !== DEFAULT_SERVICE.name && serviceData.name.trim().length > 0 ? serviceData.name : "New Service"}
+          {renderIcon(service)}
+          {service.name.trim().length > 0 ? service.name : "New Service"}
         </ServiceTitle>
         <ActionButton onClick={(e) => {
           deleteService();
@@ -65,9 +70,7 @@ const Service: React.FC<ServiceProps> = ({
         height={showExpanded ? "auto" : 0}
       >
         <StyledSourceBox showExpanded={showExpanded}>
-          {serviceData.type === 'web' && <WebTabs />}
-          {serviceData.type === 'worker' && <WorkerTabs />}
-          {serviceData.type === 'job' && <JobTabs />}
+          {renderTabs(service)}
         </StyledSourceBox>
       </AnimateHeight>
       <Spacer y={0.5} />
@@ -75,7 +78,7 @@ const Service: React.FC<ServiceProps> = ({
   )
 }
 
-export default Service;
+export default ServiceContainer;
 
 const ServiceTitle = styled.div`
     display: flex;

+ 11 - 9
dashboard/src/main/home/app-dashboard/new-app-flow/Services.tsx

@@ -1,5 +1,5 @@
 import React, { useState } from "react"
-import Service, { DEFAULT_SERVICE, ServiceType } from "./Service";
+import ServiceContainer from "./ServiceContainer";
 import styled from "styled-components";
 import Spacer from "components/porter/Spacer";
 import Modal from "components/porter/Modal";
@@ -12,10 +12,11 @@ import Button from "components/porter/Button";
 import web from "assets/web.png";
 import worker from "assets/worker.png";
 import job from "assets/job.png";
+import { Service, ServiceType, createDefaultService } from "./serviceTypes";
 
 interface ServicesProps {
-  services: ServiceType[];
-  setServices: (services: ServiceType[]) => void;
+  services: Service[];
+  setServices: (services: Service[]) => void;
 }
 
 const Services: React.FC<ServicesProps> = ({
@@ -24,7 +25,7 @@ const Services: React.FC<ServicesProps> = ({
 }) => {
   const [showAddServiceModal, setShowAddServiceModal] = useState<boolean>(false);
   const [serviceName, setServiceName] = useState<string>('');
-  const [serviceType, setServiceType] = useState<string>('web');
+  const [serviceType, setServiceType] = useState<ServiceType>('web');
 
   return (
     <>
@@ -33,9 +34,9 @@ const Services: React.FC<ServicesProps> = ({
           <ServicesContainer>
             {services.map((service, index) => {
               return (
-                <Service
-                  serviceData={service}
-                  editService={(newService: ServiceType) => setServices(services.map((s, i) => i === index ? newService : s))}
+                <ServiceContainer
+                  service={service}
+                  editService={(newService: Service) => setServices(services.map((s, i) => i === index ? newService : s))}
                   deleteService={() => setServices(services.filter((_, i) => i !== index))}
                 />
               )
@@ -62,7 +63,8 @@ const Services: React.FC<ServicesProps> = ({
             </ServiceIcon>
             <Select
               value={serviceType}
-              setValue={setServiceType}
+              // this is ugly
+              setValue={(value: string) => setServiceType(value as ServiceType)}
               options={[
                 { label: 'Web', value: 'web' },
                 { label: 'Worker', value: 'worker' },
@@ -81,7 +83,7 @@ const Services: React.FC<ServicesProps> = ({
           />
           <Spacer y={1} />
           <Button onClick={() => {
-            setServices([...services, { ...DEFAULT_SERVICE, name: serviceName, type: serviceType }]);
+            setServices([...services, createDefaultService(serviceName, serviceType)]);
             setShowAddServiceModal(false);
             setServiceName('');
             setServiceType('web');

+ 39 - 34
dashboard/src/main/home/app-dashboard/new-app-flow/WebTabs.tsx

@@ -4,11 +4,16 @@ import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import TabSelector from "components/TabSelector";
 import Checkbox from "components/porter/Checkbox";
+import { WebService } from "./serviceTypes";
 
 interface Props {
+  service: WebService
+  editService: (service: WebService) => void
 }
 
 const WebTabs: React.FC<Props> = ({
+  service,
+  editService
 }) => {
   const [currentTab, setCurrentTab] = React.useState<string>('main');
 
@@ -16,25 +21,25 @@ const WebTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Start command"
           placeholder="ex: sh start.sh"
-          value=""
+          value={service.startCommand}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, startCommand: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Container port"
           placeholder="ex: 80"
-          value=""
+          value={service.port}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, port: e }) }}
         />
         <Spacer y={1} />
         <Checkbox
-          checked={true}
-          toggleChecked={() => {}}
+          checked={service.generateUrlForExternalTraffic}
+          toggleChecked={() => { editService({ ...service, generateUrlForExternalTraffic: !service.generateUrlForExternalTraffic }) }}
         >
           <Text color="helper">Generate a Porter URL for external traffic</Text>
         </Checkbox>
@@ -46,67 +51,67 @@ const WebTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="CPUs"
           placeholder="ex: 0.5"
-          value=""
+          value={service.cpu}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, cpu: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="RAM (GB)"
           placeholder="ex: 1"
-          value=""
+          value={service.ram}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, ram: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Replicas"
           placeholder="ex: 1"
-          value=""
+          value={service.replicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, replicas: e }) }}
         />
         <Spacer y={1} />
         <Checkbox
-          checked={true}
-          toggleChecked={() => {}}
+          checked={service.autoscalingOn}
+          toggleChecked={() => { editService({ ...service, autoscalingOn: !service.autoscalingOn }) }}
         >
           <Text color="helper">Enable autoscaling (overrides replicas)</Text>
         </Checkbox>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Min replicas"
           placeholder="ex: 1"
-          value=""
+          value={service.minReplicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, minReplicas: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Max replicas"
           placeholder="ex: 10"
-          value=""
+          value={service.maxReplicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, maxReplicas: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Target CPU utilization (%)"
           placeholder="ex: 50"
-          value=""
+          value={service.targetCPUUtilizationPercentage}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, targetCPUUtilizationPercentage: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Target RAM utilization (%)"
           placeholder="ex: 50"
-          value=""
+          value={service.targetRAMUtilizationPercentage}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, targetRAMUtilizationPercentage: e }) }}
         />
       </>
     )
@@ -116,12 +121,12 @@ const WebTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Custom domain"
           placeholder="ex: my-app.my-domain.com"
-          value=""
+          value={service.customDomain ?? ''}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, customDomain: e }) }}
         />
       </>
     );

+ 31 - 26
dashboard/src/main/home/app-dashboard/new-app-flow/WorkerTabs.tsx

@@ -4,11 +4,16 @@ import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import TabSelector from "components/TabSelector";
 import Checkbox from "components/porter/Checkbox";
+import { WorkerService } from "./serviceTypes";
 
 interface Props {
+  service: WorkerService
+  editService: (service: WorkerService) => void
 }
 
 const WorkerTabs: React.FC<Props> = ({
+  service,
+  editService
 }) => {
   const [currentTab, setCurrentTab] = React.useState<string>('main');
 
@@ -16,12 +21,12 @@ const WorkerTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Start command"
           placeholder="ex: sh start.sh"
-          value=""
+          value={service.startCommand}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, startCommand: e }) }}
         />
       </>
     )
@@ -31,67 +36,67 @@ const WorkerTabs: React.FC<Props> = ({
     return (
       <>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="CPUs"
           placeholder="ex: 0.5"
-          value=""
+          value={service.cpu}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, cpu: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="RAM (GB)"
           placeholder="ex: 1"
-          value=""
+          value={service.ram}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, ram: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Replicas"
           placeholder="ex: 1"
-          value=""
+          value={service.replicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, replicas: e }) }}
         />
         <Spacer y={1} />
         <Checkbox
-          checked={true}
-          toggleChecked={() => {}}
+          checked={service.autoscalingOn}
+          toggleChecked={() => { editService({ ...service, autoscalingOn: !service.autoscalingOn }) }}
         >
           <Text color="helper">Enable autoscaling (overrides replicas)</Text>
         </Checkbox>
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Min replicas"
           placeholder="ex: 1"
-          value=""
+          value={service.minReplicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, minReplicas: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Max replicas"
           placeholder="ex: 10"
-          value=""
+          value={service.maxReplicas}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, maxReplicas: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Target CPU utilization (%)"
           placeholder="ex: 50"
-          value=""
+          value={service.targetCPUUtilizationPercentage}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, targetCPUUtilizationPercentage: e }) }}
         />
         <Spacer y={1} />
-        <Input 
+        <Input
           label="Target RAM utilization (%)"
           placeholder="ex: 50"
-          value=""
+          value={service.targetRAMUtilizationPercentage}
           width="300px"
-          setValue={(e) => {}}
+          setValue={(e) => { editService({ ...service, targetRAMUtilizationPercentage: e }) }}
         />
       </>
     )

+ 87 - 0
dashboard/src/main/home/app-dashboard/new-app-flow/serviceTypes.ts

@@ -0,0 +1,87 @@
+export type Service = WorkerService | WebService | JobService;
+export type ServiceType = 'web' | 'worker' | 'job';
+
+type SharedServiceParams = {
+    name: string;
+    cpu: string;
+    ram: string;
+    startCommand: string;
+    type: ServiceType;
+}
+
+export type WorkerService = SharedServiceParams & {
+    type: 'worker';
+    replicas: string;
+    autoscalingOn: boolean;
+    minReplicas: string;
+    maxReplicas: string;
+    targetCPUUtilizationPercentage: string;
+    targetRAMUtilizationPercentage: string;
+}
+const WorkerService = {
+    empty: (name: string): WorkerService => ({
+        name,
+        cpu: '',
+        ram: '',
+        startCommand: '',
+        type: 'worker',
+        replicas: '1',
+        autoscalingOn: false,
+        minReplicas: '1',
+        maxReplicas: '10',
+        targetCPUUtilizationPercentage: '50',
+        targetRAMUtilizationPercentage: '50',
+    }),
+}
+
+export type WebService = SharedServiceParams & Omit<WorkerService, 'type'> & {
+    type: 'web';
+    port: string;
+    generateUrlForExternalTraffic: boolean;
+    customDomain?: string;
+}
+const WebService = {
+    empty: (name: string): WebService => ({
+        name,
+        cpu: '',
+        ram: '',
+        startCommand: '',
+        type: 'web',
+        replicas: '1',
+        autoscalingOn: false,
+        minReplicas: '1',
+        maxReplicas: '10',
+        targetCPUUtilizationPercentage: '50',
+        targetRAMUtilizationPercentage: '50',
+        port: '8080',
+        generateUrlForExternalTraffic: true,
+    }),
+}
+
+export type JobService = SharedServiceParams & {
+    type: 'job';
+    jobsExecuteConcurrently: boolean;
+    cronSchedule: string;
+}
+const JobService = {
+    empty: (name: string): JobService => ({
+        name,
+        cpu: '',
+        ram: '',
+        startCommand: '',
+        type: 'job',
+        jobsExecuteConcurrently: false,
+        cronSchedule: '',
+    }),
+}
+
+export const createDefaultService = (name: string, type: ServiceType) => {
+    switch (type) {
+        case 'web':
+            return WebService.empty(name);
+        case 'worker':
+            return WorkerService.empty(name);
+        case 'job':
+            return JobService.empty(name);
+    }
+}