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

Merge branch 'nico/por-559-support-environment-group-creation-from' of github.com:porter-dev/porter into dev

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

+ 130 - 85
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -25,6 +25,8 @@ import DeploymentType from "./DeploymentType";
 import IncidentsTab from "./incidents/IncidentsTab";
 import BuildSettingsTab from "./BuildSettingsTab";
 import { DisabledNamespacesForIncidents } from "./incidents/DisabledNamespaces";
+import { Stack } from "../stacks/types";
+import { PopulatedEnvGroup } from "components/porter-form/types";
 
 type Props = {
   namespace: string;
@@ -45,6 +47,74 @@ const getReadableDate = (s: string) => {
   return `${time} on ${date}`;
 };
 
+const useStackEnvGroups = (chart: ChartType) => {
+  const { currentProject, currentCluster, setCurrentError } = useContext(
+    Context
+  );
+  const [stackEnvGroups, setStackEnvGroups] = useState([]);
+  const [loading, setLoading] = useState(true);
+
+  const getEnvGroups = async (stack: Stack) => {
+    const envGroups = stack.latest_revision.env_groups;
+
+    const envGroupsWithValues = envGroups.map((envGroup) => {
+      return api
+        .getEnvGroup<PopulatedEnvGroup>(
+          "<token>",
+          {},
+          {
+            id: currentProject.id,
+            namespace: chart.namespace,
+            cluster_id: currentCluster.id,
+            name: envGroup.name,
+            version: envGroup.env_group_version,
+          }
+        )
+        .then((res) => res.data);
+    });
+
+    return Promise.all(envGroupsWithValues);
+  };
+
+  const getStack = (stack_id: string) =>
+    api
+      .getStack<Stack>(
+        "token",
+        {},
+        {
+          cluster_id: currentCluster.id,
+          project_id: currentProject.id,
+          stack_id,
+          namespace: chart.namespace,
+        }
+      )
+      .then((res) => res.data);
+
+  useEffect(() => {
+    const stack_id = chart.stack_id;
+    if (!stack_id) {
+      return;
+    }
+    setLoading(true);
+    getStack(stack_id)
+      .then((stack) => getEnvGroups(stack))
+      .then((populatedEnvGroups) => {
+        setStackEnvGroups(populatedEnvGroups);
+
+        setLoading(false);
+      })
+      .catch((error) => {
+        setCurrentError(error);
+      });
+  }, [chart.stack_id]);
+
+  return {
+    isStack: chart.stack_id?.length ? true : false,
+    stackEnvGroups,
+    isLoadingStackEnvGroups: loading,
+  };
+};
+
 const ExpandedChart: React.FC<Props> = (props) => {
   const [currentChart, setCurrentChart] = useState<ChartType>(
     props.currentChart
@@ -74,6 +144,12 @@ const ExpandedChart: React.FC<Props> = (props) => {
   const [isAuthorized] = useAuth();
   const [fullScreenLogs, setFullScreenLogs] = useState<boolean>(false);
 
+  const {
+    isStack,
+    stackEnvGroups,
+    isLoadingStackEnvGroups,
+  } = useStackEnvGroups(currentChart);
+
   const {
     newWebsocket,
     openWebsocket,
@@ -528,7 +604,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
       );
     }
 
-    if (currentChart?.git_action_config?.git_repo && !currentChart.is_stack) {
+    if (currentChart?.git_action_config?.git_repo && !isStack) {
       rightTabOptions.push({
         label: "Build Settings",
         value: "build-settings",
@@ -565,59 +641,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
     setDevOpsMode(!devOpsMode);
   };
 
-  const renderIcon = () => {
-    if (
-      currentChart.chart.metadata.icon &&
-      currentChart.chart.metadata.icon !== ""
-    ) {
-      return <Icon src={currentChart.chart.metadata.icon} />;
-    } else {
-      return <i className="material-icons">tonality</i>;
-    }
-  };
-
-  // const chartStatus = useMemo(() => {
-  //   const getAvailability = (kind: string, c: any) => {
-  //     switch (kind?.toLowerCase()) {
-  //       case "deployment":
-  //       case "replicaset":
-  //         return c.status.availableReplicas == c.status.replicas;
-  //       case "statefulset":
-  //         return c.status.readyReplicas == c.status.replicas;
-  //       case "daemonset":
-  //         return c.status.numberAvailable == c.status.desiredNumberScheduled;
-  //     }
-  //   };
-
-  //   const chartStatus = currentChart.info.status;
-
-  //   if (chartStatus === "deployed") {
-  //     for (var uid in controllers) {
-  //       let value = controllers[uid];
-  //       let available = getAvailability(value.metadata.kind, value);
-  //       let progressing = true;
-
-  //       controllers[uid]?.status?.conditions?.forEach((condition: any) => {
-  //         if (
-  //           condition.type == "Progressing" &&
-  //           condition.status == "False" &&
-  //           condition.reason == "ProgressDeadlineExceeded"
-  //         ) {
-  //           progressing = false;
-  //         }
-  //       });
-
-  //       if (!available && progressing) {
-  //         return "loading";
-  //       } else if (!available && !progressing) {
-  //         return "failed";
-  //       }
-  //     }
-  //     return "deployed";
-  //   }
-  //   return chartStatus;
-  // }, [currentChart, controllers]);
-
   const renderUrl = () => {
     if (url) {
       return (
@@ -840,37 +863,59 @@ const ExpandedChart: React.FC<Props> = (props) => {
                 latestVersion={currentChart.latest_version}
                 upgradeVersion={handleUpgradeVersion}
               />
-              {(isPreview || leftTabOptions.length > 0) && (
-                <BodyWrapper>
-                  <PorterFormWrapper
-                    formData={cloneDeep(currentChart.form)}
-                    valuesToOverride={{
-                      namespace: props.namespace,
-                      clusterId: currentCluster.id,
-                    }}
-                    renderTabContents={renderTabContents}
-                    isReadOnly={
-                      isPreview ||
-                      imageIsPlaceholder ||
-                      !isAuthorized("application", "", ["get", "update"])
-                    }
-                    onSubmit={onSubmit}
-                    includeMetadata
-                    rightTabOptions={rightTabOptions}
-                    leftTabOptions={leftTabOptions}
-                    color={isPreview ? "#f5cb42" : null}
-                    addendum={
-                      <TabButton
-                        onClick={toggleDevOpsMode}
-                        devOpsMode={devOpsMode}
-                      >
-                        <i className="material-icons">offline_bolt</i> DevOps
-                        Mode
-                      </TabButton>
-                    }
-                    saveValuesStatus={saveValuesStatus}
-                  />
-                </BodyWrapper>
+              {isStack && isLoadingStackEnvGroups ? (
+                <>
+                  <LineBreak />
+                  <Placeholder>
+                    <TextWrap>
+                      <Header>
+                        <Spinner src={loadingSrc} />
+                      </Header>
+                    </TextWrap>
+                  </Placeholder>
+                </>
+              ) : (
+                <>
+                  {(isPreview || leftTabOptions.length > 0) && (
+                    <BodyWrapper>
+                      <PorterFormWrapper
+                        formData={cloneDeep(currentChart.form)}
+                        valuesToOverride={{
+                          namespace: props.namespace,
+                          clusterId: currentCluster.id,
+                        }}
+                        renderTabContents={renderTabContents}
+                        isReadOnly={
+                          isPreview ||
+                          imageIsPlaceholder ||
+                          !isAuthorized("application", "", ["get", "update"])
+                        }
+                        onSubmit={onSubmit}
+                        includeMetadata
+                        rightTabOptions={rightTabOptions}
+                        leftTabOptions={leftTabOptions}
+                        color={isPreview ? "#f5cb42" : null}
+                        addendum={
+                          <TabButton
+                            onClick={toggleDevOpsMode}
+                            devOpsMode={devOpsMode}
+                          >
+                            <i className="material-icons">offline_bolt</i>{" "}
+                            DevOps Mode
+                          </TabButton>
+                        }
+                        saveValuesStatus={saveValuesStatus}
+                        injectedProps={{
+                          "key-value-array": {
+                            availableSyncEnvGroups: isStack
+                              ? stackEnvGroups
+                              : undefined,
+                          },
+                        }}
+                      />
+                    </BodyWrapper>
+                  )}
+                </>
               )}
             </>
           )}

+ 3 - 47
dashboard/src/main/home/cluster-dashboard/stacks/launch/NewApp.tsx

@@ -15,6 +15,7 @@ import styled from "styled-components";
 import Heading from "components/form-components/Heading";
 import TitleSection from "components/TitleSection";
 import { hardcodedIcons } from "shared/hardcodedNameDict";
+import { BackButton, Icon, Polymer } from "./components/styles";
 
 const DEFAULT_STACK_SOURCE_CONFIG_INDEX = 0;
 
@@ -200,7 +201,7 @@ const NewApp = () => {
   };
 
   return (
-    <StyledLaunchFlow style={{ position: "relative" }}>
+    <>
       <TitleSection>
         <DynamicLink to={`/stacks/launch/overview`}>
           <BackButton>
@@ -244,7 +245,7 @@ const NewApp = () => {
           includeMetadata
         />
       </div>
-    </StyledLaunchFlow>
+    </>
   );
 };
 
@@ -260,51 +261,6 @@ const Wrapper = styled.div`
   margin-top: calc(50vh - 150px);
 `;
 
-const Icon = styled.img`
-  width: 40px;
-  margin-right: 14px;
-
-  opacity: 0;
-  animation: floatIn 0.5s 0.2s;
-  animation-fill-mode: forwards;
-  @keyframes floatIn {
-    from {
-      opacity: 0;
-      transform: translateY(10px);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0px);
-    }
-  }
-`;
-
-const BackButton = styled.div`
-  > i {
-    cursor: pointer;
-    font-size: 24px;
-    color: #969fbbaa;
-    margin-right: 10px;
-    padding: 3px;
-    margin-left: 0px;
-    border-radius: 100px;
-    :hover {
-      background: #ffffff11;
-    }
-  }
-`;
-
-const Polymer = styled.div`
-  margin-bottom: -6px;
-
-  > i {
-    color: #ffffff;
-    font-size: 24px;
-    margin-left: 5px;
-    margin-right: 18px;
-  }
-`;
-
 const StyledLaunchFlow = styled.div`
   min-width: 300px;
   width: calc(100% - 100px);

+ 15 - 1
dashboard/src/main/home/cluster-dashboard/stacks/launch/NewEnvGroup.tsx

@@ -1,13 +1,16 @@
+import DynamicLink from "components/DynamicLink";
 import Heading from "components/form-components/Heading";
 import Helper from "components/form-components/Helper";
 import InputRow from "components/form-components/InputRow";
+import TitleSection from "components/TitleSection";
 import React, { useContext, useState } from "react";
 import { isAlphanumeric } from "shared/common";
 import { useRouting } from "shared/routing";
 import styled from "styled-components";
 import EnvGroupArray, { KeyValueType } from "../../env-groups/EnvGroupArray";
-import { SubmitButton } from "./components/styles";
+import { BackButton, Icon, Polymer, SubmitButton } from "./components/styles";
 import { StacksLaunchContext } from "./Store";
+import sliders from "assets/sliders.svg";
 
 const envArrayToObject = (variables: KeyValueType[]) => {
   return variables.reduce<{ [key: string]: string }>((acc, curr) => {
@@ -48,6 +51,17 @@ const NewEnvGroup = () => {
 
   return (
     <>
+      <TitleSection>
+        <DynamicLink to={`/stacks/launch/overview`}>
+          <BackButton>
+            <i className="material-icons">keyboard_backspace</i>
+          </BackButton>
+        </DynamicLink>
+        <Polymer>
+          <Icon src={sliders} />
+        </Polymer>
+        Add a Env Group to Stack
+      </TitleSection>
       <Heading isAtTop={true}>Name</Heading>
       <Subtitle>
         <Warning

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

@@ -107,7 +107,7 @@ const Overview = () => {
   }, [namespace, newStack.name]);
 
   return (
-    <StyledLaunchFlow style={{ position: "relative" }}>
+    <>
       <TitleSection handleNavBack={() => window.open("/stacks", "_self")}>
         <Polymer>
           <i className="material-icons">lan</i>
@@ -219,7 +219,7 @@ const Overview = () => {
       >
         Create Stack
       </SubmitButton>
-    </StyledLaunchFlow>
+    </>
   );
 };
 

+ 3 - 11
dashboard/src/main/home/cluster-dashboard/stacks/launch/SelectSource.tsx

@@ -31,7 +31,7 @@ const SelectSource = () => {
   };
 
   return (
-    <StyledLaunchFlow style={{ position: "relative" }}>
+    <>
       <TitleSection handleNavBack={() => window.open("/stacks", "_self")}>
         <Polymer>
           <i className="material-icons">lan</i>
@@ -59,7 +59,7 @@ const SelectSource = () => {
         clearPosition
         makeFlush
       />
-    </StyledLaunchFlow>
+    </>
   );
 };
 
@@ -67,7 +67,7 @@ export default SelectSource;
 
 const Br = styled.div<{ height?: string }>`
   width: 100%;
-  height: ${props => props.height || "1px"};
+  height: ${(props) => props.height || "1px"};
 `;
 
 const Required = styled.div`
@@ -86,11 +86,3 @@ const Polymer = styled.div`
     margin-right: 18px;
   }
 `;
-
-const StyledLaunchFlow = styled.div`
-  width: calc(100% - 100px);
-  margin-left: 50px;
-  min-width: 300px;
-  margin-top: ${(props: { disableMarginTop?: boolean }) =>
-    props.disableMarginTop ? "inherit" : "calc(50vh - 380px)"};
-`;

+ 45 - 0
dashboard/src/main/home/cluster-dashboard/stacks/launch/components/styles.tsx

@@ -182,3 +182,48 @@ export const SelectorStyles = {
     text-overflow: ellipsis;
   `,
 };
+
+export const BackButton = styled.div`
+  > i {
+    cursor: pointer;
+    font-size: 24px;
+    color: #969fbbaa;
+    margin-right: 10px;
+    padding: 3px;
+    margin-left: 0px;
+    border-radius: 100px;
+    :hover {
+      background: #ffffff11;
+    }
+  }
+`;
+
+export const Polymer = styled.div`
+  margin-bottom: -6px;
+
+  > i {
+    color: #ffffff;
+    font-size: 24px;
+    margin-left: 5px;
+    margin-right: 18px;
+  }
+`;
+
+export const Icon = styled.img`
+  width: 40px;
+  margin-right: 14px;
+
+  opacity: 0;
+  animation: floatIn 0.5s 0.2s;
+  animation-fill-mode: forwards;
+  @keyframes floatIn {
+    from {
+      opacity: 0;
+      transform: translateY(10px);
+    }
+    to {
+      opacity: 1;
+      transform: translateY(0px);
+    }
+  }
+`;

+ 27 - 17
dashboard/src/main/home/cluster-dashboard/stacks/launch/index.tsx

@@ -13,23 +13,25 @@ const LaunchRoutes = () => {
   return (
     <LaunchContainer>
       <StacksLaunchContextProvider>
-        <Switch>
-          <Route path={`${path}/source`}>
-            <SelectSource />
-          </Route>
-          <Route path={`${path}/overview`}>
-            <Overview />
-          </Route>
-          <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>
-        </Switch>
+        <StyledLaunchFlow>
+          <Switch>
+            <Route path={`${path}/source`}>
+              <SelectSource />
+            </Route>
+            <Route path={`${path}/overview`}>
+              <Overview />
+            </Route>
+            <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>
+          </Switch>
+        </StyledLaunchFlow>
       </StacksLaunchContextProvider>
     </LaunchContainer>
   );
@@ -41,3 +43,11 @@ const LaunchContainer = styled.div`
   margin: 0 auto;
   width: 100%;
 `;
+
+const StyledLaunchFlow = styled.div`
+  width: calc(100% - 100px);
+  margin-left: 50px;
+  min-width: 300px;
+  margin-top: ${(props: { disableMarginTop?: boolean }) =>
+    props.disableMarginTop ? "inherit" : "calc(50vh - 380px)"};
+`;

+ 1 - 1
dashboard/src/shared/types.tsx

@@ -21,7 +21,7 @@ export interface DetailedIngressError {
 }
 
 export interface ChartType {
-  is_stack: boolean;
+  stack_id: string;
   image_repo_uri: string;
   git_action_config: any;
   build_config: BuildConfig;