Sfoglia il codice sorgente

Merge branch 'master' of github.com:porter-dev/porter into 0.7.0-fix-empty-selector-query-on-metrics-tab

jnfrati 4 anni fa
parent
commit
14c8d6e2fe
28 ha cambiato i file con 341 aggiunte e 305 eliminazioni
  1. 1 1
      dashboard/src/components/ExpandableResource.tsx
  2. 2 2
      dashboard/src/components/form-components/KeyValueArray.tsx
  3. 1 1
      dashboard/src/components/porter-form/FormDebugger.tsx
  4. 1 1
      dashboard/src/components/porter-form/PorterForm.tsx
  5. 14 2
      dashboard/src/components/porter-form/field-components/Input.tsx
  6. 17 8
      dashboard/src/components/porter-form/field-components/KeyValueArray.tsx
  7. 1 1
      dashboard/src/components/porter-form/field-components/ResourceList.tsx
  8. 1 1
      dashboard/src/components/porter-form/field-components/ServiceIPList.tsx
  9. 1 1
      dashboard/src/components/repo-selector/ContentsList.tsx
  10. 18 1
      dashboard/src/main/home/Home.tsx
  11. 1 1
      dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx
  12. 1 1
      dashboard/src/main/home/cluster-dashboard/chart/ChartList.tsx
  13. 8 2
      dashboard/src/main/home/cluster-dashboard/dashboard/ClusterSettings.tsx
  14. 75 65
      dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx
  15. 107 117
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx
  16. 3 5
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChartWrapper.tsx
  17. 63 83
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx
  18. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/GraphSection.tsx
  19. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ListSection.tsx
  20. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/RevisionSection.tsx
  21. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx
  22. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx
  23. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobList.tsx
  24. 1 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx
  25. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/status/StatusSection.tsx
  26. 1 0
      dashboard/src/main/home/modals/LoadEnvGroupModal.tsx
  27. 8 0
      dashboard/src/shared/Context.tsx
  28. 6 0
      dashboard/src/shared/types.tsx

+ 1 - 1
dashboard/src/components/ExpandableResource.tsx

@@ -73,7 +73,7 @@ const Status = styled.div`
 `;
 
 const StatusSection = styled.div`
-  border-radius: 5px;
+  border-radius: 8px;
   background: #ffffff11;
   font-size: 13px;
   padding: 20px 20px 25px;

+ 2 - 2
dashboard/src/components/form-components/KeyValueArray.tsx

@@ -75,7 +75,7 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
   };
 
   objectToValues = (obj: Record<string, string>): KeyValue[] => {
-    return Object.entries(obj).map(([key, value]) => ({ key, value }));
+    return Object.entries(obj)?.map(([key, value]) => ({ key, value }));
   };
 
   renderDeleteButton = (i: number) => {
@@ -109,7 +109,7 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
   renderInputList = () => {
     return (
       <>
-        {this.state.values.map((entry: any, i: number) => {
+        {this.state.values?.map((entry: any, i: number) => {
           // Preprocess non-string env values set via raw Helm values
           let { value } = entry;
           if (typeof value === "object") {

+ 1 - 1
dashboard/src/components/porter-form/FormDebugger.tsx

@@ -185,7 +185,7 @@ const TabWrapper = styled.div`
   background: #ffffff11;
   height: 200px;
   width: 100%;
-  border-radius: 5px;
+  border-radius: 8px;
   display: flex;
   align-items: center;
   justify-content: center;

+ 1 - 1
dashboard/src/components/porter-form/PorterForm.tsx

@@ -223,7 +223,7 @@ const StyledPorterForm = styled.div<{ showSave?: boolean }>`
   color: #ffffff;
   padding: 0px 35px 25px;
   position: relative;
-  border-radius: 5px;
+  border-radius: 8px;
   font-size: 13px;
   overflow: auto;
 `;

+ 14 - 2
dashboard/src/components/porter-form/field-components/Input.tsx

@@ -19,6 +19,18 @@ const Input: React.FC<InputField> = ({
   isReadOnly,
   value,
 }) => {
+  const clipOffUnit = (x: string) => {
+    let unit = settings?.unit;
+    if (typeof x === "string" && unit) {
+      return unit === x.slice(x.length - unit.length, x.length) ? (
+        x.slice(0, x.length - unit.length)
+      ) : (
+        x
+      );
+    }
+    return x;
+  }
+
   const {
     state,
     variables,
@@ -31,7 +43,7 @@ const Input: React.FC<InputField> = ({
         : settings?.default != undefined,
     },
     initVars: {
-      [variable]: value ? value[0] : settings?.default,
+      [variable]: value ? clipOffUnit(value[0]) : settings?.default,
     },
   });
 
@@ -85,7 +97,7 @@ export const getFinalVariablesForStringInput: GetFinalVariablesFunction = (
   const val = vars[props.variable] || props.settings?.default;
   return {
     [props.variable]:
-      props.settings?.unit && props.settings?.omitUnitFromValue === false
+      props.settings?.unit && !props.settings.omitUnitFromValue
         ? val + props.settings.unit
         : val,
   };

+ 17 - 8
dashboard/src/components/porter-form/field-components/KeyValueArray.tsx

@@ -24,7 +24,7 @@ const KeyValueArray: React.FC<Props> = (props) => {
       initState: {
         values:
           props.value && props.value[0]
-            ? (Object.entries(props.value[0]).map(([k, v]) => {
+            ? (Object.entries(props.value[0])?.map(([k, v]) => {
                 return { key: k, value: v };
               }) as any[])
             : [],
@@ -132,7 +132,16 @@ const KeyValueArray: React.FC<Props> = (props) => {
     }
   };
 
+  const getProcessedValues = (): any => {
+    let obj = {} as any;
+    state.values?.forEach(({ key, value }) => {
+      obj[key] = value;
+    });
+    return obj;
+  }
+
   const renderEnvModal = () => {
+    console.log(state.values)
     if (state.showEnvModal) {
       return (
         <Modal
@@ -145,7 +154,7 @@ const KeyValueArray: React.FC<Props> = (props) => {
           height="542px"
         >
           <LoadEnvGroupModal
-            existingValues={variables}
+            existingValues={getProcessedValues()}
             namespace={variables.namespace}
             clusterId={variables.clusterId}
             closeModal={() =>
@@ -159,15 +168,15 @@ const KeyValueArray: React.FC<Props> = (props) => {
               setState((prev) => {
                 return {
                   // might be broken
-                  values: {
+                  values: [
                     ...prev.values,
-                    ...Object.entries(values).map(([k, v]) => {
+                    ...Object.entries(values)?.map(([k, v]) => {
                       return {
                         key: k,
                         value: v,
                       };
                     }),
-                  },
+                  ],
                 };
               });
             }}
@@ -211,7 +220,7 @@ const KeyValueArray: React.FC<Props> = (props) => {
   const renderInputList = () => {
     return (
       <>
-        {state.values.map((entry: any, i: number) => {
+        {state.values?.map((entry: any, i: number) => {
           // Preprocess non-string env values set via raw Helm values
           let { value } = entry;
           if (typeof value === "object") {
@@ -230,7 +239,7 @@ const KeyValueArray: React.FC<Props> = (props) => {
                   e.persist();
                   setState((prev) => {
                     return {
-                      values: prev.values.map((t, j) => {
+                      values: prev.values?.map((t, j) => {
                         if (j == i) {
                           return {
                             ...t,
@@ -254,7 +263,7 @@ const KeyValueArray: React.FC<Props> = (props) => {
                   e.persist();
                   setState((prev) => {
                     return {
-                      values: prev.values.map((t, j) => {
+                      values: prev.values?.map((t, j) => {
                         if (j == i) {
                           return {
                             ...t,

+ 1 - 1
dashboard/src/components/porter-form/field-components/ResourceList.tsx

@@ -27,6 +27,6 @@ export default ResourceList;
 const ResourceListWrapper = styled.div`
   margin-bottom: 15px;
   margin-top: 20px;
-  border-radius: 5px;
+  border-radius: 8px;
   overflow: hidden;
 `;

+ 1 - 1
dashboard/src/components/porter-form/field-components/ServiceIPList.tsx

@@ -18,6 +18,6 @@ export default ServiceIPList;
 const ResourceList = styled.div`
   margin-bottom: 15px;
   margin-top: 20px;
-  border-radius: 5px;
+  border-radius: 8px;
   overflow: hidden;
 `;

+ 1 - 1
dashboard/src/components/repo-selector/ContentsList.tsx

@@ -642,7 +642,7 @@ const Banner = styled.div`
   margin: 5px 0 10px;
   font-size: 13px;
   display: flex;
-  border-radius: 5px;
+  border-radius: 8px;
   padding-left: 15px;
   align-items: center;
   background: #ffffff11;

+ 18 - 1
dashboard/src/main/home/Home.tsx

@@ -485,7 +485,13 @@ class Home extends Component<PropsType, StateType> {
   };
 
   render() {
-    let { currentModal, setCurrentModal, currentProject } = this.context;
+    let { 
+      currentModal, 
+      setCurrentModal, 
+      currentProject,
+      currentOverlay,
+      setCurrentOverlay,
+    } = this.context;
 
     return (
       <StyledHome>
@@ -572,6 +578,17 @@ class Home extends Component<PropsType, StateType> {
           </Modal>
         )}
 
+        {
+          currentOverlay && (
+            <ConfirmOverlay
+              show={true}
+              message={currentOverlay.message}
+              onYes={currentOverlay.onYes}
+              onNo={currentOverlay.onNo}
+            />
+          )
+        }
+
         {this.renderSidebar()}
 
         <ViewWrapper>

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx

@@ -252,7 +252,7 @@ const StyledChart = styled.div`
   cursor: pointer;
   margin-bottom: 25px;
   padding: 1px;
-  border-radius: 5px;
+  border-radius: 8px;
   box-shadow: 0 5px 8px 0px #00000033;
   position: relative;
   border: 2px solid #9eb4ff00;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/chart/ChartList.tsx

@@ -278,5 +278,5 @@ const LoadingWrapper = styled.div`
 `;
 
 const StyledChartList = styled.div`
-  padding-bottom: 85px;
+  padding-bottom: 105px;
 `;

+ 8 - 2
dashboard/src/main/home/cluster-dashboard/dashboard/ClusterSettings.tsx

@@ -122,6 +122,7 @@ const ClusterSettings: React.FC = () => {
     <div>
       <StyledSettingsSection showSource={false}>
         {keyRotationSection}
+        <DarkMatter />
         <Heading>Delete Cluster</Heading>
         {helperText}
         <Button
@@ -137,14 +138,19 @@ const ClusterSettings: React.FC = () => {
 
 export default ClusterSettings;
 
+const DarkMatter = styled.div`
+  width: 100%;
+  margin-top: -15px;
+`;
+
 const StyledSettingsSection = styled.div<{ showSource: boolean }>`
   margin-top: 35px;
   width: 100%;
   background: #ffffff11;
   padding: 0 35px;
-  padding-bottom: 50px;
+  padding-bottom: 15px;
   position: relative;
-  border-radius: 5px;
+  border-radius: 8px;
   overflow: auto;
   height: ${(props) => (props.showSource ? "calc(100% - 55px)" : "100%")};
 `;

+ 75 - 65
dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx

@@ -4,6 +4,7 @@ import close from "assets/close.png";
 import backArrow from "assets/back_arrow.png";
 import key from "assets/key.svg";
 import _ from "lodash";
+import loading from "assets/loading.gif";
 
 import { ChartType, StorageType, ClusterType } from "shared/types";
 import { Context } from "shared/Context";
@@ -12,7 +13,6 @@ import api from "shared/api";
 
 import TitleSection from "components/TitleSection";
 import SaveButton from "components/SaveButton";
-import ConfirmOverlay from "components/ConfirmOverlay";
 import Loading from "components/Loading";
 import TabRegion from "components/TabRegion";
 import EnvGroupArray, { KeyValueType } from "./EnvGroupArray";
@@ -31,7 +31,6 @@ type PropsType = WithAuthProps & {
 type StateType = {
   loading: boolean;
   currentTab: string | null;
-  showDeleteOverlay: boolean;
   deleting: boolean;
   saveValuesStatus: string | null;
   envGroup: EnvGroup;
@@ -54,7 +53,6 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
   state = {
     loading: true,
     currentTab: "environment",
-    showDeleteOverlay: false,
     deleting: false,
     saveValuesStatus: null as string | null,
     envGroup: {
@@ -303,6 +301,9 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
                 >
                   Rename {name}
                 </Button>
+
+                <DarkMatter />
+
                 <Heading>Manage Environment Group</Heading>
                 <Helper>
                   Permanently delete this set of environment variables. This
@@ -310,7 +311,13 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
                 </Helper>
                 <Button
                   color="#b91133"
-                  onClick={() => this.setState({ showDeleteOverlay: true })}
+                  onClick={() => {
+                    this.context.setCurrentOverlay({
+                      message: `Are you sure you want to delete ${this.state.envGroup.name}?`,
+                      onYes: this.handleDeleteEnvGroup,
+                      onNo: () => this.context.setCurrentOverlay(null),
+                    });
+                  }}
                 >
                   Delete {name}
                 </Button>
@@ -338,6 +345,7 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
     } = this.state;
 
     this.setState({ deleting: true });
+    this.context.setCurrentOverlay(null);
     api
       .deleteConfigMap(
         "<token>",
@@ -353,20 +361,10 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
         this.setState({ deleting: false });
       })
       .catch((err) => {
-        this.setState({ deleting: false, showDeleteOverlay: false });
+        this.setState({ deleting: false });
       });
   };
 
-  renderDeleteOverlay = () => {
-    if (this.state.deleting) {
-      return (
-        <DeleteOverlay>
-          <Loading />
-        </DeleteOverlay>
-      );
-    }
-  };
-
   render() {
     const { namespace, closeExpanded } = this.props;
     const {
@@ -376,14 +374,6 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
     return (
       <>
         <StyledExpandedChart>
-          <ConfirmOverlay
-            show={this.state.showDeleteOverlay}
-            message={`Are you sure you want to delete ${name}?`}
-            onYes={this.handleDeleteEnvGroup}
-            onNo={() => this.setState({ showDeleteOverlay: false })}
-          />
-          {this.renderDeleteOverlay()}
-
           <HeaderWrapper>
             <BackButton onClick={closeExpanded}>
               <BackButtonImg src={backArrow} />
@@ -402,14 +392,30 @@ class ExpandedEnvGroup extends Component<PropsType, StateType> {
             </LastDeployed>
           </InfoWrapper>
 
-          <TabRegion
-            currentTab={this.state.currentTab}
-            setCurrentTab={(x: string) => this.setState({ currentTab: x })}
-            options={this.state.tabOptions}
-            color={null}
-          >
-            {this.renderTabContents()}
-          </TabRegion>
+          {
+            this.state.deleting ? (
+              <>
+                <LineBreak />
+                <Placeholder>
+                  <TextWrap>
+                    <Header>
+                      <Spinner src={loading} /> Deleting "{this.state.envGroup.name}"
+                    </Header>
+                    You will be automatically redirected after deletion is complete.
+                  </TextWrap>
+                </Placeholder>
+              </>
+            ) : (
+              <TabRegion
+                currentTab={this.state.currentTab}
+                setCurrentTab={(x: string) => this.setState({ currentTab: x })}
+                options={this.state.tabOptions}
+                color={null}
+              >
+                {this.renderTabContents()}
+              </TabRegion>
+            )
+          }
         </StyledExpandedChart>
       </>
     );
@@ -420,6 +426,42 @@ ExpandedEnvGroup.contextType = Context;
 
 export default withAuth(ExpandedEnvGroup);
 
+const Header = styled.div`
+  font-weight: 500;
+  color: #aaaabb;
+  font-size: 16px;
+  margin-bottom: 15px;
+`;
+
+const Placeholder = styled.div`
+  min-height: 400px;
+  height: 50vh;
+  padding: 30px;
+  padding-bottom: 90px;
+  font-size: 13px;
+  color: #ffffff44;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+`;
+
+const Spinner = styled.img`
+  width: 15px;
+  height: 15px;
+  margin-right: 12px;
+  margin-bottom: -2px;
+`;
+
+const TextWrap = styled.div``;
+
+const LineBreak = styled.div`
+  width: calc(100% - 0px);
+  height: 2px;
+  background: #ffffff20;
+  margin: 15px 0px 55px;
+`;
+
 const HeaderWrapper = styled.div`
   position: relative;
 `;
@@ -481,9 +523,9 @@ const InnerWrapper = styled.div<{ full?: boolean }>`
   height: ${(props) => (props.full ? "100%" : "calc(100% - 65px)")};
   background: #ffffff11;
   padding: 0 35px;
-  padding-bottom: 50px;
+  padding-bottom: 15px;
   position: relative;
-  border-radius: 5px;
+  border-radius: 8px;
   overflow: auto;
 `;
 
@@ -494,38 +536,6 @@ const TabWrapper = styled.div`
   overflow: hidden;
 `;
 
-const DeleteOverlay = styled.div`
-  position: absolute;
-  top: 0px;
-  opacity: 100%;
-  left: 0px;
-  width: 100%;
-  height: 100%;
-  z-index: 999;
-  display: flex;
-  padding-bottom: 30px;
-  align-items: center;
-  justify-content: center;
-  font-family: "Work Sans", sans-serif;
-  font-size: 18px;
-  font-weight: 500;
-  color: white;
-  flex-direction: column;
-  background: rgb(0, 0, 0, 0.73);
-  opacity: 0;
-  animation: lindEnter 0.2s;
-  animation-fill-mode: forwards;
-
-  @keyframes lindEnter {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
 const InfoWrapper = styled.div`
   display: flex;
   align-items: center;

+ 107 - 117
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -21,7 +21,6 @@ import {
 import { Context } from "shared/Context";
 import api from "shared/api";
 
-import ConfirmOverlay from "components/ConfirmOverlay";
 import Loading from "components/Loading";
 import StatusIndicator from "components/StatusIndicator";
 import PorterFormWrapper from "components/porter-form/PorterFormWrapper";
@@ -76,7 +75,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
     Record<string, Record<string, any>>
   >({});
   const [url, setUrl] = useState<string>(null);
-  const [showDeleteOverlay, setShowDeleteOverlay] = useState<boolean>(false);
   const [deleting, setDeleting] = useState<boolean>(false);
   const [imageIsPlaceholder, setImageIsPlaceholer] = useState<boolean>(false);
   const [newestImage, setNewestImage] = useState<string>(null);
@@ -91,9 +89,12 @@ const ExpandedChart: React.FC<Props> = (props) => {
     closeWebsocket,
   } = useWebsockets();
 
-  const { currentCluster, currentProject, setCurrentError } = useContext(
-    Context
-  );
+  const { 
+    currentCluster, 
+    currentProject, 
+    setCurrentError,
+    setCurrentOverlay,
+  } = useContext(Context);
 
   // Retrieve full chart data (includes form and values)
   const getChartData = async (chart: ChartType) => {
@@ -154,7 +155,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
 
         setControllers((oldControllers) => ({
           ...oldControllers,
-          [c.metadata.kind]: c,
+          [c.metadata.uid]: c,
         }));
       });
 
@@ -176,24 +177,22 @@ const ExpandedChart: React.FC<Props> = (props) => {
         let object = event.Object;
         object.metadata.kind = event.Kind;
 
+        if (event.event_type != "UPDATE") {
+          return;
+        }
+
         setControllers((oldControllers) => {
-          switch (event.event_type) {
-            case "DELETE":
-              typeof oldControllers !== "undefined" &&
-                delete oldControllers[object.metadata.uid];
-            case "UPDATE":
-              if (
-                oldControllers &&
-                oldControllers[object.metadata.uid]?.status?.conditions ==
-                  object.status?.conditions
-              ) {
-                return oldControllers;
-              }
-              return {
-                ...oldControllers,
-                [object.metadata.uid]: object,
-              };
+          if (
+            oldControllers &&
+            oldControllers[object.metadata.uid]?.status?.conditions ==
+              object.status?.conditions
+          ) {
+            return oldControllers;
           }
+          return {
+            ...oldControllers,
+            [object.metadata.uid]: object,
+          };
         });
       },
       onerror() {
@@ -391,7 +390,17 @@ const ExpandedChart: React.FC<Props> = (props) => {
           <SettingsSection
             currentChart={chart}
             refreshChart={() => getChartData(currentChart)}
-            setShowDeleteOverlay={(x: boolean) => setShowDeleteOverlay(x)}
+            setShowDeleteOverlay={(x: boolean) => {
+              if (x) {
+                setCurrentOverlay({
+                  message: `Are you sure you want to delete ${currentChart.name}?`,
+                  onYes: handleUninstallChart,
+                  onNo: () => setCurrentOverlay(null),
+                });
+              } else {
+                setCurrentOverlay(null);
+              }
+            }}
           />
         );
       case "graph":
@@ -429,10 +438,10 @@ const ExpandedChart: React.FC<Props> = (props) => {
     // Collate non-form tabs
     let rightTabOptions = [] as any[];
     let leftTabOptions = [] as any[];
-    rightTabOptions.push({ label: "Status", value: "status" });
+    leftTabOptions.push({ label: "Status", value: "status" });
 
     if (props.isMetricsInstalled) {
-      rightTabOptions.push({ label: "Metrics", value: "metrics" });
+      leftTabOptions.push({ label: "Metrics", value: "metrics" });
     }
 
     rightTabOptions.push({ label: "Chart Overview", value: "graph" });
@@ -459,9 +468,9 @@ const ExpandedChart: React.FC<Props> = (props) => {
         (tab: any) => !liveTabs.includes(tab.value)
       );
     }
-
-    setRightTabOptions(rightTabOptions);
+    
     setLeftTabOptions(leftTabOptions);
+    setRightTabOptions(rightTabOptions);
   };
 
   const setRevision = (chart: ChartType, isCurrent?: boolean) => {
@@ -563,6 +572,7 @@ const ExpandedChart: React.FC<Props> = (props) => {
 
   const handleUninstallChart = async () => {
     setDeleting(true);
+    setCurrentOverlay(null);
     try {
       await api.uninstallTemplate(
         "<token>",
@@ -575,7 +585,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
           cluster_id: currentCluster.id,
         }
       );
-      setShowDeleteOverlay(false);
       props.closeChart();
     } catch (error) {
       console.log(error);
@@ -655,17 +664,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
   return (
     <>
       <StyledExpandedChart>
-        <ConfirmOverlay
-          show={showDeleteOverlay}
-          message={`Are you sure you want to delete ${currentChart.name}?`}
-          onYes={handleUninstallChart}
-          onNo={() => setShowDeleteOverlay(false)}
-        />
-        {deleting && (
-          <DeleteOverlay>
-            <Loading />
-          </DeleteOverlay>
-        )}
         <HeaderWrapper>
           <BackButton onClick={props.closeChart}>
             <BackButtonImg src={backArrow} />
@@ -695,48 +693,66 @@ const ExpandedChart: React.FC<Props> = (props) => {
             </LastDeployed>
           </InfoWrapper>
         </HeaderWrapper>
-        <RevisionSection
-          showRevisions={showRevisions}
-          toggleShowRevisions={() => {
-            setShowRevisions(!showRevisions);
-          }}
-          chart={currentChart}
-          refreshChart={() => getChartData(currentChart)}
-          setRevision={setRevision}
-          forceRefreshRevisions={forceRefreshRevisions}
-          refreshRevisionsOff={() => setForceRefreshRevisions(false)}
-          status={chartStatus}
-          shouldUpdate={
-            currentChart.latest_version &&
-            currentChart.latest_version !== currentChart.chart.metadata.version
-          }
-          latestVersion={currentChart.latest_version}
-          upgradeVersion={handleUpgradeVersion}
-        />
-        <BodyWrapper>
-          <PorterFormWrapper
-            formData={currentChart.form}
-            valuesToOverride={{
-              namespace: props.namespace,
-              clusterId: currentCluster.id,
-            }}
-            renderTabContents={renderTabContents}
-            isReadOnly={
-              imageIsPlaceholder ||
-              !isAuthorized("application", "", ["get", "update"])
-            }
-            onSubmit={onSubmit}
-            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>
+        {
+          deleting ? (
+            <>
+              <LineBreak />
+              <Placeholder>
+                <TextWrap>
+                  <Header>
+                    <Spinner src={loadingSrc} /> Deleting "{currentChart.name}"
+                  </Header>
+                  You will be automatically redirected after deletion is complete.
+                </TextWrap>
+              </Placeholder>
+            </>
+          ) : (
+            <>
+              <RevisionSection
+                showRevisions={showRevisions}
+                toggleShowRevisions={() => {
+                  setShowRevisions(!showRevisions);
+                }}
+                chart={currentChart}
+                refreshChart={() => getChartData(currentChart)}
+                setRevision={setRevision}
+                forceRefreshRevisions={forceRefreshRevisions}
+                refreshRevisionsOff={() => setForceRefreshRevisions(false)}
+                status={chartStatus}
+                shouldUpdate={
+                  currentChart.latest_version &&
+                  currentChart.latest_version !== currentChart.chart.metadata.version
+                }
+                latestVersion={currentChart.latest_version}
+                upgradeVersion={handleUpgradeVersion}
+              />
+              <BodyWrapper>
+                <PorterFormWrapper
+                  formData={currentChart.form}
+                  valuesToOverride={{
+                    namespace: props.namespace,
+                    clusterId: currentCluster.id,
+                  }}
+                  renderTabContents={renderTabContents}
+                  isReadOnly={
+                    imageIsPlaceholder ||
+                    !isAuthorized("application", "", ["get", "update"])
+                  }
+                  onSubmit={onSubmit}
+                  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>
+            </>
+          )
+        }
       </StyledExpandedChart>
     </>
   );
@@ -746,9 +762,17 @@ export default ExpandedChart;
 
 const TextWrap = styled.div``;
 
+const LineBreak = styled.div`
+  width: calc(100% - 0px);
+  height: 2px;
+  background: #ffffff20;
+  margin: 35px 0px;
+`;
+
 const BodyWrapper = styled.div`
   position: relative;
   overflow: hidden;
+  margin-bottom: 120px;
 `;
 
 const BackButton = styled.div`
@@ -805,38 +829,6 @@ const Spinner = styled.img`
   margin-bottom: -2px;
 `;
 
-const DeleteOverlay = styled.div`
-  position: absolute;
-  top: 0px;
-  opacity: 100%;
-  left: 0px;
-  width: 100%;
-  height: 100%;
-  z-index: 999;
-  display: flex;
-  padding-bottom: 30px;
-  align-items: center;
-  justify-content: center;
-  font-family: "Work Sans", sans-serif;
-  font-size: 18px;
-  font-weight: 500;
-  color: white;
-  flex-direction: column;
-  background: rgb(0, 0, 0, 0.73);
-  opacity: 0;
-  animation: lindEnter 0.2s;
-  animation-fill-mode: forwards;
-
-  @keyframes lindEnter {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
 const Bolded = styled.div`
   font-weight: 500;
   color: #ffffff44;
@@ -864,7 +856,7 @@ const TabButton = styled.div`
   position: absolute;
   right: 0px;
   height: 30px;
-  background: linear-gradient(to right, #26282f00, #26282f 20%);
+  background: linear-gradient(to right, #20222700, #202227 20%);
   padding-left: 30px;
   display: flex;
   align-items: center;
@@ -967,15 +959,13 @@ const IconWrapper = styled.div`
 
 const StyledExpandedChart = styled.div`
   width: 100%;
+  overflow: hidden;
   z-index: 0;
   animation: fadeIn 0.3s;
   animation-timing-function: ease-out;
   animation-fill-mode: forwards;
   display: flex;
-  overflow-y: auto;
-  padding-bottom: 120px;
   flex-direction: column;
-  overflow: visible;
 
   @keyframes fadeIn {
     from {

+ 3 - 5
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChartWrapper.tsx

@@ -93,7 +93,7 @@ class ExpandedChartWrapper extends Component<PropsType, StateType> {
     let { baseRoute, namespace } = match.params as any;
     let { loading, currentChart } = this.state;
     if (loading) {
-      return <Loading />;
+      return <LoadingWrapper><Loading /></LoadingWrapper>;
     } else if (currentChart && baseRoute === "jobs") {
       return (
         <ExpandedJobChart
@@ -134,10 +134,8 @@ ExpandedChartWrapper.contextType = Context;
 
 export default withRouter(ExpandedChartWrapper);
 
-const NotFoundPlaceholder = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
+const LoadingWrapper = styled.div`
   width: 100%;
   height: 100%;
+  margin-top: -50px;
 `;

+ 63 - 83
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -11,7 +11,6 @@ import { Context } from "shared/Context";
 import api from "shared/api";
 
 import SaveButton from "components/SaveButton";
-import ConfirmOverlay from "components/ConfirmOverlay";
 import Loading from "components/Loading";
 import TitleSection from "components/TitleSection";
 import JobList from "./jobs/JobList";
@@ -39,7 +38,6 @@ type StateType = {
   tabContents: any;
   currentTab: string | null;
   websockets: Record<string, any>;
-  showDeleteOverlay: boolean;
   deleting: boolean;
   saveValuesStatus: string | null;
   formData: any;
@@ -57,7 +55,6 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
     tabContents: [] as any,
     currentTab: null as string | null,
     websockets: {} as Record<string, any>,
-    showDeleteOverlay: false,
     deleting: false,
     saveValuesStatus: null as string | null,
     formData: {} as any,
@@ -474,9 +471,18 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
               showSource={true}
               currentChart={this.state.currentChart}
               refreshChart={() => this.refreshChart(0)}
-              setShowDeleteOverlay={(x: boolean) =>
-                this.setState({ showDeleteOverlay: x })
-              }
+              setShowDeleteOverlay={(x: boolean) => {
+                let { setCurrentOverlay } = this.context;
+                if (x) {
+                  setCurrentOverlay({
+                    message: `Are you sure you want to delete ${this.state.currentChart.name}?`,
+                    onYes: this.handleUninstallChart,
+                    onNo: () => setCurrentOverlay(null),
+                  });
+                } else {
+                  setCurrentOverlay(null);
+                }
+              }}
               saveButtonText="Save Config"
             />
           )
@@ -528,9 +534,10 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
   }
 
   handleUninstallChart = () => {
-    let { currentProject, currentCluster } = this.context;
+    let { currentProject, currentCluster, setCurrentOverlay } = this.context;
     let { currentChart } = this.state;
     this.setState({ deleting: true });
+    setCurrentOverlay(null);
     api
       .uninstallTemplate(
         "<token>",
@@ -544,22 +551,11 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
         }
       )
       .then((res) => {
-        this.setState({ showDeleteOverlay: false });
         this.props.closeChart();
       })
       .catch(console.log);
   };
 
-  renderDeleteOverlay = () => {
-    if (this.state.deleting) {
-      return (
-        <DeleteOverlay>
-          <Loading />
-        </DeleteOverlay>
-      );
-    }
-  };
-
   render() {
     let { closeChart } = this.props;
     let { currentChart } = this.state;
@@ -568,14 +564,6 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
     return (
       <>
         <StyledExpandedChart>
-          <ConfirmOverlay
-            show={this.state.showDeleteOverlay}
-            message={`Are you sure you want to delete ${currentChart.name}?`}
-            onYes={this.handleUninstallChart}
-            onNo={() => this.setState({ showDeleteOverlay: false })}
-          />
-          {this.renderDeleteOverlay()}
-
           <HeaderWrapper>
             <BackButton onClick={closeChart}>
               <BackButtonImg src={backArrow} />
@@ -599,31 +587,48 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
             </InfoWrapper>
           </HeaderWrapper>
 
-          <BodyWrapper>
-            {(this.state.leftTabOptions?.length > 0 ||
-              this.state.formData.tabs?.length > 0 ||
-              this.state.rightTabOptions?.length > 0) && (
-              <PorterFormWrapper
-                formData={this.state.formData}
-                valuesToOverride={{
-                  namespace: chart.namespace,
-                  clusterId: this.props.currentCluster.id,
-                }}
-                renderTabContents={this.renderTabContents}
-                isReadOnly={
-                  this.state.imageIsPlaceholder ||
-                  !this.props.isAuthorized("job", "", ["get", "update"])
-                }
-                onSubmit={(formValues) =>
-                  this.handleSaveValues(formValues, false)
-                }
-                leftTabOptions={this.state.leftTabOptions}
-                rightTabOptions={this.state.rightTabOptions}
-                saveValuesStatus={this.state.saveValuesStatus}
-                saveButtonText="Save Config"
-              />
-            )}
-          </BodyWrapper>
+          {
+            this.state.deleting ? (
+              <>
+                <LineBreak />
+                <Placeholder>
+                  <TextWrap>
+                    <Header>
+                      <Spinner src={loading} /> Deleting "{currentChart.name}"
+                    </Header>
+                    You will be automatically redirected after deletion is complete.
+                  </TextWrap>
+                </Placeholder>
+              </>
+            ) : (
+              <BodyWrapper>
+                {(this.state.leftTabOptions?.length > 0 ||
+                  this.state.formData.tabs?.length > 0 ||
+                  this.state.rightTabOptions?.length > 0) && (
+                  <PorterFormWrapper
+                    formData={this.state.formData}
+                    valuesToOverride={{
+                      namespace: chart.namespace,
+                      clusterId: this.props.currentCluster.id,
+                    }}
+                    renderTabContents={this.renderTabContents}
+                    isReadOnly={
+                      this.state.imageIsPlaceholder ||
+                      !this.props.isAuthorized("job", "", ["get", "update"])
+                    }
+                    onSubmit={(formValues) => {
+                      console.log(formValues)
+                      this.handleSaveValues(formValues, false)
+                    }}
+                    leftTabOptions={this.state.leftTabOptions}
+                    rightTabOptions={this.state.rightTabOptions}
+                    saveValuesStatus={this.state.saveValuesStatus}
+                    saveButtonText="Save Config"
+                  />
+                )}
+              </BodyWrapper>
+            )
+          }
         </StyledExpandedChart>
       </>
     );
@@ -634,6 +639,13 @@ ExpandedJobChart.contextType = Context;
 
 export default withAuth(ExpandedJobChart);
 
+const LineBreak = styled.div`
+  width: calc(100% - 0px);
+  height: 2px;
+  background: #ffffff20;
+  margin: 15px 0px 55px;
+`;
+
 const ButtonWrapper = styled.div`
   margin: 5px 0 35px;
 `;
@@ -706,38 +718,6 @@ const TabWrapper = styled.div`
   overflow: hidden;
 `;
 
-const DeleteOverlay = styled.div`
-  position: absolute;
-  top: 0px;
-  opacity: 100%;
-  left: 0px;
-  width: 100%;
-  height: 100%;
-  z-index: 999;
-  display: flex;
-  padding-bottom: 30px;
-  align-items: center;
-  justify-content: center;
-  font-family: "Work Sans", sans-serif;
-  font-size: 18px;
-  font-weight: 500;
-  color: white;
-  flex-direction: column;
-  background: rgb(0, 0, 0, 0.73);
-  opacity: 0;
-  animation: lindEnter 0.2s;
-  animation-fill-mode: forwards;
-
-  @keyframes lindEnter {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
 const HeaderWrapper = styled.div`
   position: relative;
 `;

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

@@ -52,7 +52,7 @@ const StyledGraphSection = styled.div`
   height: 50vh;
   font-size: 13px;
   overflow: hidden;
-  border-radius: 10px;
+  border-radius: 8px;
   border: 1px solid #ffffff33;
   animation: floatIn 0.3s;
   animation-timing-function: ease-out;

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

@@ -146,7 +146,7 @@ const StyledListSection = styled.div`
   height: 50vh;
   font-size: 13px;
   overflow: hidden;
-  border-radius: 10px;
+  border-radius: 8px;
   animation: floatIn 0.3s;
   animation-timing-function: ease-out;
   animation-fill-mode: forwards;

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

@@ -480,7 +480,7 @@ const StyledRevisionSection = styled.div`
   background: #ffffff11;
   margin: 25px 0px 18px;
   overflow: hidden;
-  border-radius: 5px;
+  border-radius: 8px;
   animation: ${(props: { showRevisions: boolean }) =>
     props.showRevisions ? "expandRevisions 0.3s" : ""};
   animation-timing-function: ease-out;

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx

@@ -379,9 +379,9 @@ const StyledSettingsSection = styled.div<{ showSource: boolean }>`
   width: 100%;
   background: #ffffff11;
   padding: 0 35px;
-  padding-bottom: 50px;
+  padding-bottom: 15px;
   position: relative;
-  border-radius: 5px;
+  border-radius: 8px;
   overflow: auto;
   height: ${(props) => (props.showSource ? "calc(100% - 55px)" : "100%")};
 `;

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx

@@ -111,7 +111,7 @@ ValuesYaml.contextType = Context;
 const Wrapper = styled.div`
   overflow: auto;
   height: calc(100% - 60px);
-  border-radius: 10px;
+  border-radius: 8px;
   border: 1px solid #ffffff33;
 `;
 
@@ -123,7 +123,7 @@ const StyledValuesYaml = styled.div`
   height: 50vh;
   font-size: 13px;
   overflow: hidden;
-  border-radius: 10px;
+  border-radius: 8px;
   animation: floatIn 0.3s;
   animation-timing-function: ease-out;
   animation-fill-mode: forwards;

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobList.tsx

@@ -112,8 +112,8 @@ export default withAuth(JobList);
 
 const Placeholder = styled.div`
   width: 100%;
-  min-height: 400px;
-  height: 50vh;
+  min-height: 250px;
+  height: 30vh;
   display: flex;
   align-items: center;
   justify-content: center;

+ 1 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx

@@ -688,12 +688,11 @@ const StyledMetricsSection = styled.div`
   width: 100%;
   min-height: 400px;
   height: 50vh;
-  overflow: hidden;
   display: flex;
   flex-direction: column;
   position: relative;
   font-size: 13px;
-  border-radius: 10px;
+  border-radius: 8px;
   border: 1px solid #ffffff33;
   padding: 18px 22px;
   animation: floatIn 0.3s;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/StatusSection.tsx

@@ -158,7 +158,7 @@ const StyledStatusSection = styled.div`
   height: 50vh;
   font-size: 13px;
   overflow: hidden;
-  border-radius: 10px;
+  border-radius: 8px;
   animation: floatIn 0.3s;
   animation-timing-function: ease-out;
   animation-fill-mode: forwards;

+ 1 - 0
dashboard/src/main/home/modals/LoadEnvGroupModal.tsx

@@ -103,6 +103,7 @@ export default class LoadEnvGroupModal extends Component<PropsType, StateType> {
   };
 
   potentiallyOverriddenKeys(incoming: Record<string, string>): KeyValue[] {
+    console.log(incoming, this.props.existingValues);
     return Object.entries(incoming)
       .filter(([key]) => this.props.existingValues[key])
       .map(([key, value]) => ({ key, value }));

+ 8 - 0
dashboard/src/shared/Context.tsx

@@ -25,6 +25,12 @@ export interface GlobalContextType {
   currentModal: string;
   currentModalData: any;
   setCurrentModal: (currentModal: string, currentModalData?: any) => void;
+  currentOverlay: {
+    message: string,
+    onYes: any,
+    onNo: any,
+  };
+  setCurrentOverlay: (x: any) => void;
   currentError: string | null;
   setCurrentError: (currentError: string) => void;
   currentCluster: ClusterType;
@@ -63,6 +69,8 @@ class ContextProvider extends Component<PropsType, StateType> {
     setCurrentModal: (currentModal: string, currentModalData?: any) => {
       this.setState({ currentModal, currentModalData });
     },
+    currentOverlay: null,
+    setCurrentOverlay: (x: any) => this.setState({ currentOverlay: x }),
     currentError: null,
     setCurrentError: (currentError: string) => {
       this.setState({ currentError });

+ 6 - 0
dashboard/src/shared/types.tsx

@@ -266,6 +266,12 @@ export interface ContextProps {
   currentModal?: string;
   currentModalData: any;
   setCurrentModal: (currentModal: string, currentModalData?: any) => void;
+  currentOverlay: {
+    message: string,
+    onYes: any,
+    onNo: any,
+  };
+  setCurrentOverlay: (x: any) => void;
   currentError?: string;
   setCurrentError: (currentError: string) => void;
   currentCluster?: ClusterType;