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

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

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

+ 6 - 101
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -1,10 +1,4 @@
-import React, {
-  useCallback,
-  useContext,
-  useEffect,
-  useRef,
-  useState,
-} from "react";
+import React, { useCallback, useContext, useEffect, useState } from "react";
 import styled from "styled-components";
 import yaml from "js-yaml";
 import backArrow from "assets/back_arrow.png";
@@ -31,9 +25,7 @@ import DeploymentType from "./DeploymentType";
 import IncidentsTab from "./incidents/IncidentsTab";
 import BuildSettingsTab from "./BuildSettingsTab";
 import { DisabledNamespacesForIncidents } from "./incidents/DisabledNamespaces";
-import { FullStackRevision, Stack } from "../stacks/types";
-import { PopulatedEnvGroup } from "components/porter-form/types";
-import { usePrevious } from "shared/hooks/usePrevious";
+import { useStackEnvGroups } from "./useStackEnvGroups";
 
 type Props = {
   namespace: string;
@@ -54,94 +46,6 @@ 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 stackRevisionCache = useRef<{ [id: number]: FullStackRevision }>({});
-
-  const getEnvGroups = async (stackRevision: FullStackRevision) => {
-    const envGroups = stackRevision.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 getStackRevision = (
-    stack_id: string,
-    namespace: string,
-    revision_id: number
-  ) => {
-    if (stackRevisionCache.current[revision_id]) {
-      return Promise.resolve(stackRevisionCache.current[revision_id]);
-    }
-
-    return api
-      .getStackRevision<FullStackRevision>(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          cluster_id: currentCluster.id,
-          namespace,
-          revision_id,
-          stack_id,
-        }
-      )
-      .then((res) => {
-        const newRevision = res.data;
-        stackRevisionCache.current = {
-          ...stackRevisionCache.current,
-          [newRevision.id]: newRevision,
-        };
-        return newRevision;
-      });
-  };
-
-  useEffect(() => {
-    const stack_id = chart.stack_id;
-    if (!stack_id) {
-      return;
-    }
-
-    setLoading(true);
-
-    getStackRevision(stack_id, chart.namespace, chart.version)
-      .then((stackRevision) => getEnvGroups(stackRevision))
-      .then((populatedEnvGroups) => {
-        setStackEnvGroups(populatedEnvGroups);
-
-        setLoading(false);
-      })
-      .catch((error) => {
-        setCurrentError(error);
-      });
-  }, [chart]);
-
-  return {
-    isStack: chart.stack_id?.length ? true : false,
-    stackEnvGroups,
-    isLoadingStackEnvGroups: loading,
-  };
-};
-
 const ExpandedChart: React.FC<Props> = (props) => {
   const [currentChart, setCurrentChart] = useState<ChartType>(
     props.currentChart
@@ -934,9 +838,10 @@ const ExpandedChart: React.FC<Props> = (props) => {
                         saveValuesStatus={saveValuesStatus}
                         injectedProps={{
                           "key-value-array": {
-                            availableSyncEnvGroups: isStack
-                              ? stackEnvGroups
-                              : undefined,
+                            availableSyncEnvGroups:
+                              isStack && !isPreview
+                                ? stackEnvGroups
+                                : undefined,
                           },
                         }}
                       />

+ 14 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -28,6 +28,7 @@ import CommandLineIcon from "assets/command-line-icon";
 import CronParser from "cron-parser";
 import CronPrettifier from "cronstrue";
 import BuildSettingsTab from "./BuildSettingsTab";
+import { useStackEnvGroups } from "./useStackEnvGroups";
 
 const readableDate = (s: string) => {
   let ts = new Date(s);
@@ -69,6 +70,12 @@ export const ExpandedJobChartFC: React.FC<{
     setSelectedJob,
   } = useJobs(chart);
 
+  const {
+    isStack,
+    stackEnvGroups,
+    isLoadingStackEnvGroups,
+  } = useStackEnvGroups(chart);
+
   const [devOpsMode, setDevOpsMode] = useState(
     () => localStorage.getItem("devOpsMode") === "true"
   );
@@ -283,7 +290,7 @@ export const ExpandedJobChartFC: React.FC<{
 
   const formData = useMemo(() => cloneDeep(chart?.form || {}), [chart]);
 
-  if (status === "loading") {
+  if (status === "loading" || isLoadingStackEnvGroups) {
     return <Loading />;
   }
 
@@ -378,6 +385,12 @@ export const ExpandedJobChartFC: React.FC<{
                   <i className="material-icons">offline_bolt</i> DevOps Mode
                 </TabButton>
               }
+              injectedProps={{
+                "key-value-array": {
+                  availableSyncEnvGroups:
+                    isStack && !disableForm ? stackEnvGroups : undefined,
+                },
+              }}
             />
           )}
         </BodyWrapper>

+ 74 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/useStackEnvGroups.ts

@@ -0,0 +1,74 @@
+import { PopulatedEnvGroup } from "components/porter-form/types";
+import { useContext, useEffect, useState } from "react";
+import api from "shared/api";
+import { Context } from "shared/Context";
+import { ChartType } from "shared/types";
+import { Stack } from "../stacks/types";
+
+export 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,
+  };
+};

+ 31 - 1
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/components/EnvGroups.tsx

@@ -5,6 +5,8 @@ import { Card } from "../../launch/components/styles";
 import { Stack } from "../../types";
 import sliders from "assets/sliders.svg";
 import DynamicLink from "components/DynamicLink";
+import Placeholder from "components/Placeholder";
+import Loading from "components/Loading";
 
 type PopulatedEnvGroup = {
   applications: string[];
@@ -18,6 +20,7 @@ type PopulatedEnvGroup = {
 
 const EnvGroups = ({ stack }: { stack: Stack }) => {
   const { currentProject, currentCluster } = useContext(Context);
+  const [isLoading, setIsLoading] = useState(true);
   const [envGroups, setEnvGroups] = useState<PopulatedEnvGroup[]>([]);
 
   const getEnvGroups = async () => {
@@ -42,13 +45,40 @@ const EnvGroups = ({ stack }: { stack: Stack }) => {
   };
 
   useEffect(() => {
+    let isSubscribed = true;
     getEnvGroups().then((envGroups) => {
+      if (!isSubscribed) {
+        return;
+      }
       setEnvGroups(envGroups);
+      setIsLoading(false);
     });
+
+    return () => {
+      isSubscribed = false;
+    };
   }, [stack]);
 
+  if (isLoading) {
+    return (
+      <Placeholder height="250px">
+        <Loading />
+      </Placeholder>
+    );
+  }
+
+  if (envGroups.length === 0) {
+    return (
+      <Placeholder height="250px">
+        <div>
+          <h3>No environment groups found for this stack</h3>
+        </div>
+      </Placeholder>
+    );
+  }
+
   return (
-    <Card.Grid>
+    <Card.Grid style={{ marginTop: "0px" }}>
       {envGroups.map((envGroup) => {
         return (
           <Card.Wrapper>

+ 27 - 1
dashboard/src/main/home/cluster-dashboard/stacks/launch/NewApp.tsx

@@ -16,9 +16,33 @@ import Heading from "components/form-components/Heading";
 import TitleSection from "components/TitleSection";
 import { hardcodedIcons } from "shared/hardcodedNameDict";
 import { BackButton, Icon, Polymer } from "./components/styles";
+import { PopulatedEnvGroup } from "components/porter-form/types";
+import { CreateStackBody } from "../types";
 
 const DEFAULT_STACK_SOURCE_CONFIG_INDEX = 0;
 
+const parseEnvGroup = (namespace: string) => (
+  envGroup: CreateStackBody["env_groups"][0]
+): PopulatedEnvGroup => {
+  const variables = envGroup?.variables || {};
+  const secretVariables = envGroup?.secret_variables || {};
+
+  return {
+    name: envGroup.name,
+    version: 1,
+    namespace,
+    applications: envGroup.linked_applications,
+    meta_version: 2,
+    variables: {
+      ...variables,
+      ...Object.keys(secretVariables).reduce((acc, key) => {
+        acc[key] = "PORTERSECRET_" + key;
+        return acc;
+      }, {} as any),
+    },
+  };
+};
+
 const NewApp = () => {
   const { addAppResource, newStack, namespace } = useContext(
     StacksLaunchContext
@@ -239,7 +263,9 @@ const NewApp = () => {
           valuesToOverride={{ namespace }}
           injectedProps={{
             "key-value-array": {
-              availableSyncEnvGroups: newStack.env_groups as any,
+              availableSyncEnvGroups: newStack.env_groups.map(
+                parseEnvGroup(namespace)
+              ),
             },
           }}
           includeMetadata

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

@@ -151,22 +151,18 @@ const Overview = () => {
         />
       </ClusterSection>
 
-      <Heading>Applications</Heading>
-      <Helper>
-        At least one application is required:
-        <Required>*</Required>
-      </Helper>
+      <Heading>Env groups</Heading>
       <Card.Grid>
-        {newStack.app_resources.map((app) => (
-          <Card.Wrapper>
+        {newStack.env_groups.map((envGroup) => (
+          <Card.Wrapper variant="unclickable">
             <Card.Title>
-              <Card.Icon src={hardcodedIcons[app.template_name]}></Card.Icon>
-              {app.name}
+              <Card.Icon src={sliders} />
+              {envGroup.name}
             </Card.Title>
             <Card.Actions>
               <Card.ActionButton
                 onClick={() => {
-                  removeAppResource(app);
+                  removeEnvGroup(envGroup);
                 }}
               >
                 <i className="material-icons-outlined">close</i>
@@ -175,21 +171,33 @@ const Overview = () => {
           </Card.Wrapper>
         ))}
 
-        <AddResourceButton />
+        <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>
       </Card.Grid>
 
-      <Heading>Env groups</Heading>
+      <Heading>Applications</Heading>
+      <Helper>
+        At least one application is required:
+        <Required>*</Required>
+      </Helper>
       <Card.Grid>
-        {newStack.env_groups.map((envGroup) => (
-          <Card.Wrapper variant="unclickable">
+        {newStack.app_resources.map((app) => (
+          <Card.Wrapper>
             <Card.Title>
-              <Card.Icon src={sliders} />
-              {envGroup.name}
+              <Card.Icon src={hardcodedIcons[app.template_name]}></Card.Icon>
+              {app.name}
             </Card.Title>
             <Card.Actions>
               <Card.ActionButton
                 onClick={() => {
-                  removeEnvGroup(envGroup);
+                  removeAppResource(app);
                 }}
               >
                 <i className="material-icons-outlined">close</i>
@@ -198,15 +206,7 @@ const Overview = () => {
           </Card.Wrapper>
         ))}
 
-        <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>
+        <AddResourceButton />
       </Card.Grid>
 
       <SubmitButton

+ 11 - 2
internal/stacks/hooks.go

@@ -138,9 +138,18 @@ func UpdateEnvGroupVersion(config *config.Config, projID, clusterID uint, envGro
 		return err
 	}
 
-	for _, clonedEnvGroup := range clonedEnvGroups {
+	for i, clonedEnvGroup := range clonedEnvGroups {
 		if clonedEnvGroup.Name == envGroup.Name {
-			clonedEnvGroup.EnvGroupVersion = envGroup.Version
+			clonedEnvGroups[i].EnvGroupVersion = envGroup.Version
+		}
+	}
+
+	// find all synced apps which should have an updated revision number
+	for i, clonedAppResource := range clonedAppResources {
+		for _, appName := range envGroup.Applications {
+			if clonedAppResource.Name == appName {
+				clonedAppResources[i].HelmRevisionID = clonedAppResource.HelmRevisionID + 1
+			}
 		}
 	}