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

Merge branch '0.6.0-expanded-chart-speed-investigation' of https://github.com/porter-dev/porter into 0.6.0-expanded-chart-speed-investigation

jusrhee 4 лет назад
Родитель
Сommit
5f7466d0be

+ 262 - 338
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -1,4 +1,11 @@
-import React, { useContext, useState, useEffect, useRef } from "react";
+import React, {
+  useContext,
+  useState,
+  useEffect,
+  useRef,
+  useCallback,
+  useMemo,
+} from "react";
 import styled from "styled-components";
 import yaml from "js-yaml";
 import close from "assets/close.png";
@@ -25,10 +32,10 @@ import MetricsSection from "./metrics/MetricsSection";
 import ListSection from "./ListSection";
 import StatusSection from "./status/StatusSection";
 import SettingsSection from "./SettingsSection";
-import ChartList from "../chart/ChartList";
-import { withAuth, WithAuthProps } from "shared/auth/AuthorizationHoc";
+import { useWebsockets } from "shared/hooks/useWebsockets";
+import useAuth from "shared/auth/useAuth";
 
-type PropsType = WithAuthProps & {
+type Props = {
   namespace: string;
   currentChart: ChartType;
   currentCluster: ClusterType;
@@ -37,38 +44,23 @@ type PropsType = WithAuthProps & {
   isMetricsInstalled: boolean;
 };
 
-type StateType = {
-  currentChart: ChartType;
-  loading: boolean;
-  showRevisions: boolean;
-  components: ResourceType[];
-  podSelectors: string[];
-  isPreview: boolean;
-  isUpdatingChart: boolean;
-  devOpsMode: boolean;
-  tabOptions: any[];
-  saveValuesStatus: string | null;
-  forceRefreshRevisions: boolean; // Update revisions after upgrading values
-  controllers: Record<string, Record<string, any>>;
-  websockets: Record<string, any>;
-  url: string | null;
-  showDeleteOverlay: boolean;
-  deleting: boolean;
-  formData: any;
-  imageIsPlaceholder: boolean;
-  newestImage: string;
+const getReadableDate = (s: string) => {
+  let ts = new Date(s);
+  let date = ts.toLocaleDateString();
+  let time = ts.toLocaleTimeString([], {
+    hour: "numeric",
+    minute: "2-digit",
+  });
+  return `${time} on ${date}`;
 };
 
-const ExpandedChart: React.FC<PropsType> = (props) => {
+const ExpandedChart: React.FC<Props> = (props) => {
   const [currentChart, setCurrentChart] = useState<ChartType>(
     props.currentChart
   );
-  const [loading, setLoading] = useState<boolean>(true);
   const [showRevisions, setShowRevisions] = useState<boolean>(false);
   const [components, setComponents] = useState<ResourceType[]>([]);
-  const [podSelectors, setPodSelectors] = useState<string[]>([]);
   const [isPreview, setIsPreview] = useState<boolean>(false);
-  const [isUpdatingChart, setIsUpdatingChart] = useState<boolean>(false);
   const [devOpsMode, setDevOpsMode] = useState<boolean>(
     localStorage.getItem("devOpsMode") === "true"
   );
@@ -80,150 +72,128 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
   const [controllers, setControllers] = useState<
     Record<string, Record<string, any>>
   >({});
-  const controllersCallback = useRef(null);
-  const [websockets, setWebsockets] = useState<Record<string, any>>({});
   const [url, setUrl] = useState<string>(null);
   const [showDeleteOverlay, setShowDeleteOverlay] = useState<boolean>(false);
   const [deleting, setDeleting] = useState<boolean>(false);
-  const [formData, setFormData] = useState<any>({});
   const [imageIsPlaceholder, setImageIsPlaceholer] = useState<boolean>(false);
   const [newestImage, setNewestImage] = useState<string>(null);
 
+  const [isAuthorized] = useAuth();
+
+  const {
+    newWebsocket,
+    openWebsocket,
+    closeAllWebsockets,
+    closeWebsocket,
+  } = useWebsockets();
+
   const { currentCluster, currentProject, setCurrentError } = useContext(
     Context
   );
 
   // Retrieve full chart data (includes form and values)
-  const getChartData = (chart: ChartType) => {
-    let { currentCluster, currentChart } = props;
+  const getChartData = async (chart: ChartType) => {
+    const res = await api.getChart(
+      "<token>",
+      {
+        namespace: chart.namespace,
+        cluster_id: currentCluster.id,
+        storage: StorageType.Secret,
+      },
+      {
+        name: chart.name,
+        revision: chart.version,
+        id: currentProject.id,
+      }
+    );
+    const image = res.data?.config?.image?.repository;
+    const tag = res.data?.config?.image?.tag?.toString();
+    const newNewestImage = tag ? image + ":" + tag : image;
+    let imageIsPlaceholder = false;
+    if (
+      (image === "porterdev/hello-porter" ||
+        image === "public.ecr.aws/o1j4x7p4/hello-porter") &&
+      !newestImage
+    ) {
+      imageIsPlaceholder = true;
+    }
+    setCurrentChart(res.data);
+    setImageIsPlaceholer(imageIsPlaceholder);
+    setNewestImage(newNewestImage);
 
-    setLoading(true);
-    api
-      .getChart(
+    updateComponents(res.data);
+  };
+
+  const getControllers = async (chart: ChartType) => {
+    // don't retrieve controllers for chart that failed to even deploy.
+    if (chart.info.status == "failed") return;
+
+    try {
+      const { data: chartControllers } = await api.getChartControllers(
         "<token>",
         {
-          namespace: currentChart.namespace,
+          namespace: chart.namespace,
           cluster_id: currentCluster.id,
           storage: StorageType.Secret,
         },
         {
+          id: currentProject.id,
           name: chart.name,
           revision: chart.version,
-          id: currentProject.id,
         }
-      )
-      .then((res) => {
-        let image = res.data?.config?.image?.repository;
-        let tag = res.data?.config?.image?.tag?.toString();
-        let newNewestImage = tag ? image + ":" + tag : image;
-        let imageIsPlaceholder = false;
-        if (
-          (image === "porterdev/hello-porter" ||
-            image === "public.ecr.aws/o1j4x7p4/hello-porter") &&
-          !newestImage
-        ) {
-          imageIsPlaceholder = true;
-        }
-        updateComponents(
-          {
-            currentChart: res.data,
-            loading: false,
-            imageIsPlaceholder,
-            newNewestImage,
-          },
-          res.data
-        );
-      })
-      .catch(console.log);
-  };
-
-  const getControllers = async (chart: ChartType) => {
-    // don't retrieve controllers for chart that failed to even deploy.
-    if (chart.info.status == "failed") return;
-
-    // TODO: properly promisify
-    await new Promise((next: (res?: any) => void) => {
-      api
-        .getChartControllers(
-          "<token>",
-          {
-            namespace: chart.namespace,
-            cluster_id: currentCluster.id,
-            storage: StorageType.Secret,
-          },
-          {
-            id: currentProject.id,
-            name: chart.name,
-            revision: chart.version,
-          }
-        )
-        .then((res) => {
-          res.data?.forEach(async (c: any) => {
-            await new Promise((nextController: (res?: any) => void) => {
-              c.metadata.kind = c.kind;
-              controllersCallback.current = nextController;
-              setControllers({
-                ...controllers,
-                [c.metadata.uid]: c,
-              });
-            });
-          });
-          next();
-        })
-        .catch((err) => setCurrentError(JSON.stringify(err)));
-    });
-  };
+      );
 
-  const setupWebsocket = (kind: string, chart: ChartType) => {
-    let protocol = window.location.protocol == "https:" ? "wss" : "ws";
-    let ws = new WebSocket(
-      `${protocol}://${window.location.host}/api/projects/${currentProject.id}/k8s/${kind}/status?cluster_id=${currentCluster.id}`
-    );
-    ws.onopen = () => {
-      console.log("connected to websocket");
-    };
+      chartControllers.forEach((c: any) => {
+        c.metadata.kind = c.kind;
 
-    ws.onmessage = (evt: MessageEvent) => {
-      let event = JSON.parse(evt.data);
+        setControllers((oldControllers) => ({
+          ...oldControllers,
+          [c.metadata.kind]: c,
+        }));
+      });
 
-      if (event.event_type == "UPDATE") {
-        let object = event.Object;
-        object.metadata.kind = event.Kind;
+      return;
+    } catch (error) {
+      if (typeof error !== "string") {
+        setCurrentError(JSON.stringify(error));
+      }
+      setCurrentError(error);
+    }
+  };
 
-        if (!controllers[object.metadata.uid]) return;
+  const setupWebsocket = (kind: string) => {
+    const apiEndpoint = `/api/projects/${currentProject.id}/k8s/${kind}/status?cluster_id=${currentCluster.id}`;
 
-        setControllers({
-          ...controllers,
-          [object.metadata.uid]: object,
-        });
-      }
-    };
+    const wsConfig = {
+      onmessage(evt: MessageEvent) {
+        const event = JSON.parse(evt.data);
 
-    ws.onclose = () => {
-      console.log("closing websocket");
-    };
+        if (event.event_type == "UPDATE") {
+          let object = event.Object;
+          object.metadata.kind = event.Kind;
 
-    ws.onerror = (err: ErrorEvent) => {
-      console.log(err);
-      ws.close();
+          setControllers((oldControllers) => {
+            if (oldControllers[object.metadata.uid]) {
+              return oldControllers;
+            }
+            return {
+              ...oldControllers,
+              [object.metadata.uid]: object,
+            };
+          });
+        }
+      },
+      onerror() {
+        closeWebsocket(kind);
+      },
     };
 
-    return ws;
+    newWebsocket(kind, apiEndpoint, wsConfig);
   };
 
-  const setControllerWebsockets = (
-    controller_types: any[],
-    chart: ChartType
-  ) => {
-    let websockets = controller_types.map((kind: string) => {
-      return setupWebsocket(kind, chart);
-    });
-    setWebsockets(websockets);
-  };
-
-  const updateComponents = (state: any, currentChart: ChartType) => {
-    api
-      .getChartComponents(
+  const updateComponents = async (currentChart: ChartType) => {
+    try {
+      const res = await api.getChartComponents(
         "<token>",
         {
           namespace: currentChart.namespace,
@@ -235,18 +205,14 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           name: currentChart.name,
           revision: currentChart.version,
         }
-      )
-      .then((res) => {
-        setComponents(res.data.Objects);
-        setPodSelectors(res.data.PodSelectors);
-        updateTabs();
-      })
-      .catch(console.log);
+      );
+      setComponents(res.data.Objects);
+    } catch (error) {
+      console.log(error);
+    }
   };
 
-  const refreshChart = () => getChartData(currentChart);
-
-  const onSubmit = (rawValues: any) => {
+  const onSubmit = async (rawValues: any) => {
     // Convert dotted keys to nested objects
     let values = {};
 
@@ -269,10 +235,9 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
     });
 
     setSaveValueStatus("loading");
-    refreshChart();
-
-    api
-      .upgradeChartValues(
+    getChartData(currentChart);
+    try {
+      await api.upgradeChartValues(
         "<token>",
         {
           namespace: currentChart.namespace,
@@ -284,63 +249,62 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           name: currentChart.name,
           cluster_id: currentCluster.id,
         }
-      )
-      .then(() => {
-        setSaveValueStatus("successful");
-        setForceRefreshRevisions(true);
+      );
 
-        window.analytics.track("Chart Upgraded", {
-          chart: currentChart.name,
-          values: valuesYaml,
-        });
-      })
-      .catch((err) => {
-        let parsedErr =
-          err?.response?.data?.errors && err.response.data.errors[0];
+      setSaveValueStatus("successful");
+      setForceRefreshRevisions(true);
 
-        if (parsedErr) {
-          err = parsedErr;
-        }
+      window.analytics.track("Chart Upgraded", {
+        chart: currentChart.name,
+        values: valuesYaml,
+      });
+    } catch (err) {
+      const parsedErr =
+        err?.response?.data?.errors && err.response.data.errors[0];
 
-        setSaveValueStatus(err);
+      if (parsedErr) {
+        err = parsedErr;
+      }
 
-        setCurrentError(parsedErr);
+      setSaveValueStatus(err);
 
-        window.analytics.track("Failed to Upgrade Chart", {
-          chart: currentChart.name,
-          values: valuesYaml,
-          error: err,
-        });
+      setCurrentError(parsedErr);
+
+      window.analytics.track("Failed to Upgrade Chart", {
+        chart: currentChart.name,
+        values: valuesYaml,
+        error: err,
       });
+    }
   };
 
-  const handleUpgradeVersion = (version: string, cb: () => void) => {
-    // convert current values to yaml
-    let values = currentChart.config;
+  const handleUpgradeVersion = useCallback(
+    async (version: string, cb: () => void) => {
+      // convert current values to yaml
+      let values = currentChart.config;
 
-    let valuesYaml = yaml.dump({
-      ...values,
-    });
+      let valuesYaml = yaml.dump({
+        ...values,
+      });
 
-    setSaveValueStatus("loading");
-    refreshChart();
+      setSaveValueStatus("loading");
+      getChartData(currentChart);
 
-    api
-      .upgradeChartValues(
-        "<token>",
-        {
-          namespace: currentChart.namespace,
-          storage: StorageType.Secret,
-          values: valuesYaml,
-          version: version,
-        },
-        {
-          id: currentProject.id,
-          name: currentChart.name,
-          cluster_id: currentCluster.id,
-        }
-      )
-      .then(() => {
+      try {
+        await api.upgradeChartValues(
+          "<token>",
+          {
+            namespace: currentChart.namespace,
+            storage: StorageType.Secret,
+            values: valuesYaml,
+            version: version,
+          },
+          {
+            id: currentProject.id,
+            name: currentChart.name,
+            cluster_id: currentCluster.id,
+          }
+        );
         setSaveValueStatus("successful");
         setForceRefreshRevisions(true);
 
@@ -350,8 +314,7 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         });
 
         cb && cb();
-      })
-      .catch((err) => {
+      } catch (err) {
         let parsedErr =
           err?.response?.data?.errors && err.response.data.errors[0];
 
@@ -360,7 +323,6 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         }
 
         setSaveValueStatus(err);
-        setLoading(false);
         setCurrentError(parsedErr);
 
         window.analytics.track("Failed to Upgrade Chart", {
@@ -368,8 +330,10 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           values: valuesYaml,
           error: err,
         });
-      });
-  };
+      }
+    },
+    [currentChart]
+  );
 
   const renderTabContents = (currentTab: string) => {
     let { setSidebar } = props;
@@ -399,7 +363,7 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         return (
           <SettingsSection
             currentChart={chart}
-            refreshChart={refreshChart}
+            refreshChart={() => getChartData(currentChart)}
             setShowDeleteOverlay={(x: boolean) => setShowDeleteOverlay(x)}
           />
         );
@@ -426,8 +390,8 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         return (
           <ValuesYaml
             currentChart={chart}
-            refreshChart={refreshChart}
-            disabled={!props.isAuthorized("application", "", ["get", "update"])}
+            refreshChart={() => getChartData(currentChart)}
+            disabled={!isAuthorized("application", "", ["get", "update"])}
           />
         );
       default:
@@ -435,11 +399,6 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
   };
 
   const updateTabs = () => {
-    let formData = currentChart.form;
-    if (formData) {
-      setFormData(formData);
-    }
-
     // Collate non-form tabs
     let tabOptions = [] as any[];
     tabOptions.push({ label: "Status", value: "status" });
@@ -458,12 +417,12 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
     }
 
     // Settings tab is always last
-    if (props.isAuthorized("application", "", ["get", "delete"])) {
+    if (isAuthorized("application", "", ["get", "delete"])) {
       tabOptions.push({ label: "Settings", value: "settings" });
     }
 
     // Filter tabs if previewing an old revision or updating the chart version
-    if (isPreview || isUpdatingChart) {
+    if (isPreview) {
       let liveTabs = ["status", "settings", "deploy", "metrics"];
       tabOptions = tabOptions.filter(
         (tab: any) => !liveTabs.includes(tab.value)
@@ -494,17 +453,21 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
     }
   };
 
-  const readableDate = (s: string) => {
-    let ts = new Date(s);
-    let date = ts.toLocaleDateString();
-    let time = ts.toLocaleTimeString([], {
-      hour: "numeric",
-      minute: "2-digit",
-    });
-    return `${time} on ${date}`;
-  };
+  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;
 
-  const getChartStatus = (chartStatus: string) => {
     if (chartStatus === "deployed") {
       for (var uid in controllers) {
         let value = controllers[uid];
@@ -530,57 +493,7 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
       return "deployed";
     }
     return chartStatus;
-  };
-
-  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;
-    }
-  };
-
-  useEffect(() => {
-    window.analytics.track("Opened Chart", {
-      chart: currentChart.name,
-    });
-
-    getChartData(currentChart);
-    getControllers(currentChart); // isn't this async?
-    setControllerWebsockets(
-      ["deployment", "statefulset", "daemonset", "replicaset"],
-      currentChart
-    );
-
-    api
-      .getChartComponents(
-        "<token>",
-        {
-          namespace: currentChart.namespace,
-          cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
-        },
-        {
-          id: currentProject.id,
-          name: currentChart.name,
-          revision: currentChart.version,
-        }
-      )
-      .then((res) => setComponents(res.data.Objects))
-      .catch(console.log);
-
-    return () => {
-      if (websockets?.length > 0) {
-        websockets?.forEach((ws: WebSocket) => {
-          ws.close();
-        });
-      }
-    };
-  }, []);
+  }, [currentChart, controllers]);
 
   const renderUrl = () => {
     if (url) {
@@ -590,34 +503,28 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           {url}
         </Url>
       );
-    } else {
-      let serviceName = null as string;
-      let serviceNamespace = null as string;
-
-      components?.forEach((c: any) => {
-        if (c.Kind == "Service") {
-          serviceName = c.Name;
-          serviceNamespace = c.Namespace;
-        }
-      });
+    }
 
-      if (!serviceName || !serviceNamespace) {
-        return;
-      }
+    const service: any = components?.find((c) => {
+      return c.Kind === "Service";
+    });
 
-      return (
-        <Url>
-          <Bolded>Internal URI:</Bolded>
-          {`${serviceName}.${serviceNamespace}.svc.cluster.local`}
-        </Url>
-      );
+    if (!service?.Name || !service?.Namespace) {
+      return;
     }
+
+    return (
+      <Url>
+        <Bolded>Internal URI:</Bolded>
+        {`${service.Name}.${service.Namespace}.svc.cluster.local`}
+      </Url>
+    );
   };
 
-  const handleUninstallChart = () => {
+  const handleUninstallChart = async () => {
     setDeleting(true);
-    api
-      .uninstallTemplate(
+    try {
+      await api.uninstallTemplate(
         "<token>",
         {},
         {
@@ -627,34 +534,45 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           id: currentProject.id,
           cluster_id: currentCluster.id,
         }
-      )
-      .then((res) => {
-        setShowDeleteOverlay(false);
-        props.closeChart();
-      })
-      .catch(console.log);
-  };
-
-  const renderDeleteOverlay = () => {
-    if (deleting) {
-      return (
-        <DeleteOverlay>
-          <Loading />
-        </DeleteOverlay>
       );
+      setShowDeleteOverlay(false);
+      props.closeChart();
+    } catch (error) {
+      console.log(error);
+      setCurrentError("Couldn't uninstall chart, please try again");
     }
   };
 
   useEffect(() => {
-    if (controllersCallback.current) controllersCallback.current();
-  }, [controllers]);
+    window.analytics.track("Opened Chart", {
+      chart: currentChart.name,
+    });
+
+    getChartData(currentChart).then(() => {
+      getControllers(currentChart).then(() => {
+        ["deployment", "statefulset", "daemonset", "replicaset"]
+          .map((kind) => {
+            setupWebsocket(kind);
+            return kind;
+          })
+          .forEach((kind) => {
+            openWebsocket(kind);
+          });
+      });
+    });
+
+    return () => {
+      closeAllWebsockets();
+    };
+  }, []);
 
   useEffect(() => {
     updateTabs();
     localStorage.setItem("devOpsMode", devOpsMode.toString());
-  }, [devOpsMode]);
+  }, [devOpsMode, currentChart?.form, isPreview]);
 
   useEffect(() => {
+    let isSubscribed = true;
     let ingressName = null;
     for (var i = 0; i < components.length; i++) {
       if (components[i].Kind === "Ingress") {
@@ -662,6 +580,8 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
       }
     }
 
+    if (!ingressName) return;
+
     api
       .getIngress(
         "<token>",
@@ -675,6 +595,9 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         }
       )
       .then((res) => {
+        if (!isSubscribed) {
+          return;
+        }
         if (res.data?.spec?.rules && res.data?.spec?.rules[0]?.host) {
           setUrl(`https://${res.data?.spec?.rules[0]?.host}`);
           return;
@@ -688,15 +611,12 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
         }
       })
       .catch(console.log);
+    return () => (isSubscribed = false);
   }, [components]);
 
-  let { closeChart } = props;
-  let chart = currentChart;
-  let status = getChartStatus(chart.info.status);
-
   return (
     <>
-      <CloseOverlay onClick={closeChart} />
+      <CloseOverlay onClick={props.closeChart} />
       <StyledExpandedChart>
         <ConfirmOverlay
           show={showDeleteOverlay}
@@ -704,35 +624,38 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           onYes={handleUninstallChart}
           onNo={() => setShowDeleteOverlay(false)}
         />
-        {renderDeleteOverlay()}
-
+        {deleting && (
+          <DeleteOverlay>
+            <Loading />
+          </DeleteOverlay>
+        )}
         <HeaderWrapper>
           <TitleSection>
             <Title>
               <IconWrapper>{renderIcon()}</IconWrapper>
-              {chart.name}
+              {currentChart.name}
             </Title>
-            {chart.chart.metadata.name != "worker" &&
-              chart.chart.metadata.name != "job" &&
+            {currentChart.chart.metadata.name != "worker" &&
+              currentChart.chart.metadata.name != "job" &&
               renderUrl()}
             <InfoWrapper>
               <StatusIndicator
                 controllers={controllers}
-                status={chart.info.status}
+                status={currentChart.info.status}
                 margin_left={"0px"}
               />
               <LastDeployed>
                 <Dot>•</Dot>Last deployed
-                {" " + readableDate(chart.info.last_deployed)}
+                {" " + getReadableDate(currentChart.info.last_deployed)}
               </LastDeployed>
             </InfoWrapper>
 
             <TagWrapper>
-              Namespace <NamespaceTag>{chart.namespace}</NamespaceTag>
+              Namespace <NamespaceTag>{currentChart.namespace}</NamespaceTag>
             </TagWrapper>
           </TitleSection>
 
-          <CloseButton onClick={closeChart}>
+          <CloseButton onClick={props.closeChart}>
             <CloseButtonImg src={close} />
           </CloseButton>
 
@@ -741,17 +664,18 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
             toggleShowRevisions={() => {
               setShowRevisions(!showRevisions);
             }}
-            chart={chart}
-            refreshChart={refreshChart}
+            chart={currentChart}
+            refreshChart={() => getChartData(currentChart)}
             setRevision={setRevision}
             forceRefreshRevisions={forceRefreshRevisions}
             refreshRevisionsOff={() => setForceRefreshRevisions(false)}
-            status={status}
+            status={chartStatus}
             shouldUpdate={
-              chart.latest_version &&
-              chart.latest_version !== chart.chart.metadata.version
+              currentChart.latest_version &&
+              currentChart.latest_version !==
+                currentChart.chart.metadata.version
             }
-            latestVersion={chart.latest_version}
+            latestVersion={currentChart.latest_version}
             upgradeVersion={handleUpgradeVersion}
           />
         </HeaderWrapper>
@@ -759,9 +683,9 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
           <FormWrapper
             isReadOnly={
               imageIsPlaceholder ||
-              props.isAuthorized("application", "", ["get", "update"])
+              !isAuthorized("application", "", ["get", "update"])
             }
-            formData={formData}
+            formData={currentChart.form}
             tabOptions={tabOptions}
             isInModal={true}
             renderTabContents={renderTabContents}
@@ -784,7 +708,7 @@ const ExpandedChart: React.FC<PropsType> = (props) => {
   );
 };
 
-export default withAuth(ExpandedChart);
+export default ExpandedChart;
 
 const TextWrap = styled.div``;
 

+ 1 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/ListSection.tsx

@@ -128,6 +128,7 @@ const TabWrapper = styled.div`
   margin-right: 10px;
   border-radius: 5px;
   overflow: hidden;
+  overflow-y: auto;
 `;
 
 const FlexWrapper = styled.div`

+ 1 - 1
dashboard/src/shared/auth/AuthContext.tsx

@@ -16,7 +16,7 @@ const AuthProvider: React.FC = ({ children }) => {
 
   useEffect(() => {
     let isSubscribed = true;
-    if (!user) {
+    if (!user || !currentProject?.id) {
       setCurrentPolicy(null);
     } else {
       api