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

V1 for env group creation on stacks launch flow

jnfrati 3 лет назад
Родитель
Сommit
a12a202b04

+ 87 - 0
dashboard/src/main/home/cluster-dashboard/stacks/launch/NewEnvGroup.tsx

@@ -0,0 +1,87 @@
+import Heading from "components/form-components/Heading";
+import Helper from "components/form-components/Helper";
+import InputRow from "components/form-components/InputRow";
+import React, { useContext, useState } from "react";
+import { isAlphanumeric } from "shared/common";
+import { useRouting } from "shared/routing";
+import styled from "styled-components";
+import EnvGroupArray from "../../env-groups/EnvGroupArray";
+import { SubmitButton } from "./components/styles";
+import { StacksLaunchContext } from "./Store";
+
+const NewEnvGroup = () => {
+  const { addEnvGroup } = useContext(StacksLaunchContext);
+  const [name, setName] = useState("");
+  const [envVariables, setEnvVariables] = useState<any[]>([]);
+
+  const { pushFiltered } = useRouting();
+
+  const isDisabled = () =>
+    !isAlphanumeric(name) || name === "" || !envVariables.length;
+
+  return (
+    <>
+      <Heading isAtTop={true}>Name</Heading>
+      <Subtitle>
+        <Warning
+          makeFlush={true}
+          highlight={!isAlphanumeric(name) && name !== ""}
+        >
+          Lowercase letters, numbers, and "-" only.
+        </Warning>
+      </Subtitle>
+      <InputRow
+        type="text"
+        value={name}
+        setValue={(x: string) => {
+          setName(x);
+        }}
+        placeholder="ex: doctor-scientist"
+        width="100%"
+      />
+
+      <Heading>Environment Variables</Heading>
+      <Helper>
+        Set environment variables for your secrets and environment-specific
+        configuration.
+      </Helper>
+      <EnvGroupArray
+        values={envVariables}
+        setValues={(x: any) => setEnvVariables((prev) => [...x])}
+        fileUpload={true}
+        secretOption={true}
+      />
+
+      <SubmitButton
+        onClick={() => {
+          addEnvGroup({
+            name,
+            variables: [...envVariables],
+          });
+          pushFiltered("/stacks/launch/overview", []);
+        }}
+        makeFlush
+        clearPosition
+        text="Save env group"
+        disabled={isDisabled()}
+      />
+    </>
+  );
+};
+
+export default NewEnvGroup;
+
+const Subtitle = styled.div`
+  padding: 11px 0px 16px;
+  font-family: "Work Sans", sans-serif;
+  font-size: 13px;
+  color: #aaaabb;
+  line-height: 1.6em;
+  display: flex;
+  align-items: center;
+`;
+
+const Warning = styled.span<{ highlight: boolean; makeFlush?: boolean }>`
+  color: ${(props) => (props.highlight ? "#f5cb42" : "")};
+  margin-left: ${(props) => (props.makeFlush ? "" : "5px")};
+`;

+ 41 - 1
dashboard/src/main/home/cluster-dashboard/stacks/launch/Overview.tsx

@@ -6,7 +6,11 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import useAuth from "shared/auth/useAuth";
 import { useRouting } from "shared/routing";
-import { CardGrid, SubmitButton } from "./components/styles";
+import {
+  AddResourceButtonStyles,
+  CardGrid,
+  SubmitButton,
+} from "./components/styles";
 import { AppCard } from "./components/AppCard";
 import { AddResourceButton } from "./components/AddResourceButton";
 import styled from "styled-components";
@@ -14,6 +18,7 @@ import styled from "styled-components";
 import Helper from "components/form-components/Helper";
 import Heading from "components/form-components/Heading";
 import TitleSection from "components/TitleSection";
+import DynamicLink from "components/DynamicLink";
 
 const Overview = () => {
   const {
@@ -156,6 +161,23 @@ const Overview = () => {
         <AddResourceButton />
       </CardGrid>
 
+      <Heading>Env groups</Heading>
+      <CardGrid>
+        {newStack.envGroups.map((envGroup) => (
+          <>{envGroup.name}</>
+        ))}
+
+        <AddResourceButtonStyles.Wrapper>
+          <AddResourceButtonStyles.Flex>
+            <LinkMask to={`/stacks/launch/new-env-group`}></LinkMask>
+            <Icon>
+              <i className="material-icons">add</i>
+            </Icon>
+            Add a new env group
+          </AddResourceButtonStyles.Flex>
+        </AddResourceButtonStyles.Wrapper>
+      </CardGrid>
+
       <SubmitButton
         disabled={!isValid || submitButtonStatus !== ""}
         text="Create Stack"
@@ -229,3 +251,21 @@ const StyledLaunchFlow = styled.div`
     props.disableMarginTop ? "inherit" : "calc(50vh - 380px)"};
   padding-bottom: 150px;
 `;
+
+const LinkMask = styled(DynamicLink)`
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+`;
+
+const Icon = styled.div`
+  margin-bottom: -3px;
+  > i {
+    margin-right: 20px;
+    margin-left: 9px;
+    font-size: 20px;
+    color: #aaaabb;
+  }
+`;

+ 13 - 0
dashboard/src/main/home/cluster-dashboard/stacks/launch/Store.tsx

@@ -19,6 +19,8 @@ export type StacksLaunchContextType = {
 
   removeAppResource: (appResource: CreateStackBody["app_resources"][0]) => void;
 
+  addEnvGroup: (envGroup: CreateStackBody["envGroups"][0]) => void;
+
   submit: () => Promise<void>;
 };
 
@@ -27,6 +29,7 @@ const defaultValues: StacksLaunchContextType = {
     name: "",
     app_resources: [],
     source_configs: [],
+    envGroups: [],
   },
 
   namespace: "",
@@ -42,6 +45,8 @@ const defaultValues: StacksLaunchContextType = {
 
   removeAppResource: (appResource: CreateStackBody["app_resources"][0]) => {},
 
+  addEnvGroup: () => {},
+
   submit: async () => {},
 };
 
@@ -111,6 +116,13 @@ const StacksLaunchContextProvider: React.FC<{}> = ({ children }) => {
     }));
   };
 
+  const addEnvGroup: StacksLaunchContextType["addEnvGroup"] = (envGroup) => {
+    setNewStack((prev) => ({
+      ...prev,
+      envGroups: [...prev.envGroups, envGroup],
+    }));
+  };
+
   const submit: StacksLaunchContextType["submit"] = async () => {
     try {
       await api.createStack("<token>", newStack, {
@@ -134,6 +146,7 @@ const StacksLaunchContextProvider: React.FC<{}> = ({ children }) => {
         addSourceConfig,
         addAppResource,
         removeAppResource,
+        addEnvGroup,
         submit,
       }}
     >

+ 5 - 31
dashboard/src/main/home/cluster-dashboard/stacks/launch/components/AppCard.tsx

@@ -1,10 +1,8 @@
 import React, { useContext } from "react";
 import { StacksLaunchContext, StacksLaunchContextType } from "../Store";
-import { ButtonWithIcon, Card } from "./styles";
+import { ButtonWithIcon, Card, Flex, Icon } from "./styles";
 import { hardcodedIcons } from "shared/hardcodedNameDict";
 
-import styled from "styled-components";
-
 export const AppCard = ({
   app,
 }: {
@@ -17,38 +15,14 @@ export const AppCard = ({
   };
 
   return (
-    <UnclickableCard>
+    <Card variant="unclickable">
       <Flex>
         <Icon src={hardcodedIcons[app.template_name]} />
         {app.name}
       </Flex>
-      <DeleteButton onClick={handleDelete}>
+      <ButtonWithIcon variant="delete" onClick={handleDelete}>
         <i className="material-icons-outlined">close</i>
-      </DeleteButton>
-    </UnclickableCard>
+      </ButtonWithIcon>
+    </Card>
   );
 };
-
-const UnclickableCard = styled(Card)`
-  cursor: default;
-  :hover {
-    border: 1px solid #ffffff0f;
-  }
-`;
-
-const DeleteButton = styled(ButtonWithIcon)`
-  margin-right: 5px;
-`;
-
-const Flex = styled.div`
-  display: flex;
-  align-items: center;
-  font-size: 14px;
-  font-weight: 500;
-`;
-
-const Icon = styled.img`
-  height: 30px;
-  margin-right: 15px;
-  margin-left: 5px;
-`;

+ 27 - 0
dashboard/src/main/home/cluster-dashboard/stacks/launch/components/EnvGroupCard.tsx

@@ -0,0 +1,27 @@
+import React from "react";
+import { hardcodedIcons } from "shared/hardcodedNameDict";
+import { ButtonWithIcon, Card, Flex, Icon } from "./styles";
+
+const EnvGroupCard = ({
+  envGroup: { name },
+}: {
+  envGroup: { name: string };
+}) => {
+  const handleDelete = () => {
+    console.error("NOT IMPLEMENTED");
+  };
+
+  return (
+    <Card variant="unclickable">
+      <Flex>
+        <Icon src={""} />
+        {name}
+      </Flex>
+      <ButtonWithIcon variant="delete" onClick={handleDelete}>
+        <i className="material-icons-outlined">close</i>
+      </ButtonWithIcon>
+    </Card>
+  );
+};
+
+export default EnvGroupCard;

+ 39 - 6
dashboard/src/main/home/cluster-dashboard/stacks/launch/components/styles.tsx

@@ -8,22 +8,36 @@ export const CardGrid = styled.div`
   grid-row-gap: 25px;
 `;
 
-export const Card = styled.div`
+export const Card = styled.div<{ variant?: "clickable" | "unclickable" }>`
   display: flex;
   color: #ffffff;
   background: #2b2e3699;
   justify-content: space-between;
   border-radius: 5px;
-  cursor: pointer;
   height: 75px;
   padding: 12px;
   padding-left: 14px;
   border: 1px solid #ffffff0f;
   align-items: center;
 
-  :hover {
-    border: 1px solid #ffffff3c;
-  }
+  ${(props) => {
+    if (props.variant === "unclickable") {
+      return `
+      cursor: default;
+      :hover {
+        border: 1px solid #ffffff0f;
+      }
+      `;
+    }
+
+    return `
+      cursor: pointer;
+      :hover {
+        border: 1px solid #ffffff3c;
+      }
+    `;
+  }}
+
   animation: fadeIn 0.5s;
   @keyframes fadeIn {
     from {
@@ -127,7 +141,7 @@ export const SelectorStyles = {
   `,
 };
 
-export const ButtonWithIcon = styled.div`
+export const ButtonWithIcon = styled.div<{ variant?: "normal" | "delete" }>`
   display: flex;
   align-items: center;
   justify-content: center;
@@ -138,6 +152,12 @@ export const ButtonWithIcon = styled.div`
   border: 1px solid #ffffff22;
   cursor: pointer;
 
+  ${({ variant }) => {
+    if (variant === "delete") {
+      return "margin-right: 5px;";
+    }
+  }}
+
   &:hover {
     background-color: #ffffff3c;
   }
@@ -146,3 +166,16 @@ export const ButtonWithIcon = styled.div`
     font-size: 18px;
   }
 `;
+
+export const Flex = styled.div`
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  font-weight: 500;
+`;
+
+export const Icon = styled.img`
+  height: 30px;
+  margin-right: 15px;
+  margin-left: 5px;
+`;

+ 4 - 0
dashboard/src/main/home/cluster-dashboard/stacks/launch/index.tsx

@@ -2,6 +2,7 @@ import React from "react";
 import { Redirect, Route, Switch, useRouteMatch } from "react-router";
 import styled from "styled-components";
 import NewApp from "./NewApp";
+import NewEnvGroup from "./NewEnvGroup";
 import Overview from "./Overview";
 import SelectSource from "./SelectSource";
 import StacksLaunchContextProvider from "./Store";
@@ -22,6 +23,9 @@ const LaunchRoutes = () => {
           <Route path={`${path}/new-app/:template_name/:version/:repo_url?`}>
             <NewApp />
           </Route>
+          <Route path={`${path}/new-env-group`}>
+            <NewEnvGroup />
+          </Route>
           <Route path={`*`}>
             <Redirect to={`${path}/source`} />
           </Route>

+ 5 - 0
dashboard/src/main/home/cluster-dashboard/stacks/types.ts

@@ -20,6 +20,11 @@ export type CreateStackBody = {
       dockerfile?: unknown;
     };
   }[];
+
+  envGroups: {
+    name: string;
+    variables: unknown[];
+  }[];
 };
 
 export type CreateStackResponse = Stack;