Sfoglia il codice sorgente

Merge branch 'master' into nafees/hotfixes

Mohammed Nafees 3 anni fa
parent
commit
82d89ab5f7
70 ha cambiato i file con 1036 aggiunte e 812 eliminazioni
  1. 4 0
      api/server/handlers/infra/forms.go
  2. 15 13
      cli/cmd/apply.go
  3. 3 0
      dashboard/src/assets/arrow-down.svg
  4. 4 0
      dashboard/src/assets/left-arrow.svg
  5. 201 0
      dashboard/src/components/MultiSelectFilter.tsx
  6. 1 1
      dashboard/src/components/Selector.tsx
  7. 4 3
      dashboard/src/components/TitleSection.tsx
  8. 58 42
      dashboard/src/components/expanded-object/Header.tsx
  9. 2 2
      dashboard/src/main/home/Home.tsx
  10. 1 1
      dashboard/src/main/home/ModalHandler.tsx
  11. 4 5
      dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx
  12. 5 5
      dashboard/src/main/home/cluster-dashboard/DashboardHeader.tsx
  13. 9 62
      dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx
  14. 105 9
      dashboard/src/main/home/cluster-dashboard/dashboard/Dashboard.tsx
  15. 7 1
      dashboard/src/main/home/cluster-dashboard/dashboard/Metrics.tsx
  16. 10 11
      dashboard/src/main/home/cluster-dashboard/dashboard/NamespaceList.tsx
  17. 3 4
      dashboard/src/main/home/cluster-dashboard/dashboard/NodeList.tsx
  18. 2 2
      dashboard/src/main/home/cluster-dashboard/dashboard/incidents/IncidentPage.tsx
  19. 32 25
      dashboard/src/main/home/cluster-dashboard/dashboard/node-view/ExpandedNodeView.tsx
  20. 3 4
      dashboard/src/main/home/cluster-dashboard/databases/DatabasesList.tsx
  21. 1 1
      dashboard/src/main/home/cluster-dashboard/env-groups/CreateEnvGroup.tsx
  22. 10 59
      dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroup.tsx
  23. 10 11
      dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroupDashboard.tsx
  24. 42 5
      dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx
  25. 37 110
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx
  26. 1 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChartWrapper.tsx
  27. 87 49
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx
  28. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/GraphSection.tsx
  29. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ListSection.tsx
  30. 2 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx
  31. 40 4
      dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/ExpandedJobRun.tsx
  32. 5 6
      dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobResource.tsx
  33. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx
  34. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/status/StatusSection.tsx
  35. 1 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/components/ButtonEnablePREnvironments.tsx
  36. 3 3
      dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentCard.tsx
  37. 43 7
      dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentDetail.tsx
  38. 3 3
      dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/PullRequestCard.tsx
  39. 4 12
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentCard.tsx
  40. 4 4
      dashboard/src/main/home/cluster-dashboard/stacks/Dashboard.tsx
  41. 44 8
      dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/ExpandedStack.tsx
  42. 1 1
      dashboard/src/main/home/cluster-dashboard/stacks/_StackList.tsx
  43. 1 2
      dashboard/src/main/home/cluster-dashboard/stacks/components/styles.ts
  44. 2 2
      dashboard/src/main/home/cluster-dashboard/stacks/launch/Overview.tsx
  45. 4 4
      dashboard/src/main/home/cluster-dashboard/stacks/launch/components/styles.tsx
  46. 72 157
      dashboard/src/main/home/dashboard/ClusterList.tsx
  47. 13 14
      dashboard/src/main/home/dashboard/Dashboard.tsx
  48. 5 6
      dashboard/src/main/home/infrastructure/InfrastructureList.tsx
  49. 2 2
      dashboard/src/main/home/infrastructure/components/ProvisionInfra.tsx
  50. 49 10
      dashboard/src/main/home/integrations/IntegrationCategories.tsx
  51. 13 14
      dashboard/src/main/home/integrations/IntegrationList.tsx
  52. 10 7
      dashboard/src/main/home/integrations/IntegrationRow.tsx
  53. 1 6
      dashboard/src/main/home/integrations/Integrations.tsx
  54. 3 3
      dashboard/src/main/home/launch/Launch.tsx
  55. 4 5
      dashboard/src/main/home/launch/TemplateList.tsx
  56. 2 2
      dashboard/src/main/home/launch/expanded-template/TemplateInfo.tsx
  57. 2 3
      dashboard/src/main/home/launch/launch-flow/LaunchFlow.tsx
  58. 9 6
      dashboard/src/main/home/launch/launch-flow/SourcePage.tsx
  59. 3 65
      dashboard/src/main/home/navbar/Navbar.tsx
  60. 2 2
      dashboard/src/main/home/new-project/NewProject.tsx
  61. 2 2
      dashboard/src/main/home/onboarding/steps/ConnectRegistry/ConnectRegistry.tsx
  62. 1 1
      dashboard/src/main/home/onboarding/steps/ConnectSource.tsx
  63. 1 1
      dashboard/src/main/home/onboarding/steps/ProvisionResources/ProvisionResources.tsx
  64. 1 1
      dashboard/src/main/home/project-settings/ProjectSettings.tsx
  65. 5 5
      dashboard/src/main/home/provisioner/ProvisionerSettings.tsx
  66. 7 5
      dashboard/src/main/home/sidebar/ClusterSection.tsx
  67. 3 3
      dashboard/src/main/home/sidebar/Sidebar.tsx
  68. 1 0
      dashboard/src/shared/api.tsx
  69. 3 3
      dashboard/src/shared/common.tsx
  70. BIN
      porter-0.36.0.tgz

+ 4 - 0
api/server/handlers/infra/forms.go

@@ -500,6 +500,10 @@ tabs:
           value: t3.xlarge
         - label: t3.2xlarge
           value: t3.2xlarge
+        - label: c6i.large
+          value: c6i.large
+        - label: c6i.xlarge
+          value: c6i.xlarge
         - label: c6i.2xlarge
           value: c6i.2xlarge
     - type: number-input

+ 15 - 13
cli/cmd/apply.go

@@ -323,6 +323,8 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 		return nil, fmt.Errorf("nil resource")
 	}
 
+	resourceName := resource.Name
+
 	appConfig, err := d.getApplicationConfig(resource)
 
 	if err != nil {
@@ -333,13 +335,13 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 
 	if method != "pack" && method != "docker" && method != "registry" {
 		return nil, fmt.Errorf("for resource %s, config.build.method should either be \"docker\", \"pack\" or \"registry\"",
-			resource.Name)
+			resourceName)
 	}
 
 	fullPath, err := filepath.Abs(appConfig.Build.Context)
 
 	if err != nil {
-		return nil, fmt.Errorf("for resource %s, error getting absolute path for config.build.context: %w", resource.Name,
+		return nil, fmt.Errorf("for resource %s, error getting absolute path for config.build.context: %w", resourceName,
 			err)
 	}
 
@@ -347,17 +349,17 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 
 	if tag == "" {
 		color.New(color.FgYellow).Printf("for resource %s, since PORTER_TAG is not set, the Docker image tag will default to"+
-			" the git repo SHA", resource.Name)
+			" the git repo SHA", resourceName)
 
 		commit, err := git.LastCommit()
 
 		if err != nil {
-			return nil, fmt.Errorf("for resource %s, error getting last git commit: %w", resource.Name, err)
+			return nil, fmt.Errorf("for resource %s, error getting last git commit: %w", resourceName, err)
 		}
 
 		tag = commit.Sha[:7]
 
-		color.New(color.FgYellow).Printf("for resource %s, using tag %s\n", resource.Name, tag)
+		color.New(color.FgYellow).Printf("for resource %s, using tag %s\n", resourceName, tag)
 	}
 
 	// if the method is registry and a tag is defined, we use the provided tag
@@ -398,16 +400,16 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 		resource, err = d.createApplication(resource, client, sharedOpts, appConfig)
 
 		if err != nil {
-			return nil, fmt.Errorf("error creating app from resource %s: %w", resource.Name, err)
+			return nil, fmt.Errorf("error creating app from resource %s: %w", resourceName, err)
 		}
 	} else if !appConfig.OnlyCreate {
 		resource, err = d.updateApplication(resource, client, sharedOpts, appConfig)
 
 		if err != nil {
-			return nil, fmt.Errorf("error updating application from resource %s: %w", resource.Name, err)
+			return nil, fmt.Errorf("error updating application from resource %s: %w", resourceName, err)
 		}
 	} else {
-		color.New(color.FgYellow).Printf("Skipping creation for resource %s as onlyCreate is set to true\n", resource.Name)
+		color.New(color.FgYellow).Printf("Skipping creation for resource %s as onlyCreate is set to true\n", resourceName)
 	}
 
 	if err = d.assignOutput(resource, client); err != nil {
@@ -415,13 +417,13 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 	}
 
 	if d.source.Name == "job" && appConfig.WaitForJob && (shouldCreate || !appConfig.OnlyCreate) {
-		color.New(color.FgYellow).Printf("Waiting for job '%s' to finish\n", resource.Name)
+		color.New(color.FgYellow).Printf("Waiting for job '%s' to finish\n", resourceName)
 
 		err = wait.WaitForJob(client, &wait.WaitOpts{
 			ProjectID: d.target.Project,
 			ClusterID: d.target.Cluster,
 			Namespace: d.target.Namespace,
-			Name:      resource.Name,
+			Name:      resourceName,
 		})
 
 		if err != nil && appConfig.OnlyCreate {
@@ -430,15 +432,15 @@ func (d *DeployDriver) applyApplication(resource *models.Resource, client *api.C
 				d.target.Project,
 				d.target.Cluster,
 				d.target.Namespace,
-				resource.Name,
+				resourceName,
 			)
 
 			if deleteJobErr != nil {
 				return nil, fmt.Errorf("error deleting job %s with waitForJob and onlyCreate set to true: %w",
-					resource.Name, deleteJobErr)
+					resourceName, deleteJobErr)
 			}
 		} else if err != nil {
-			return nil, fmt.Errorf("error waiting for job %s: %w", resource.Name, err)
+			return nil, fmt.Errorf("error waiting for job %s: %w", resourceName, err)
 		}
 	}
 

+ 3 - 0
dashboard/src/assets/arrow-down.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15 1.5L8 8.5L1 1.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 4 - 0
dashboard/src/assets/left-arrow.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.25 12.2743L19.25 12.2743" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.2998 18.2987L4.2498 12.2747L10.2998 6.24969" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 201 - 0
dashboard/src/components/MultiSelectFilter.tsx

@@ -0,0 +1,201 @@
+import React, { useEffect, useState, useRef } from "react";
+
+import styled from "styled-components";
+import arrow from "assets/arrow-down.svg";
+
+import CheckboxList from "components/form-components/CheckboxList";
+
+type Props = {
+  name: string;
+  icon?: any;
+  options: { value: any; label: string }[];
+  selected: any[];
+  setSelected: any;
+};
+
+export const MultiSelectFilter: React.FC<Props> = (props) => {
+  const [expanded, setExpanded] = useState(false);
+
+  const wrapperRef = useRef<HTMLInputElement>(null);
+  const parentRef = useRef<HTMLInputElement>(null);
+
+  useEffect(() => {
+    document.addEventListener("mousedown", handleClickOutside.bind(this));
+    return () =>
+      document.removeEventListener("mousedown", handleClickOutside.bind(this));
+  }, []);
+
+  const handleClickOutside = (event: any) => {
+    if (
+      wrapperRef &&
+      wrapperRef.current &&
+      !wrapperRef.current.contains(event.target) &&
+      parentRef &&
+      parentRef.current &&
+      !parentRef.current.contains(event.target)
+    ) {
+      setExpanded(false);
+    }
+  };
+
+  const renderOptions = () => {
+    return props.options.map(
+      (option: { value: any; label: string }, i: number) => {
+        return (
+          <Option key={i} onClick={() => alert("choise")}>
+            {option.label}
+          </Option>
+        );
+      }
+    );
+  };
+
+  const renderDropdown = () => {
+    if (expanded) {
+      return (
+        <DropdownWrapper>
+          <Dropdown ref={wrapperRef}>
+            {props.options.length > 0 ? (
+              <ScrollableWrapper>
+                <CheckboxList
+                  options={props.options}
+                  selected={props.selected}
+                  setSelected={props.setSelected}
+                />
+              </ScrollableWrapper>
+            ) : (
+              <Placeholder>No options found</Placeholder>
+            )}
+          </Dropdown>
+        </DropdownWrapper>
+      );
+    }
+  };
+
+  return (
+    <Relative>
+      <StyledMultiSelectFilter
+        onClick={() => setExpanded(!expanded)}
+        ref={parentRef}
+      >
+        {props.icon && <FilterIcon src={props.icon} />}
+        {props.name}
+        {props.selected.length > 0 && (
+          <FilterCount>{props.selected.length}</FilterCount>
+        )}
+        <DropdownIcon src={arrow} />
+      </StyledMultiSelectFilter>
+      {renderDropdown()}
+    </Relative>
+  );
+};
+
+const FilterCount = styled.div`
+  padding: 5px;
+  color: #ffffff;
+  background: #ffffff11;
+  margin-left: 7px;
+  font-size: 12px;
+  border-radius: 50px;
+  margin-right: -5px;
+  height: 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-width: 20px;
+`;
+
+const Placeholder = styled.div`
+  color: #aaaabb88;
+  font-size: 12px;
+  width: 100%;
+  height: 50px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+`;
+
+const ScrollableWrapper = styled.div`
+  overflow-y: auto;
+  height: 100%;
+  max-height: 350px;
+`;
+
+const Label = styled.div`
+  height: 37px;
+  display: flex;
+  align-items: center;
+  margin-left: 10px;
+  font-size: 13px;
+`;
+
+const Option: any = styled.div`
+  width: 100%;
+  border-top: 1px solid #00000000;
+  height: 37px;
+  font-size: 13px;
+  align-items: center;
+  display: flex;
+  align-items: center;
+  padding-left: 15px;
+  cursor: pointer;
+  padding-right: 10px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  background: ${(props: any) => (props.selected ? "#ffffff11" : "")};
+
+  :hover {
+    background: #ffffff22;
+  }
+`;
+
+const Relative = styled.div`
+  position: relative;
+`;
+
+const DropdownWrapper = styled.div`
+  position: absolute;
+  width: 100%;
+  right: 0;
+  z-index: 1;
+  top: calc(100% + 5px);
+`;
+
+const Dropdown = styled.div`
+  width: 260px;
+  border-radius: 3px;
+  z-index: 999;
+  overflow-y: auto;
+  margin-bottom: 20px;
+  background: #2f3135;
+  border-radius: 5px;
+  border: 1px solid #aaaabb33;
+`;
+
+const DropdownIcon = styled.img`
+  width: 8px;
+  margin-left: 12px;
+`;
+
+const FilterIcon = styled.img`
+  width: 14px;
+  margin-right: 7px;
+`;
+
+const StyledMultiSelectFilter = styled.div`
+  height: 30px;
+  font-size: 13px;
+  position: relative;
+  padding: 10px;
+  background: #26292e;
+  border-radius: 5px;
+  border: 1px solid #aaaabb33;
+  display: flex;
+  align-items: center;
+  margin-right: 10px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;

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

@@ -98,7 +98,7 @@ export default class Selector extends Component<SelectorPropsType, StateType> {
           }}
         >
           <Plus>+</Plus>
-          Add Namespace
+          Add namespace
         </NewOption>
       );
     }

+ 4 - 3
dashboard/src/components/TitleSection.tsx

@@ -65,20 +65,21 @@ const StyledTitleSection = styled.div`
   margin-bottom: 15px;
   display: flex;
   align-items: center;
+  height: 35px;
 `;
 
 const Icon = styled.img<{ width: string }>`
-  width: ${(props) => props.width || "28px"};
+  width: ${(props) => props.width || "25px"};
   margin-right: 16px;
 `;
 
 const MaterialIcon = styled.span<{ width: string }>`
-  width: ${(props) => props.width || "28px"};
+  width: ${(props) => props.width || "25px"};
   margin-right: 16px;
 `;
 
 const StyledTitle = styled.div<{ capitalize: boolean }>`
-  font-size: 24px;
+  font-size: 21px;
   font-weight: 600;
   user-select: text;
   text-transform: ${(props) => (props.capitalize ? "capitalize" : "")};

+ 58 - 42
dashboard/src/components/expanded-object/Header.tsx

@@ -1,9 +1,10 @@
 import DynamicLink from "components/DynamicLink";
 import React from "react";
 import styled from "styled-components";
-import backArrow from "assets/back_arrow.png";
 import TitleSection from "components/TitleSection";
 
+import leftArrow from "assets/left-arrow.svg";
+
 type Props = {
   last_updated: string;
   back_link: string;
@@ -26,26 +27,68 @@ const Header: React.FunctionComponent<Props> = (props) => {
   } = props;
 
   return (
-    <HeaderWrapper>
-      <BackButton to={back_link}>
-        <BackButtonImg src={backArrow} />
-      </BackButton>
-      <Title icon={icon} iconWidth="25px" materialIconClass={materialIconClass}>
-        {name}
-        <Flex>{inline_title_items}</Flex>
-      </Title>
+    <>
+      <BreadcrumbRow>
+        <Breadcrumb to={back_link}>
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
+      <HeaderWrapper>
+        <Title
+          icon={icon}
+          iconWidth="25px"
+          materialIconClass={materialIconClass}
+        >
+          {name}
+          <Flex>{inline_title_items}</Flex>
+        </Title>
 
-      {sub_title_items || (
-        <InfoWrapper>
-          <InfoText>Last updated {last_updated}</InfoText>
-        </InfoWrapper>
-      )}
-    </HeaderWrapper>
+        {sub_title_items || (
+          <InfoWrapper>
+            <InfoText>Last updated {last_updated}</InfoText>
+          </InfoWrapper>
+        )}
+      </HeaderWrapper>
+    </>
   );
 };
 
 export default Header;
 
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled(DynamicLink)`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
 const HeaderWrapper = styled.div`
   position: relative;
   margin-bottom: 10px;
@@ -63,33 +106,6 @@ const InfoText = styled.span`
   color: #aaaabb66;
 `;
 
-const BackButton = styled(DynamicLink)`
-  position: absolute;
-  top: 0px;
-  right: 0px;
-  display: flex;
-  width: 36px;
-  cursor: pointer;
-  height: 36px;
-  align-items: center;
-  justify-content: center;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  background: #ffffff11;
-
-  :hover {
-    background: #ffffff22;
-    > img {
-      opacity: 1;
-    }
-  }
-`;
-
-const BackButtonImg = styled.img`
-  width: 16px;
-  opacity: 0.75;
-`;
-
 const Title = styled(TitleSection)`
   font-size: 16px;
   margin-top: 4px;

+ 2 - 2
dashboard/src/main/home/Home.tsx

@@ -529,7 +529,7 @@ export default withRouter(withAuth(Home));
 const ViewWrapper = styled.div`
   height: 100%;
   width: 100vw;
-  padding-top: 10vh;
+  padding: 45px;
   overflow-y: auto;
   display: flex;
   flex: 1;
@@ -539,7 +539,7 @@ const ViewWrapper = styled.div`
 `;
 
 const DashboardWrapper = styled.div`
-  width: calc(85%);
+  width: 100%;
   min-width: 300px;
   height: fit-content;
 `;

+ 1 - 1
dashboard/src/main/home/ModalHandler.tsx

@@ -143,7 +143,7 @@ const ModalHandler: React.FC<{
             onRequestClose={() => setCurrentModal(null, null)}
             width="600px"
             height="220px"
-            title="Add Namespace"
+            title="Add namespace"
           >
             <NamespaceModal />
           </Modal>

+ 4 - 5
dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx

@@ -185,16 +185,16 @@ class ClusterDashboard extends Component<PropsType, StateType> {
     return (
       <>
         <ControlRow>
+          <SortFilterWrapper>{this.renderCommonFilters()}</SortFilterWrapper>
           {isAuthorizedToAdd && (
             <Button
               onClick={() =>
                 pushFiltered(this.props, "/launch", ["project_id"])
               }
             >
-              <i className="material-icons">add</i> Launch Template
+              <i className="material-icons">add</i> Launch template
             </Button>
           )}
-          <SortFilterWrapper>{this.renderCommonFilters()}</SortFilterWrapper>
         </ControlRow>
 
         <ChartList
@@ -240,7 +240,7 @@ class ClusterDashboard extends Component<PropsType, StateType> {
                 pushFiltered(this.props, "/launch", ["project_id"])
               }
             >
-              <i className="material-icons">add</i> Launch Template
+              <i className="material-icons">add</i> Launch template
             </Button>
           )}
           <SortFilterWrapper>
@@ -364,14 +364,13 @@ const Button = styled.div`
   font-size: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 20px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   margin-bottom: 35px;
   padding: 0px 8px;
   min-width: 155px;
   padding-bottom: 1px;
-  margin-right: 10px;
   font-weight: 500;
   padding-right: 15px;
   overflow: hidden;

+ 5 - 5
dashboard/src/main/home/cluster-dashboard/DashboardHeader.tsx

@@ -55,8 +55,9 @@ const Br = styled.div`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
+  width: 100%;
   margin: 10px 0px 35px;
 `;
 
@@ -66,11 +67,10 @@ const TopRow = styled.div`
 `;
 
 const Description = styled.div`
-  color: #aaaabb;
+  color: #8b949f;
   margin-top: 13px;
   margin-left: 2px;
   font-size: 13px;
-  line-height: 1.5em;
 `;
 
 const InfoLabel = styled.div`
@@ -78,7 +78,7 @@ const InfoLabel = styled.div`
   height: 20px;
   display: flex;
   align-items: center;
-  color: #7a838f;
+  color: #8b949f;
   font-size: 13px;
   > i {
     color: #8b949f;

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

@@ -48,7 +48,6 @@ const Chart: React.FunctionComponent<Props> = ({
   isJob,
   closeChartRedirectUrl,
 }) => {
-  const [expand, setExpand] = useState<boolean>(false);
   const [chartControllers, setChartControllers] = useState<any>([]);
   const [showDescription, setShowDescription] = useState(false);
   const context = useContext(Context);
@@ -120,9 +119,6 @@ const Chart: React.FunctionComponent<Props> = ({
 
   return (
     <StyledChart
-      onMouseEnter={() => setExpand(true)}
-      onMouseLeave={() => setExpand(false)}
-      expand={expand}
       onClick={() => {
         const cluster = context.currentCluster?.name;
         let route = `${isJob ? "/jobs" : "/applications"}/${cluster}/${
@@ -233,7 +229,7 @@ const BottomWrapper = styled.div`
   justify-content: space-between;
   align-items: center;
   padding-right: 11px;
-  margin-top: 12px;
+  margin-top: 3px;
 `;
 
 const TopRightContainer = styled.div`
@@ -365,66 +361,17 @@ const JobStatus = styled.span<{ status?: JobStatusType }>`
 `;
 
 const StyledChart = styled.div`
-  background: #26282f;
   cursor: pointer;
-  margin-bottom: 25px;
-  padding: 1px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
+  margin-bottom: 15px;
+  padding-top: 2px;
+  padding-bottom: 13px;
   position: relative;
-  border: 2px solid #9eb4ff00;
   width: calc(100% + 2px);
   height: calc(100% + 2px);
-
-  animation: ${(props: { expand: boolean }) =>
-      props.expand ? "expand" : "shrink"}
-    0.12s;
-  animation-fill-mode: forwards;
-  animation-timing-function: ease-out;
-
-  @keyframes expand {
-    from {
-      width: calc(100% + 2px);
-      padding-top: 4px;
-      padding-bottom: 14px;
-      margin-left: 0px;
-      box-shadow: 0 4px 15px 0px #00000055;
-      padding-left: 1px;
-      margin-bottom: 25px;
-      margin-top: 0px;
-    }
-    to {
-      width: calc(100% + 22px);
-      padding-top: 7px;
-      padding-bottom: 20px;
-      margin-left: -10px;
-      box-shadow: 0 8px 20px 0px #00000030;
-      padding-left: 5px;
-      margin-bottom: 21px;
-      margin-top: -4px;
-    }
-  }
-
-  @keyframes shrink {
-    from {
-      width: calc(100% + 22px);
-      padding-top: 7px;
-      padding-bottom: 20px;
-      margin-left: -10px;
-      box-shadow: 0 8px 20px 0px #00000030;
-      padding-left: 5px;
-      margin-bottom: 21px;
-      margin-top: -4px;
-    }
-    to {
-      width: calc(100% + 2px);
-      padding-top: 4px;
-      padding-bottom: 14px;
-      margin-left: 0px;
-      box-shadow: 0 4px 15px 0px #00000055;
-      padding-left: 1px;
-      margin-bottom: 25px;
-      margin-top: 0px;
-    }
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
   }
 `;

+ 105 - 9
dashboard/src/main/home/cluster-dashboard/dashboard/Dashboard.tsx

@@ -4,6 +4,7 @@ import styled from "styled-components";
 import { Context } from "shared/Context";
 import TabSelector from "components/TabSelector";
 import TitleSection from "components/TitleSection";
+import api from "shared/api";
 
 import NodeList from "./NodeList";
 
@@ -15,6 +16,11 @@ import { useLocation } from "react-router";
 import { getQueryParam } from "shared/routing";
 import IncidentsTab from "./incidents/IncidentsTab";
 
+import CopyToClipboard from "components/CopyToClipboard";
+import Loading from "components/Loading";
+
+import { DetailedIngressError } from "shared/types";
+
 type TabEnum = "nodes" | "settings" | "namespaces" | "metrics" | "incidents";
 
 const tabOptions: {
@@ -35,6 +41,8 @@ export const Dashboard: React.FunctionComponent = () => {
   const [currentTabOptions, setCurrentTabOptions] = useState(tabOptions);
   const [isAuthorized] = useAuth();
   const location = useLocation();
+  const [ingressIp, setIngressIp] = useState(null);
+  const [ingressError, setIngressError] = useState(null);
 
   const context = useContext(Context);
   const renderTab = () => {
@@ -76,6 +84,71 @@ export const Dashboard: React.FunctionComponent = () => {
     setCurrentTab("nodes");
   }, [context.currentCluster]);
 
+  const renderIngressIp = (
+    ingressIp: string | undefined,
+    ingressError: DetailedIngressError
+  ) => {
+    if (typeof ingressIp !== "string") {
+      return (
+        <Url onClick={(e) => e.preventDefault()}>
+          <Loading />
+        </Url>
+      );
+    }
+
+    if (!ingressIp.length && ingressError) {
+      return (
+        <>
+          <Bolded>Ingress IP:</Bolded>
+          <span>{ingressError.message}</span>
+        </>
+      );
+    }
+
+    if (!ingressIp.length) {
+      return (
+        <>
+          <Bolded>Ingress IP:</Bolded>
+          <span>Ingress IP not available</span>
+        </>
+      );
+    }
+
+    return (
+      <CopyToClipboard
+        as={Url}
+        text={ingressIp}
+        wrapperProps={{ onClick: (e: any) => e.stopPropagation() }}
+      >
+        <Bolded>Ingress IP:</Bolded>
+        <span>{ingressIp}</span>
+        <i className="material-icons-outlined">content_copy</i>
+      </CopyToClipboard>
+    );
+  };
+
+  const updateClusterWithDetailedData = async () => {
+    try {
+      const res = await api.getCluster(
+        "<token>",
+        {},
+        {
+          project_id: context.currentProject.id,
+          cluster_id: context.currentCluster.id,
+        }
+      );
+      if (res.data) {
+        const { ingress_ip, ingress_error } = res.data;
+        setIngressIp(ingress_ip);
+        setIngressError(ingress_error);
+      }
+    } catch (error) {}
+  };
+
+  useEffect(() => {
+    updateClusterWithDetailedData();
+  }, []);
+
   return (
     <>
       <TitleSection>
@@ -91,9 +164,7 @@ export const Dashboard: React.FunctionComponent = () => {
             <i className="material-icons">info</i> Info
           </InfoLabel>
         </TopRow>
-        <Description>
-          Cluster settings for {context.currentCluster.name}
-        </Description>
+        <Description>{renderIngressIp(ingressIp, ingressError)}</Description>
       </InfoSection>
 
       <TabSelector
@@ -108,9 +179,9 @@ export const Dashboard: React.FunctionComponent = () => {
 };
 
 const DashboardIcon = styled.div`
-  height: 45px;
-  min-width: 45px;
-  width: 45px;
+  height: 35px;
+  min-width: 35px;
+  width: 35px;
   border-radius: 5px;
   margin-right: 17px;
   display: flex;
@@ -119,7 +190,7 @@ const DashboardIcon = styled.div`
   background: #676c7c;
   border: 2px solid #8e94aa;
   > i {
-    font-size: 22px;
+    font-size: 18px;
   }
 `;
 
@@ -129,7 +200,7 @@ const TopRow = styled.div`
 `;
 
 const Description = styled.div`
-  color: #aaaabb;
+  color: #8b949f;
   margin-top: 13px;
   margin-left: 2px;
   font-size: 13px;
@@ -140,7 +211,7 @@ const InfoLabel = styled.div`
   height: 20px;
   display: flex;
   align-items: center;
-  color: #7a838f;
+  color: #8b949f;
   font-size: 13px;
   > i {
     color: #8b949f;
@@ -155,3 +226,28 @@ const InfoSection = styled.div`
   margin-left: 0px;
   margin-bottom: 35px;
 `;
+
+const Url = styled.a`
+  font-size: 13px;
+  user-select: text;
+  font-weight: 400;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  > i {
+    margin-left: 10px;
+    font-size: 15px;
+  }
+
+  > span {
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+`;
+
+const Bolded = styled.span`
+  color: #8b949f;
+  margin-right: 6px;
+  white-space: nowrap;
+`;

+ 7 - 1
dashboard/src/main/home/cluster-dashboard/dashboard/Metrics.tsx

@@ -44,7 +44,13 @@ const Metrics: React.FC = () => {
     if (selectedMetric && selectedRange && selectedIngress) {
       getMetrics();
     }
-  }, [selectedMetric, selectedRange, selectedIngress, selectedPercentile]);
+  }, [
+    selectedMetric,
+    selectedRange,
+    selectedIngress,
+    selectedPercentile,
+    currentCluster,
+  ]);
 
   useEffect(() => {
     Promise.all([

+ 10 - 11
dashboard/src/main/home/cluster-dashboard/dashboard/NamespaceList.tsx

@@ -155,7 +155,10 @@ export const NamespaceList: React.FunctionComponent = () => {
               {isAuthorized("namespace", "", ["get", "delete"]) &&
                 isAvailableForDeletion(namespace?.metadata?.name) &&
                 namespace?.status?.phase === "Active" && (
-                  <OptionsDropdown.Dropdown>
+                  <OptionsDropdown.Dropdown
+                    expandIcon="more_vert"
+                    shrinkIcon="more_vert"
+                  >
                     <OptionsDropdown.Option onClick={() => onDelete(namespace)}>
                       <i className="material-icons-outlined">delete</i>
                       <span>Delete</span>
@@ -244,7 +247,7 @@ const Button = styled.div`
   font-size: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 20px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   padding: 0px 8px;
@@ -281,17 +284,14 @@ const Button = styled.div`
 `;
 
 const StyledCard = styled.div`
-  background: #26282f;
   min-height: 80px;
   width: 100%;
   display: flex;
   justify-content: space-between;
   align-items: center;
-  border: 1px solid #26282f;
-  box-shadow: 0 4px 15px 0px #00000055;
-  border-radius: 8px;
   padding: 14px;
   animation: fadeIn 0.5s;
+  cursor: pointer;
   @keyframes fadeIn {
     from {
       opacity: 0;
@@ -300,12 +300,11 @@ const StyledCard = styled.div`
       opacity: 1;
     }
   }
-
-  transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    transform: scale(1.05);
-    box-shadow: 0 8px 20px 0px #00000030;
-    cursor: pointer;
+    border: 1px solid #7a7b80;
   }
 `;
 

+ 3 - 4
dashboard/src/main/home/cluster-dashboard/dashboard/NodeList.tsx

@@ -148,17 +148,16 @@ const NodeListWrapper = styled.div`
 `;
 
 const StyledChart = styled.div`
-  background: #26282f;
   padding: 14px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
   position: relative;
-  border: 2px solid #9eb4ff00;
   width: 100%;
   height: 100%;
   :not(:last-child) {
     margin-bottom: 25px;
   }
+  border-radius: 8px;
+  background: #262a30;
+  border: 1px solid #494b4f;
 `;
 
 const StatusHeader = styled.div`

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/dashboard/incidents/IncidentPage.tsx

@@ -322,8 +322,8 @@ const RefreshButton = styled.button`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 10px 0px 35px;
 `;
 

+ 32 - 25
dashboard/src/main/home/cluster-dashboard/dashboard/node-view/ExpandedNodeView.tsx

@@ -1,7 +1,7 @@
 import React, { useContext, useEffect, useMemo, useState } from "react";
 import { useHistory, useLocation, useParams } from "react-router";
 import styled from "styled-components";
-import backArrow from "assets/back_arrow.png";
+import leftArrow from "assets/left-arrow.svg";
 import api from "shared/api";
 import { Context } from "shared/Context";
 
@@ -49,8 +49,6 @@ export const ExpandedNodeView = () => {
           setNode(res.data);
         }
       });
-
-    return () => (isSubscribed = false);
   }, [nodeId, currentCluster.id, currentProject.id]);
 
   const closeNodeView = () => {
@@ -92,10 +90,13 @@ export const ExpandedNodeView = () => {
 
   return (
     <StyledExpandedNodeView>
+      <BreadcrumbRow>
+        <Breadcrumb onClick={closeNodeView}>
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
       <HeaderWrapper>
-        <BackButton onClick={closeNodeView}>
-          <BackButtonImg src={backArrow} />
-        </BackButton>
         <TitleSection icon={nodePng}>
           {nodeId}
           <InstanceType>{instanceType}</InstanceType>
@@ -121,31 +122,37 @@ export const ExpandedNodeView = () => {
 
 export default ExpandedNodeView;
 
-const BackButton = styled.div`
-  position: absolute;
-  top: 0px;
-  right: 0px;
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
   display: flex;
-  width: 36px;
-  cursor: pointer;
-  height: 36px;
-  align-items: center;
-  justify-content: center;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  background: #ffffff11;
+  justify-content: flex-start;
+`;
 
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
   :hover {
-    background: #ffffff22;
-    > img {
-      opacity: 1;
-    }
+    background: #ffffff11;
   }
 `;
 
-const BackButtonImg = styled.img`
-  width: 16px;
-  opacity: 0.75;
+const Wrap = styled.div`
+  z-index: 999;
 `;
 
 const StatusWrapper = styled.div`

+ 3 - 4
dashboard/src/main/home/cluster-dashboard/databases/DatabasesList.tsx

@@ -253,12 +253,11 @@ const DatabasesListWrapper = styled.div`
 `;
 
 const StyledTableWrapper = styled.div`
-  background: #26282f;
   padding: 14px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
   position: relative;
-  border: 2px solid #9eb4ff00;
+  border-radius: 8px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   width: 100%;
   height: 100%;
   :not(:last-child) {

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/env-groups/CreateEnvGroup.tsx

@@ -207,7 +207,7 @@ export default class CreateEnvGroup extends Component<PropsType, StateType> {
           />
           <SaveButton
             disabled={this.isDisabled()}
-            text="Create Env Group"
+            text="Create env group"
             onClick={this.onSubmit}
             status={
               this.isDisabled()

+ 10 - 59
dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroup.tsx

@@ -81,7 +81,7 @@ const BottomWrapper = styled.div`
   justify-content: space-between;
   align-items: center;
   padding-right: 11px;
-  margin-top: 12px;
+  margin-top: 3px;
 `;
 
 const Version = styled.div`
@@ -108,7 +108,7 @@ const InfoWrapper = styled.div`
 const LastDeployed = styled.div`
   font-size: 13px;
   margin-left: 14px;
-  margin-top: -1px;
+  margin-bottom: -1px;
   display: flex;
   align-items: center;
   color: #aaaabb66;
@@ -195,66 +195,17 @@ const Title = styled.div`
 `;
 
 const StyledEnvGroup = styled.div`
-  background: #26282f;
   cursor: pointer;
-  margin-bottom: 25px;
-  padding: 1px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
+  margin-bottom: 15px;
+  padding-top: 2px;
+  padding-bottom: 13px;
   position: relative;
-  border: 2px solid #9eb4ff00;
   width: calc(100% + 2px);
   height: calc(100% + 2px);
-
-  animation: ${(props: { expand: boolean }) =>
-      props.expand ? "expand" : "shrink"}
-    0.12s;
-  animation-fill-mode: forwards;
-  animation-timing-function: ease-out;
-
-  @keyframes expand {
-    from {
-      width: calc(100% + 2px);
-      padding-top: 4px;
-      padding-bottom: 14px;
-      margin-left: 0px;
-      box-shadow: 0 4px 15px 0px #00000055;
-      padding-left: 1px;
-      margin-bottom: 25px;
-      margin-top: 0px;
-    }
-    to {
-      width: calc(100% + 22px);
-      padding-top: 7px;
-      padding-bottom: 20px;
-      margin-left: -10px;
-      box-shadow: 0 8px 20px 0px #00000030;
-      padding-left: 5px;
-      margin-bottom: 21px;
-      margin-top: -4px;
-    }
-  }
-
-  @keyframes shrink {
-    from {
-      width: calc(100% + 22px);
-      padding-top: 7px;
-      padding-bottom: 20px;
-      margin-left: -10px;
-      box-shadow: 0 8px 20px 0px #00000030;
-      padding-left: 5px;
-      margin-bottom: 21px;
-      margin-top: -4px;
-    }
-    to {
-      width: calc(100% + 2px);
-      padding-top: 4px;
-      padding-bottom: 14px;
-      margin-left: 0px;
-      box-shadow: 0 4px 15px 0px #00000055;
-      padding-left: 1px;
-      margin-bottom: 25px;
-      margin-top: 0px;
-    }
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
   }
 `;

+ 10 - 11
dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroupDashboard.tsx

@@ -58,15 +58,6 @@ class EnvGroupDashboard extends Component<PropsType, StateType> {
       return (
         <>
           <ControlRow hasMultipleChilds={isAuthorizedToAdd}>
-            {isAuthorizedToAdd && (
-              <Button
-                onClick={() =>
-                  this.setState({ createEnvMode: !this.state.createEnvMode })
-                }
-              >
-                <i className="material-icons">add</i> Create Env Group
-              </Button>
-            )}
             <SortFilterWrapper>
               <NamespaceSelector
                 setNamespace={(namespace) =>
@@ -84,6 +75,15 @@ class EnvGroupDashboard extends Component<PropsType, StateType> {
                 sortType={this.state.sortType}
               />
             </SortFilterWrapper>
+            {isAuthorizedToAdd && (
+              <Button
+                onClick={() =>
+                  this.setState({ createEnvMode: !this.state.createEnvMode })
+                }
+              >
+                <i className="material-icons">add</i> Create env group
+              </Button>
+            )}
           </ControlRow>
 
           <EnvGroupList
@@ -174,12 +174,11 @@ const Button = styled.div`
   font-size: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 20px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   padding: 0px 8px;
   padding-bottom: 1px;
-  margin-right: 10px;
   font-weight: 500;
   padding-right: 15px;
   overflow: hidden;

+ 42 - 5
dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx

@@ -9,6 +9,7 @@ import styled, { keyframes } from "styled-components";
 import backArrow from "assets/back_arrow.png";
 import key from "assets/key.svg";
 import loading from "assets/loading.gif";
+import leftArrow from "assets/left-arrow.svg";
 
 import { ClusterType } from "shared/types";
 import { Context } from "shared/Context";
@@ -418,10 +419,13 @@ export const ExpandedEnvGroupFC = ({
 
   return (
     <StyledExpandedChart>
+      <BreadcrumbRow>
+        <Breadcrumb onClick={closeExpanded}>
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
       <HeaderWrapper>
-        <BackButton onClick={closeExpanded}>
-          <BackButtonImg src={backArrow} />
-        </BackButton>
         <TitleSection icon={key} iconWidth="33px">
           {envGroup.name}
           <TagWrapper>
@@ -628,6 +632,39 @@ const ApplicationsList = ({ envGroup }: { envGroup: EditableEnvGroup }) => {
   );
 };
 
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
 const HeadingWrapper = styled.div`
   display: flex;
   margin-bottom: 15px;
@@ -664,8 +701,8 @@ const TextWrap = styled.div``;
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 15px 0px 55px;
 `;
 

+ 37 - 110
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -1,9 +1,9 @@
 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";
 import _, { cloneDeep } from "lodash";
 import loadingSrc from "assets/loading.gif";
+import leftArrow from "assets/left-arrow.svg";
 
 import { ChartType, ClusterType, ResourceType } from "shared/types";
 import { Context } from "shared/Context";
@@ -760,10 +760,13 @@ const ExpandedChart: React.FC<Props> = (props) => {
         />
       ) : (
         <StyledExpandedChart>
+          <BreadcrumbRow>
+            <Breadcrumb onClick={props.closeChart}>
+              <ArrowIcon src={leftArrow} />
+              <Wrap>Back</Wrap>
+            </Breadcrumb>
+          </BreadcrumbRow>
           <HeaderWrapper>
-            <BackButton onClick={props.closeChart}>
-              <BackButtonImg src={backArrow} />
-            </BackButton>
             <TitleSection
               icon={currentChart.chart.metadata.icon}
               iconWidth="33px"
@@ -891,88 +894,52 @@ const ExpandedChart: React.FC<Props> = (props) => {
 
 export default ExpandedChart;
 
-const RepositoryName = styled.div`
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  max-width: 390px;
-  position: relative;
-  margin-right: 3px;
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
 `;
 
-const Tooltip = styled.div`
-  position: absolute;
-  left: -40px;
-  top: 28px;
-  min-height: 18px;
-  max-width: calc(700px);
-  padding: 5px 7px;
-  background: #272731;
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
   z-index: 999;
-  color: white;
-  font-size: 12px;
-  font-family: "Work Sans", sans-serif;
-  outline: 1px solid #ffffff55;
-  opacity: 0;
-  animation: faded-in 0.2s 0.15s;
-  animation-fill-mode: forwards;
-  @keyframes faded-in {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
 `;
 
-const TextWrap = styled.div``;
-
-const LoadingWrapper = styled.div`
-  width: 100%;
-  height: 200px;
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
   display: flex;
   align-items: center;
-  justify-content: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
 `;
 
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
+const TextWrap = styled.div``;
+
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 35px 0px;
 `;
 
 const BodyWrapper = styled.div`
   position: relative;
-  margin-bottom: 120px;
-`;
-
-const BackButton = styled.div`
-  position: absolute;
-  top: 0px;
-  right: 0px;
-  display: flex;
-  width: 36px;
-  cursor: pointer;
-  height: 36px;
-  align-items: center;
-  justify-content: center;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  background: #ffffff11;
-
-  :hover {
-    background: #ffffff22;
-    > img {
-      opacity: 1;
-    }
-  }
-`;
-
-const BackButtonImg = styled.img`
-  width: 16px;
-  opacity: 0.75;
+  margin-bottom: 50px;
 `;
 
 const Header = styled.div`
@@ -1113,29 +1080,8 @@ const NamespaceTag = styled.div`
   border-bottom-left-radius: 0px;
 `;
 
-const Icon = styled.img`
-  width: 100%;
-`;
-
-const IconWrapper = styled.div`
-  color: #efefef;
-  font-size: 16px;
-  height: 20px;
-  width: 20px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  border-radius: 3px;
-  margin-right: 12px;
-
-  > i {
-    font-size: 20px;
-  }
-`;
-
 const StyledExpandedChart = styled.div`
   width: 100%;
-  overflow: hidden;
   z-index: 0;
   animation: fadeIn 0.3s;
   animation-timing-function: ease-out;
@@ -1153,25 +1099,6 @@ const StyledExpandedChart = styled.div`
   }
 `;
 
-const DeploymentImageContainer = styled.div`
-  height: 20px;
-  font-size: 13px;
-  position: relative;
-  display: flex;
-  margin-left: 15px;
-  margin-bottom: -3px;
-  align-items: center;
-  font-weight: 400;
-  justify-content: center;
-  color: #ffffff66;
-  padding-left: 5px;
-`;
-
-const DeploymentTypeIcon = styled(Icon)`
-  width: 20px;
-  margin-right: 10px;
-`;
-
 const A = styled.a`
   color: #8590ff;
   text-decoration: underline;

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

@@ -156,6 +156,5 @@ export default withRouter(ExpandedChartWrapper);
 
 const LoadingWrapper = styled.div`
   width: 100%;
-  height: 100%;
-  margin-top: -50px;
+  height: 100vh;
 `;

+ 87 - 49
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -2,7 +2,7 @@ import React, { useContext, useMemo, useState } from "react";
 import styled from "styled-components";
 import yaml from "js-yaml";
 
-import backArrow from "assets/back_arrow.png";
+import leftArrow from "assets/left-arrow.svg";
 import { cloneDeep, set } from "lodash";
 import loading from "assets/loading.gif";
 
@@ -426,54 +426,92 @@ const ExpandedJobHeader: React.FC<{
   setDisableForm,
   disableRevisions,
 }) => (
-  <HeaderWrapper>
-    <BackButton onClick={closeChart}>
-      <BackButtonImg src={backArrow} />
-    </BackButton>
-    <TitleSection icon={chart?.chart.metadata.icon} iconWidth="33px">
-      {chart?.name}
-      <DeploymentType currentChart={chart} />
-      <TagWrapper>
-        Namespace <NamespaceTag>{chart.namespace}</NamespaceTag>
-      </TagWrapper>
-    </TitleSection>
-    {chart?.config?.description ? (
-      <Description>{chart?.config?.description}</Description>
-    ) : null}
-
-    <InfoWrapper>
-      <LastDeployed>
-        Run {jobs?.length} times <Dot>•</Dot>Last template update at
-        {" " + readableDate(chart.info.last_deployed)}
-      </LastDeployed>
-    </InfoWrapper>
-    {!disableRevisions ? (
-      <RevisionSection
-        chart={chart}
-        refreshChart={() => refreshChart()}
-        setRevision={(chart, isCurrent) => {
-          loadChartWithSpecificRevision(chart?.version);
-          setDisableForm(!isCurrent);
-        }}
-        forceRefreshRevisions={false}
-        refreshRevisionsOff={() => {}}
-        shouldUpdate={
-          chart?.latest_version &&
-          chart?.latest_version !== chart?.chart.metadata.version
-        }
-        latestVersion={chart?.latest_version}
-        upgradeVersion={(_version, cb) => {
-          upgradeChart().then(() => {
-            if (typeof cb === "function") {
-              cb();
-            }
-          });
-        }}
-      />
-    ) : null}
-  </HeaderWrapper>
+  <>
+    <BreadcrumbRow>
+      <Breadcrumb onClick={closeChart}>
+        <ArrowIcon src={leftArrow} />
+        <Wrap>Back</Wrap>
+      </Breadcrumb>
+    </BreadcrumbRow>
+    <HeaderWrapper>
+      <TitleSection icon={chart?.chart.metadata.icon} iconWidth="33px">
+        {chart?.name}
+        <DeploymentType currentChart={chart} />
+        <TagWrapper>
+          Namespace <NamespaceTag>{chart.namespace}</NamespaceTag>
+        </TagWrapper>
+      </TitleSection>
+      {chart?.config?.description ? (
+        <Description>{chart?.config?.description}</Description>
+      ) : null}
+
+      <InfoWrapper>
+        <LastDeployed>
+          Run {jobs?.length} times <Dot>•</Dot>Last template update at
+          {" " + readableDate(chart.info.last_deployed)}
+        </LastDeployed>
+      </InfoWrapper>
+      {!disableRevisions ? (
+        <RevisionSection
+          chart={chart}
+          refreshChart={() => refreshChart()}
+          setRevision={(chart, isCurrent) => {
+            loadChartWithSpecificRevision(chart?.version);
+            setDisableForm(!isCurrent);
+          }}
+          forceRefreshRevisions={false}
+          refreshRevisionsOff={() => {}}
+          shouldUpdate={
+            chart?.latest_version &&
+            chart?.latest_version !== chart?.chart.metadata.version
+          }
+          latestVersion={chart?.latest_version}
+          upgradeVersion={(_version, cb) => {
+            upgradeChart().then(() => {
+              if (typeof cb === "function") {
+                cb();
+              }
+            });
+          }}
+        />
+      ) : null}
+    </HeaderWrapper>
+  </>
 );
 
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
 const RunsDescription = styled.div`
   color: #ffffff;
   font-size: 13px;
@@ -546,8 +584,8 @@ const CLIModalIcon = styled(CommandLineIcon)`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 15px 0px 55px;
 `;
 

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

@@ -49,7 +49,7 @@ GraphSection.contextType = Context;
 const StyledGraphSection = styled.div`
   width: 100%;
   min-height: 400px;
-  height: 50vh;
+  height: calc(100vh - 400px);
   font-size: 13px;
   overflow: hidden;
   border-radius: 8px;

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

@@ -143,7 +143,7 @@ const StyledListSection = styled.div`
   font-size: 13px;
   width: 100%;
   min-height: 400px;
-  height: 50vh;
+  height: calc(100vh - 400px);
   font-size: 13px;
   overflow: hidden;
   border-radius: 8px;

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

@@ -100,6 +100,7 @@ export default class ValuesYaml extends Component<PropsType, StateType> {
             value={this.state.values}
             onChange={(e: any) => this.setState({ values: e })}
             readOnly={this.props.disabled}
+            height="calc(100vh - 462px)"
           />
         </Wrapper>
         {!this.props.disabled && (
@@ -129,7 +130,7 @@ const StyledValuesYaml = styled.div`
   flex-direction: column;
   width: 100%;
   min-height: 400px;
-  height: 50vh;
+  height: calc(100vh - 400px);
   font-size: 13px;
   overflow: hidden;
   border-radius: 8px;

+ 40 - 4
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/ExpandedJobRun.tsx

@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from "react";
 import { get, isEmpty } from "lodash";
 import styled from "styled-components";
 
-import backArrow from "assets/back_arrow.png";
+import leftArrow from "assets/left-arrow.svg";
 import KeyValueArray from "components/form-components/KeyValueArray";
 import Loading from "components/Loading";
 import TabRegion from "components/TabRegion";
@@ -197,10 +197,13 @@ const ExpandedJobRun = ({
 
   return (
     <StyledExpandedChart>
+      <BreadcrumbRow>
+        <Breadcrumb onClick={onClose}>
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
       <HeaderWrapper>
-        <BackButton onClick={() => onClose()}>
-          <BackButtonImg src={backArrow} />
-        </BackButton>
         <TitleSection icon={currentChart.chart.metadata.icon} iconWidth="33px">
           {chart.name} <Gray>at {readableDate(run.status.startTime)}</Gray>
         </TitleSection>
@@ -261,6 +264,39 @@ const ExpandedJobRun = ({
 
 export default ExpandedJobRun;
 
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
 const Row = styled.div`
   margin-top: 20px;
 `;

+ 5 - 6
dashboard/src/main/home/cluster-dashboard/expanded-chart/jobs/JobResource.tsx

@@ -172,7 +172,7 @@ export default class JobResource extends Component<PropsType, StateType> {
           onClick={() => this.setState({ configIsExpanded: true })}
         >
           <img src={plus} />
-          Show Job Config
+          Show job config
         </ExpandConfigBar>
       );
     } else {
@@ -494,14 +494,13 @@ const StartedText = styled.div`
 const StyledJob = styled.div`
   display: flex;
   flex-direction: column;
-  background: #2b2e3699;
   margin-bottom: 20px;
-  border-radius: 5px;
   overflow: hidden;
-  border: 1px solid #ffffff0a;
-
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    border: 1px solid #ffffff3c;
+    border: 1px solid #7a7b80;
   }
 `;
 

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

@@ -686,7 +686,7 @@ const MetricsLabel = styled.div`
 const StyledMetricsSection = styled.div`
   width: 100%;
   min-height: 400px;
-  height: 50vh;
+  height: calc(100vh - 400px);
   display: flex;
   flex-direction: column;
   position: relative;

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

@@ -243,7 +243,7 @@ const StyledStatusSection = styled.div`
   overflow: hidden;
   width: 100%;
   min-height: 400px;
-  height: 50vh;
+  height: calc(100vh - 400px);
   font-size: 13px;
   overflow: hidden;
   border-radius: 8px;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/components/ButtonEnablePREnvironments.tsx

@@ -123,7 +123,7 @@ const Button = styled(DynamicLink)`
   font-size: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 20px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   padding: 0px 8px;

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentCard.tsx

@@ -310,14 +310,14 @@ const PRName = styled.div`
 
 const DeploymentCardWrapper = styled.div`
   display: flex;
-  background: #2b2e3699;
   justify-content: space-between;
-  border-radius: 5px;
   font-size: 13px;
   height: 75px;
   padding: 12px;
   padding-left: 14px;
-  border: 1px solid #ffffff0f;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
 
   animation: fadeIn 0.5s;
   @keyframes fadeIn {

+ 43 - 7
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentDetail.tsx

@@ -1,6 +1,5 @@
 import React, { useContext, useEffect, useState } from "react";
 import styled from "styled-components";
-import backArrow from "assets/back_arrow.png";
 import TitleSection from "components/TitleSection";
 import pr_icon from "assets/pull_request_icon.svg";
 import { useRouteMatch, useLocation } from "react-router";
@@ -13,6 +12,7 @@ import ChartList from "../../chart/ChartList";
 import github from "assets/github-white.png";
 import { integrationList } from "shared/common";
 import { capitalize } from "shared/string_utils";
+import leftArrow from "assets/left-arrow.svg";
 
 const DeploymentDetail = () => {
   const { params } = useRouteMatch<{ namespace: string }>();
@@ -65,12 +65,15 @@ const DeploymentDetail = () => {
 
   return (
     <StyledExpandedChart>
-      <HeaderWrapper>
-        <BackButton
+      <BreadcrumbRow>
+        <Breadcrumb
           to={`/preview-environments/deployments/${environmentId}/${repository}`}
         >
-          <BackButtonImg src={backArrow} />
-        </BackButton>
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
+      <HeaderWrapper>
         <Title icon={pr_icon} iconWidth="25px">
           {prDeployment.gh_pr_name}
         </Title>
@@ -142,6 +145,39 @@ const DeploymentDetail = () => {
 
 export default DeploymentDetail;
 
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled(DynamicLink)`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
 const Flex = styled.div`
   display: flex;
   align-items: center;
@@ -189,8 +225,8 @@ const GHALink = styled(DynamicLink)`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin-bottom: 20px;
 `;
 

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/PullRequestCard.tsx

@@ -135,14 +135,14 @@ const PRName = styled.div`
 
 const DeploymentCardWrapper = styled.div`
   display: flex;
-  background: #2b2e3699;
   justify-content: space-between;
-  border-radius: 5px;
   font-size: 13px;
   height: 75px;
   padding: 12px;
   padding-left: 14px;
-  border: 1px solid #ffffff0f;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
 
   animation: fadeIn 0.5s;
   @keyframes fadeIn {

+ 4 - 12
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentCard.tsx

@@ -168,17 +168,16 @@ const OptionWrapper = styled.div`
 const EnvironmentCardWrapper = styled(DynamicLink)`
   display: flex;
   color: #ffffff;
-  background: #2b2e3699;
   justify-content: space-between;
-  border-radius: 5px;
   cursor: pointer;
   height: 75px;
   padding: 12px;
   padding-left: 14px;
-  border: 1px solid #ffffff0f;
-
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    border: 1px solid #ffffff3c;
+    border: 1px solid #7a7b80;
   }
   animation: fadeIn 0.5s;
   @keyframes fadeIn {
@@ -278,13 +277,6 @@ const DeleteButton = styled(Button)`
   }}
 `;
 
-const CancelButton = styled(Button)`
-  background: #616feecc;
-  :hover {
-    background: #505edddd;
-  }
-`;
-
 const ActionWrapper = styled.div`
   display: flex;
   align-items: center;

+ 4 - 4
dashboard/src/main/home/cluster-dashboard/stacks/Dashboard.tsx

@@ -40,10 +40,6 @@ const Dashboard = () => {
         description="Groups of applications deployed from a shared source."
       />
       <Action.Row>
-        <Action.Button to={"/stacks/launch"}>
-          <i className="material-icons">add</i>
-          Create Stack
-        </Action.Button>
         <FilterWrapper>
           <StyledSortSelector>
             <Label>
@@ -77,6 +73,10 @@ const Dashboard = () => {
             setNamespace={handleNamespaceChange}
           />
         </FilterWrapper>
+        <Action.Button to={"/stacks/launch"}>
+          <i className="material-icons">add</i>
+          Create stack
+        </Action.Button>
       </Action.Row>
       <StackList namespace={currentNamespace} sortBy={currentSort} />
     </>

+ 44 - 8
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/ExpandedStack.tsx

@@ -3,7 +3,7 @@ import Placeholder from "components/Placeholder";
 import TabSelector from "components/TabSelector";
 import TitleSection from "components/TitleSection";
 import React, { useContext, useState } from "react";
-import backArrow from "assets/back_arrow.png";
+import leftArrow from "assets/left-arrow.svg";
 import { useParams, useRouteMatch } from "react-router";
 import api from "shared/api";
 import { Context } from "shared/Context";
@@ -94,10 +94,13 @@ const ExpandedStack = () => {
 
   return (
     <div>
+      <BreadcrumbRow>
+        <Breadcrumb to="/stacks">
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
       <StackTitleWrapper>
-        <BackButton to="/stacks">
-          <BackButtonImg src={backArrow} />
-        </BackButton>
         <TitleSection materialIconClass="material-icons-outlined" icon={"lan"}>
           {stack.name}
         </TitleSection>
@@ -154,7 +157,7 @@ const ExpandedStack = () => {
                 <Action.Row>
                   <Action.Button to={`${url}/new-app-resource`}>
                     <i className="material-icons">add</i>
-                    Create App Resource
+                    Create app resource
                   </Action.Button>
                 </Action.Row>
                 {currentRevision.id !== stack.latest_revision.id ? (
@@ -183,7 +186,7 @@ const ExpandedStack = () => {
             ),
           },
           {
-            label: "Source Config",
+            label: "Source config",
             value: "source_config",
             component: (
               <>
@@ -197,7 +200,7 @@ const ExpandedStack = () => {
             ),
           },
           {
-            label: "Env Groups",
+            label: "Env groups",
             value: "env_groups",
             component: (
               <>
@@ -205,7 +208,7 @@ const ExpandedStack = () => {
                 <Action.Row>
                   <Action.Button to={`${url}/new-env-group`}>
                     <i className="material-icons">add</i>
-                    Create Env Group
+                    Create env group
                   </Action.Button>
                 </Action.Row>
                 <EnvGroups stack={stack} />
@@ -238,6 +241,39 @@ const ExpandedStack = () => {
 
 export default ExpandedStack;
 
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled(DynamicLink)`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
 const PaddingBottom = styled.div`
   width: 100%;
   height: 150px;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/stacks/_StackList.tsx

@@ -117,7 +117,7 @@ const StackList = ({
       <Placeholder height="250px">
         <div>
           <h3>No stacks found</h3>
-          <p>You can create a stack by clicking the "Create Stack" button.</p>
+          <p>You can create a stack by clicking the "Create stack" button.</p>
         </div>
       </Placeholder>
     );

+ 1 - 2
dashboard/src/main/home/cluster-dashboard/stacks/components/styles.ts

@@ -146,13 +146,12 @@ export const Action = {
     font-size: 13px;
     cursor: pointer;
     font-family: "Work Sans", sans-serif;
-    border-radius: 20px;
+    border-radius: 5px;
     color: white;
     height: 35px;
     padding: 0px 8px;
     min-width: 130px;
     padding-bottom: 1px;
-    margin-right: 10px;
     font-weight: 500;
     padding-right: 15px;
     overflow: hidden;

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

@@ -220,13 +220,13 @@ const Overview = () => {
 
       <SubmitButton
         disabled={!isValid || submitButtonStatus !== ""}
-        text="Create Stack"
+        text="Create stack"
         onClick={handleSubmit}
         clearPosition
         statusPosition="left"
         status={submitButtonStatus}
       >
-        Create Stack
+        Create stack
       </SubmitButton>
     </>
   );

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

@@ -11,14 +11,14 @@ export const Card = {
   Wrapper: styled.div<{ variant?: "clickable" | "unclickable" }>`
     display: flex;
     color: #ffffff;
-    background: #2b2e3699;
     justify-content: space-between;
-    border-radius: 5px;
     height: 75px;
     padding: 12px;
     padding-left: 14px;
-    border: 1px solid #ffffff0f;
     align-items: center;
+    border-radius: 5px;
+    background: #262a30;
+    border: 1px solid #494b4f;
 
     ${(props) => {
       if (props.variant === "unclickable") {
@@ -33,7 +33,7 @@ export const Card = {
       return `
         cursor: pointer;
         :hover {
-          border: 1px solid #ffffff3c;
+          border: 1px solid #7A7B80;
         }
       `;
     }}

+ 72 - 157
dashboard/src/main/home/dashboard/ClusterList.tsx

@@ -3,19 +3,14 @@ import styled from "styled-components";
 
 import { Context } from "shared/Context";
 import api from "shared/api";
-import {
-  ClusterType,
-  DetailedClusterType,
-  DetailedIngressError,
-} from "shared/types";
+import { ClusterType, DetailedClusterType } from "shared/types";
 import Helper from "components/form-components/Helper";
 import { pushFiltered } from "shared/routing";
 
 import { RouteComponentProps, withRouter } from "react-router";
 
-import CopyToClipboard from "components/CopyToClipboard";
-import Loading from "components/Loading";
 import Modal from "../modals/Modal";
+import Heading from "components/form-components/Heading";
 
 type PropsType = RouteComponentProps & {
   currentCluster: ClusterType;
@@ -59,10 +54,6 @@ class Templates extends Component<PropsType, StateType> {
 
       if (res.data) {
         this.setState({ clusters: res.data, loading: false, error: "" });
-
-        this.state.clusters.forEach((cluster) => {
-          this.updateClusterWithDetailedData(cluster.id);
-        });
       } else {
         this.setState({ loading: false, error: "Response data missing" });
       }
@@ -71,90 +62,67 @@ class Templates extends Component<PropsType, StateType> {
     }
   };
 
-  updateClusterWithDetailedData = async (clusterId: number) => {
-    try {
-      const currentClusterIndex = this.state.clusters.findIndex(
-        (cluster) => cluster.id === clusterId
-      );
-      const res = await api.getCluster(
-        "<token>",
-        {},
-        { project_id: this.context.currentProject.id, cluster_id: clusterId }
-      );
-      if (res.data) {
-        this.setState((prevState) => {
-          const currentCluster = prevState.clusters[currentClusterIndex];
-          prevState.clusters.splice(currentClusterIndex, 1, {
-            ...currentCluster,
-            ingress_ip: res.data.ingress_ip,
-            ingress_error: res.data.ingress_error,
-          });
-          return prevState;
-        });
-      }
-    } catch (error) {}
-  };
-
   renderIcon = () => {
     return (
       <DashboardIcon>
-        <i className="material-icons">device_hub</i>
+        <svg
+          width="16"
+          height="16"
+          viewBox="0 0 19 19"
+          fill="none"
+          xmlns="http://www.w3.org/2000/svg"
+        >
+          <path
+            d="M15.207 12.4403C16.8094 12.4403 18.1092 11.1414 18.1092 9.53907C18.1092 7.93673 16.8094 6.63782 15.207 6.63782"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+          <path
+            d="M3.90217 12.4403C2.29983 12.4403 1 11.1414 1 9.53907C1 7.93673 2.29983 6.63782 3.90217 6.63782"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+          <path
+            fill-rule="evenodd"
+            clip-rule="evenodd"
+            d="M9.54993 13.4133C7.4086 13.4133 5.69168 11.6964 5.69168 9.55417C5.69168 7.41284 7.4086 5.69592 9.54993 5.69592C11.6913 5.69592 13.4082 7.41284 13.4082 9.55417C13.4082 11.6964 11.6913 13.4133 9.54993 13.4133Z"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+          <path
+            d="M6.66895 15.207C6.66895 16.8094 7.96787 18.1092 9.5702 18.1092C11.1725 18.1092 12.4715 16.8094 12.4715 15.207"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+          <path
+            d="M6.66895 3.90217C6.66895 2.29983 7.96787 1 9.5702 1C11.1725 1 12.4715 2.29983 12.4715 3.90217"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+          <path
+            fill-rule="evenodd"
+            clip-rule="evenodd"
+            d="M5.69591 9.54996C5.69591 7.40863 7.41283 5.69171 9.55508 5.69171C11.6964 5.69171 13.4133 7.40863 13.4133 9.54996C13.4133 11.6913 11.6964 13.4082 9.55508 13.4082C7.41283 13.4082 5.69591 11.6913 5.69591 9.54996Z"
+            stroke="white"
+            stroke-width="1.5"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+        </svg>
       </DashboardIcon>
     );
   };
 
-  renderIngressIp = (
-    clusterId: number,
-    ingressIp: string | undefined,
-    ingressError: DetailedIngressError
-  ) => {
-    if (typeof ingressIp !== "string") {
-      return (
-        <Url onClick={(e) => e.preventDefault()}>
-          <Loading />
-        </Url>
-      );
-    }
-
-    if (!ingressIp.length && ingressError) {
-      return (
-        <>
-          <Url
-            onClick={(e) => {
-              e.stopPropagation();
-              this.setState({ showErrorModal: { clusterId, show: true } });
-            }}
-          >
-            <Bolded>Ingress IP:</Bolded>
-            <span>{ingressError.message}</span>
-            <i className="material-icons">launch</i>
-          </Url>
-        </>
-      );
-    }
-
-    if (!ingressIp.length) {
-      return (
-        <Url>
-          <Bolded>Ingress IP:</Bolded>
-          <span>Ingress IP not available</span>
-        </Url>
-      );
-    }
-
-    return (
-      <CopyToClipboard
-        as={Url}
-        text={ingressIp}
-        wrapperProps={{ onClick: (e: any) => e.stopPropagation() }}
-      >
-        <Bolded>Ingress IP:</Bolded>
-        <span>{ingressIp}</span>
-        <i className="material-icons-outlined">content_copy</i>
-      </CopyToClipboard>
-    );
-  };
-
   renderClusters = () => {
     return this.state.clusters.map(
       (cluster: DetailedClusterType, i: number) => {
@@ -168,15 +136,8 @@ class Templates extends Component<PropsType, StateType> {
             }}
             key={i}
           >
-            <TitleContainer>
-              {this.renderIcon()}
-              <TemplateTitle>{cluster.name}</TemplateTitle>
-            </TitleContainer>
-            {this.renderIngressIp(
-              cluster.id,
-              cluster.ingress_ip,
-              cluster.ingress_error
-            )}
+            {this.renderIcon()}
+            <TemplateTitle>{cluster.name}</TemplateTitle>
           </TemplateBlock>
         );
       }
@@ -209,7 +170,7 @@ class Templates extends Component<PropsType, StateType> {
   render() {
     return (
       <StyledClusterList>
-        <Helper>Clusters connected to this project:</Helper>
+        {/* <Heading isAtTop>Connected clusters</Heading> */}
         <TemplateList>{this.renderClusters()}</TemplateList>
         {this.renderErrorModal()}
       </StyledClusterList>
@@ -238,40 +199,30 @@ const CodeBlock = styled.span`
 `;
 
 const StyledClusterList = styled.div`
-  margin-top: -17px;
+  margin-top: -7px;
   padding-left: 2px;
   overflow: visible;
 `;
 
-const TitleContainer = styled.div`
-  display: flex;
-  width: 100%;
-  flex-direction: column;
-  align-items: center;
-`;
 const DashboardIcon = styled.div`
   position: relative;
-  height: 45px;
-  min-width: 45px;
-  width: 45px;
-  border-radius: 5px;
+  height: 25px;
+  min-width: 25px;
+  width: 25px;
+  border-radius: 200px;
+  margin-right: 15px;
   display: flex;
   align-items: center;
   justify-content: center;
   background: #676c7c;
-  border: 2px solid #8e94aa;
-  margin-bottom: 10px;
+  border: 1px solid #8e94aa;
   > i {
     font-size: 22px;
   }
 `;
 
 const TemplateTitle = styled.div`
-  margin-bottom: 0px;
-  margin-top: 13px;
-  width: 100%;
   text-align: center;
-  font-size: 14px;
   white-space: nowrap;
   overflow: hidden;
   white-space: nowrap;
@@ -279,25 +230,22 @@ const TemplateTitle = styled.div`
 `;
 
 const TemplateBlock = styled.div`
-  border: 1px solid #ffffff00;
   align-items: center;
   user-select: none;
-  border-radius: 8px;
   display: flex;
   font-size: 13px;
   font-weight: 500;
-  padding: 35px;
-  flex-direction: column;
+  padding: 15px;
+  margin-bottom: 20px;
   align-item: center;
-  justify-content: space-between;
-  height: 192px;
   cursor: pointer;
   color: #ffffff;
   position: relative;
-  background: #26282f;
-  box-shadow: 0 4px 15px 0px #00000055;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    background: #ffffff11;
+    border: 1px solid #7a7b80;
   }
 
   animation: fadeIn 0.3s 0s;
@@ -314,37 +262,4 @@ const TemplateBlock = styled.div`
 const TemplateList = styled.div`
   overflow-y: auto;
   overflow: visible;
-  margin-top: 32px;
-  padding-bottom: 150px;
-  display: grid;
-  grid-column-gap: 25px;
-  grid-row-gap: 25px;
-  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
-`;
-
-const Url = styled.a`
-  width: 100%;
-  font-size: 13px;
-  user-select: text;
-  font-weight: 400;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  > i {
-    margin-left: 10px;
-    font-size: 15px;
-  }
-
-  > span {
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-  }
-`;
-
-const Bolded = styled.div`
-  font-weight: 500;
-  color: #ffffff44;
-  margin-right: 6px;
-  white-space: nowrap;
 `;

+ 13 - 14
dashboard/src/main/home/dashboard/Dashboard.tsx

@@ -149,16 +149,16 @@ class Dashboard extends Component<PropsType, StateType> {
     let { currentProject, capabilities } = this.context;
     let { onShowProjectSettings } = this;
 
-    let tabOptions = [{ label: "Project Overview", value: "overview" }];
+    let tabOptions = [{ label: "Connected clusters", value: "overview" }];
 
     if (this.props.isAuthorized("cluster", "", ["get", "create"])) {
-      tabOptions.push({ label: "Create a Cluster", value: "create-cluster" });
+      tabOptions.push({ label: "Create a cluster", value: "create-cluster" });
     }
 
-    tabOptions.push({ label: "Provisioner Status", value: "provisioner" });
+    tabOptions.push({ label: "Provisioner status", value: "provisioner" });
 
     if (!capabilities?.provisioner) {
-      tabOptions = [{ label: "Project Overview", value: "overview" }];
+      tabOptions = [{ label: "Project overview", value: "overview" }];
     }
 
     return (
@@ -255,7 +255,7 @@ const TopRow = styled.div`
 `;
 
 const Description = styled.div`
-  color: #aaaabb;
+  color: #8b949f;
   margin-top: 13px;
   margin-left: 2px;
   font-size: 13px;
@@ -266,7 +266,7 @@ const InfoLabel = styled.div`
   height: 20px;
   display: flex;
   align-items: center;
-  color: #7a838f;
+  color: #8b949f;
   font-size: 13px;
   > i {
     color: #8b949f;
@@ -284,8 +284,8 @@ const InfoSection = styled.div`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 10px 0px 20px;
 `;
 
@@ -299,24 +299,23 @@ const Overlay = styled.div`
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 24px;
+  font-size: 21px;
   font-weight: 500;
   font-family: "Work Sans", sans-serif;
   color: white;
 `;
 
 const DashboardImage = styled.img`
-  height: 45px;
-  width: 45px;
+  height: 35px;
+  width: 35px;
   border-radius: 5px;
-  box-shadow: 0 2px 5px 4px #00000011;
 `;
 
 const DashboardIcon = styled.div`
   position: relative;
-  height: 45px;
+  height: 35px;
   margin-right: 17px;
-  width: 45px;
+  width: 35px;
   border-radius: 5px;
   display: flex;
   align-items: center;

+ 5 - 6
dashboard/src/main/home/infrastructure/InfrastructureList.tsx

@@ -223,12 +223,11 @@ const DatabasesListWrapper = styled.div`
 `;
 
 const StyledTableWrapper = styled.div`
-  background: #26282f;
   padding: 14px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
   position: relative;
-  border: 2px solid #9eb4ff00;
+  border-radius: 8px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   width: 100%;
   height: 100%;
   :not(:last-child) {
@@ -274,8 +273,8 @@ const InfoSection = styled.div`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 10px 0px 35px;
 `;
 

+ 2 - 2
dashboard/src/main/home/infrastructure/components/ProvisionInfra.tsx

@@ -375,8 +375,8 @@ export default ProvisionInfra;
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 10px 0px 35px;
 `;
 

+ 49 - 10
dashboard/src/main/home/integrations/IntegrationCategories.tsx

@@ -11,6 +11,7 @@ import Loading from "../../../components/Loading";
 import SlackIntegrationList from "./SlackIntegrationList";
 import TitleSection from "components/TitleSection";
 import GitlabIntegrationList from "./GitlabIntegrationList";
+import leftArrow from "assets/left-arrow.svg";
 
 type Props = RouteComponentProps & {
   category: string;
@@ -112,13 +113,16 @@ const IntegrationCategories: React.FC<Props> = (props) => {
 
   return (
     <>
-      <Flex>
-        <TitleSection
-          handleNavBack={() =>
-            pushFiltered(props, "/integrations", ["project_id"])
-          }
-          icon={icon}
+      <BreadcrumbRow>
+        <Breadcrumb
+          onClick={() => pushFiltered(props, "/integrations", ["project_id"])}
         >
+          <ArrowIcon src={leftArrow} />
+          <Wrap>Back</Wrap>
+        </Breadcrumb>
+      </BreadcrumbRow>
+      <Flex>
+        <TitleSection icon={icon} iconWidth="32px">
           {label}
         </TitleSection>
         <Button
@@ -169,6 +173,39 @@ const IntegrationCategories: React.FC<Props> = (props) => {
 
 export default withRouter(IntegrationCategories);
 
+const Wrap = styled.div`
+  z-index: 999;
+`;
+
+const ArrowIcon = styled.img`
+  width: 15px;
+  margin-right: 8px;
+  opacity: 50%;
+`;
+
+const BreadcrumbRow = styled.div`
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+`;
+
+const Breadcrumb = styled.div`
+  color: #aaaabb88;
+  font-size: 13px;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  margin-top: -10px;
+  z-index: 999;
+  padding: 5px;
+  padding-right: 7px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+  }
+`;
+
 const Flex = styled.div`
   display: flex;
   align-items: center;
@@ -196,10 +233,12 @@ const Button = styled.div`
     background: #505edddd;
   }
   color: white;
+  height: 35px;
   font-weight: 500;
   font-size: 13px;
-  padding: 10px 15px;
-  border-radius: 3px;
+  padding: 7px 7px;
+  padding-right: 12px;
+  border-radius: 5px;
   cursor: pointer;
   box-shadow: 0 5px 8px 0px #00000010;
   display: flex;
@@ -210,10 +249,10 @@ const Button = styled.div`
   i {
     width: 20px;
     height: 20px;
-    font-size: 16px;
+    font-size: 15px;
     display: flex;
     align-items: center;
-    margin-right: 10px;
+    margin-right: 5px;
     justify-content: center;
   }
 `;

+ 13 - 14
dashboard/src/main/home/integrations/IntegrationList.tsx

@@ -159,11 +159,11 @@ export default class IntegrationList extends Component<PropsType, StateType> {
     >
       {this.allCollapsed() ? (
         <>
-          <i className="material-icons">expand_more</i> Expand All
+          <i className="material-icons">expand_more</i> Expand all
         </>
       ) : (
         <>
-          <i className="material-icons">expand_less</i> Collapse All
+          <i className="material-icons">expand_less</i> Collapse all
         </>
       )}
     </Button>
@@ -182,9 +182,6 @@ export default class IntegrationList extends Component<PropsType, StateType> {
           onYes={this.handleDeleteIntegration}
           onNo={() => this.setState({ isDelete: false })}
         />
-        {this.props.titles && this.props.titles.length > 0 && (
-          <ControlRow>{this.collapseAllButton()}</ControlRow>
-        )}
         {this.renderContents()}
       </StyledIntegrationList>
     );
@@ -200,12 +197,11 @@ const Flex = styled.div`
 `;
 
 const MainRow = styled.div`
-  height: 70px;
   width: 100%;
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 25px;
+  padding: 15px;
   border-radius: 5px;
   :hover {
     background: ${(props: { disabled: boolean }) =>
@@ -233,12 +229,15 @@ const Integration = styled.div`
   margin-left: -2px;
   display: flex;
   flex-direction: column;
-  background: #26282f;
   cursor: ${(props: { disabled: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
-  margin-bottom: 15px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
+  margin-bottom: 20px;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
+  }
 `;
 
 const Label = styled.div`
@@ -249,7 +248,7 @@ const Label = styled.div`
 
 const Icon = styled.img`
   width: 30px;
-  margin-right: 18px;
+  margin-right: 15px;
 `;
 
 const Placeholder = styled.div`
@@ -267,7 +266,7 @@ const Placeholder = styled.div`
 `;
 
 const StyledIntegrationList = styled.div`
-  margin-top: 20px;
+  margin-top: 30px;
   margin-bottom: 80px;
 `;
 
@@ -292,7 +291,7 @@ const Button = styled.div`
   font-size: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 8px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   padding: 0px 8px;

+ 10 - 7
dashboard/src/main/home/integrations/IntegrationRow.tsx

@@ -129,12 +129,15 @@ const Integration = styled.div`
   margin-left: -2px;
   display: flex;
   flex-direction: column;
-  background: #26282f;
   cursor: ${(props: { disabled: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
   margin-bottom: 15px;
-  border-radius: 8px;
-  box-shadow: 0 4px 15px 0px #00000055;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
+  :hover {
+    border: 1px solid #7a7b80;
+  }
 `;
 
 const Icon = styled.img`
@@ -148,11 +151,11 @@ const MainRow = styled.div`
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 25px;
+  padding: 15px;
+  padding-left: 20px;
+  padding-right: 30px;
   border-radius: 5px;
   :hover {
-    background: ${(props: { disabled: boolean }) =>
-      props.disabled ? "" : "#ffffff11"};
     > i {
       background: ${(props: { disabled: boolean }) =>
         props.disabled ? "" : "#ffffff11"};
@@ -178,9 +181,9 @@ const MaterialIconTray = styled.div`
   align-items: center;
   justify-content: space-between;
   > i {
-    background: #26282f;
     border-radius: 20px;
     font-size: 18px;
+    border: 1px solid #494b4f;
     padding: 5px;
     margin: 0 5px;
     color: #ffffff44;

+ 1 - 6
dashboard/src/main/home/integrations/Integrations.tsx

@@ -126,12 +126,7 @@ const Flex = styled.div`
   }
 `;
 
-const TitleSectionAlt = styled(TitleSection)`
-  margin-left: -42px;
-  width: calc(100% + 42px);
-`;
-
 const StyledIntegrations = styled.div`
-  width: calc(85%);
+  width: 100%;
   min-width: 300px;
 `;

+ 3 - 3
dashboard/src/main/home/launch/Launch.tsx

@@ -19,8 +19,8 @@ import TemplateList from "./TemplateList";
 import { capitalize } from "lodash";
 
 const initialTabOptions = [
-  { label: "New Application", value: "porter" },
-  { label: "Community Add-ons", value: "community" },
+  { label: "New application", value: "porter" },
+  { label: "Community add-ons", value: "community" },
 ];
 
 type TabOption = {
@@ -426,7 +426,7 @@ const Polymer = styled.div`
 `;
 
 const TemplatesWrapper = styled.div`
-  width: calc(85%);
+  width: 100%;
   overflow: visible;
   min-width: 300px;
 `;

+ 4 - 5
dashboard/src/main/home/launch/TemplateList.tsx

@@ -193,10 +193,8 @@ const TemplateTitle = styled.div`
 `;
 
 const TemplateBlock = styled.div`
-  border: 1px solid #ffffff00;
   align-items: center;
   user-select: none;
-  border-radius: 8px;
   display: flex;
   font-size: 13px;
   font-weight: 500;
@@ -208,10 +206,11 @@ const TemplateBlock = styled.div`
   cursor: pointer;
   color: #ffffff;
   position: relative;
-  background: #26282f;
-  box-shadow: 0 4px 15px 0px #00000044;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    background: #ffffff11;
+    border: 1px solid #7a7b80;
   }
 
   animation: fadeIn 0.3s 0s;

+ 2 - 2
dashboard/src/main/home/launch/expanded-template/TemplateInfo.tsx

@@ -216,8 +216,8 @@ const Banner = styled.div`
 
 const LineBreak = styled.div`
   width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
+  height: 1px;
+  background: #494b4f;
   margin: 30px 0px 13px;
 `;
 

+ 2 - 3
dashboard/src/main/home/launch/launch-flow/LaunchFlow.tsx

@@ -363,7 +363,6 @@ const LaunchFlow: React.FC<PropsType> = (props) => {
 
   const renderCurrentPage = () => {
     let { form, currentTab } = props;
-
     if (currentPage === "source" && form?.hasSource) {
       return (
         <SourcePage
@@ -498,8 +497,8 @@ const Polymer = styled.div`
 `;
 
 const StyledLaunchFlow = styled.div`
-  width: calc(90% - 130px);
+  width: calc(100% - 150px);
   min-width: 300px;
   margin-top: ${(props: { disableMarginTop: boolean }) =>
-    props.disableMarginTop ? "inherit" : "calc(40vh - 310px)"};
+    props.disableMarginTop ? "inherit" : "calc(40vh - 270px)"};
 `;

+ 9 - 6
dashboard/src/main/home/launch/launch-flow/SourcePage.tsx

@@ -68,7 +68,7 @@ class SourcePage extends Component<PropsType, StateType> {
           {capabilities.github || capabilities.gitlab ? (
             <Block onClick={() => setSourceType("repo")}>
               <BlockIcon src="https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png" />
-              <BlockTitle>Git Repository</BlockTitle>
+              <BlockTitle>Git repository</BlockTitle>
               <BlockDescription>
                 Deploy using source from a Git repo.
               </BlockDescription>
@@ -76,7 +76,7 @@ class SourcePage extends Component<PropsType, StateType> {
           ) : null}
           <Block onClick={() => setSourceType("registry")}>
             <BlockIcon src="https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png" />
-            <BlockTitle>Docker Registry</BlockTitle>
+            <BlockTitle>Docker registry</BlockTitle>
             <BlockDescription>
               Deploy a container from an image registry.
             </BlockDescription>
@@ -397,7 +397,6 @@ const BlockTitle = styled.div`
 const Block = styled.div<{ disabled?: boolean }>`
   align-items: center;
   user-select: none;
-  border-radius: 5px;
   display: flex;
   font-size: 13px;
   overflow: hidden;
@@ -410,10 +409,14 @@ const Block = styled.div<{ disabled?: boolean }>`
   cursor: ${(props) => (props.disabled ? "" : "pointer")};
   color: #ffffff;
   position: relative;
-  background: #26282f;
-  box-shadow: 0 3px 5px 0px #00000022;
+
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
+  :hover {
+  }
   :hover {
-    background: ${(props) => (props.disabled ? "" : "#ffffff11")};
+    border: ${(props) => (props.disabled ? "" : "1px solid #7a7b80")};
   }
 
   animation: fadeIn 0.3s 0s;

+ 3 - 65
dashboard/src/main/home/navbar/Navbar.tsx

@@ -43,10 +43,10 @@ class Navbar extends Component<PropsType, StateType> {
               <SettingsIcon>
                 <i className="material-icons">settings</i>
               </SettingsIcon>
-              Account Settings
+              Account settings
             </UserDropdownButton>
             <UserDropdownButton onClick={this.props.logOut}>
-              <i className="material-icons">keyboard_return</i> Log Out
+              <i className="material-icons">keyboard_return</i> Log out
               {version !== "production" && <VersionTag>{version}</VersionTag>}
             </UserDropdownButton>
           </Dropdown>
@@ -110,13 +110,6 @@ const I = styled.i`
   margin-right: 7px;
 `;
 
-const PolicySelector = styled(Select)`
-  height: 30px;
-  width: 100px;
-  margin-right: 15px;
-  color: white !important;
-`;
-
 const CloseOverlay = styled.div`
   position: fixed;
   width: 100vw;
@@ -217,47 +210,17 @@ const Dropdown = styled.div`
   }
 `;
 
-const DropdownAlt = styled(Dropdown)`
-  animation: fadeIn 0.3s 0.5s;
-  opacity: 0;
-  animation-fill-mode: forwards;
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
 const StyledNavbar = styled.div`
-  width: 100%;
   height: 60px;
   position: absolute;
   top: 0;
-  left: 0;
+  right: 0;
   display: flex;
   align-items: center;
-  padding-right: 5px;
   justify-content: flex-end;
   z-index: 1;
 `;
 
-const HelpIcon = styled.div`
-  > a {
-    > i {
-      font-size: 18px;
-      margin-left: 8px;
-      margin-top: 2px;
-      color: #8590ff;
-      :hover {
-        color: #aaaabb;
-      }
-    }
-  }
-`;
-
 const NavButton = styled.a`
   display: flex;
   position: relative;
@@ -281,28 +244,3 @@ const NavButton = styled.a`
     font-size: 24px;
   }
 `;
-
-const FeedbackButton = styled(NavButton)`
-  color: ${(props: { selected?: boolean }) =>
-    props.selected ? "#ffffff" : "#ffffff88"};
-  font-family: "Work Sans", sans-serif;
-  font-size: 14px;
-  margin-right: 20px;
-  :hover {
-    color: #ffffff;
-    > div {
-      > i {
-        color: #ffffff;
-      }
-    }
-  }
-
-  > div {
-    > i {
-      color: ${(props: { selected?: boolean }) =>
-        props.selected ? "#ffffff" : "#ffffff88"};
-      font-size: 26px;
-      margin-right: 6px;
-    }
-  }
-`;

+ 2 - 2
dashboard/src/main/home/new-project/NewProject.tsx

@@ -117,7 +117,7 @@ export const NewProjectFC = () => {
               <BackButtonImg src={backArrow} />
             </BackButton>
           )}
-          <TitleSection>New Project</TitleSection>
+          <TitleSection>New project</TitleSection>
         </FadeWrapper>
         <FadeWrapper delay="0.7s">
           <Helper>
@@ -147,7 +147,7 @@ export const NewProjectFC = () => {
             />
           </InputWrapper>
           <NewProjectSaveButton
-            text="Create Project"
+            text="Create project"
             disabled={false}
             onClick={createProject}
             status={buttonStatus}

+ 2 - 2
dashboard/src/main/home/onboarding/steps/ConnectRegistry/ConnectRegistry.tsx

@@ -122,9 +122,9 @@ const ConnectRegistry: React.FC<{}> = ({}) => {
           <BackButtonImg src={backArrow} />
         </BackButton>
       )}
-      <TitleSection>Getting Started</TitleSection>
+      <TitleSection>Getting started</TitleSection>
       <Subtitle>
-        Step 2 of 3 - Connect an existing registry (Optional)
+        Step 2 of 3 - Connect an existing registry (optional)
         <DocsHelper
           tooltipText="If you already have an existing image registry, you can connect your existing registry during project creation. If you don't have an image registry or don't know what that means, skip this step. Porter will handle the rest."
           link={

+ 1 - 1
dashboard/src/main/home/onboarding/steps/ConnectSource.tsx

@@ -76,7 +76,7 @@ const ConnectSource: React.FC<{
 
   return (
     <div>
-      <TitleSection>Getting Started</TitleSection>
+      <TitleSection>Getting started</TitleSection>
       <Subtitle>
         Step 1 of 3 - Connect to GitHub
         <DocsHelper

+ 1 - 1
dashboard/src/main/home/onboarding/steps/ProvisionResources/ProvisionResources.tsx

@@ -308,7 +308,7 @@ const ProvisionResources: React.FC<{}> = () => {
           <BackButtonImg src={backArrow} />
         </BackButton>
       )}
-      <TitleSection>Getting Started</TitleSection>
+      <TitleSection>Getting started</TitleSection>
       <Subtitle>
         Step 3 of 3 - Provision resources
         <DocsHelper

+ 1 - 1
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -212,7 +212,7 @@ const Warning = styled.div`
 `;
 
 const StyledProjectSettings = styled.div`
-  width: calc(85%);
+  width: 100%;
   min-width: 300px;
   height: 100vh;
 `;

+ 5 - 5
dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

@@ -352,7 +352,6 @@ const BlockTitle = styled.div`
 const Block = styled.div<{ disabled?: boolean }>`
   align-items: center;
   user-select: none;
-  border-radius: 5px;
   display: flex;
   font-size: 13px;
   overflow: hidden;
@@ -362,15 +361,16 @@ const Block = styled.div<{ disabled?: boolean }>`
   align-items: center;
   justify-content: space-between;
   height: 170px;
+  filter: ${({ disabled }) => (disabled ? "grayscale(1)" : "")};
   cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")};
   color: #ffffff;
   position: relative;
-  background: #26282f;
-  box-shadow: 0 3px 5px 0px #00000022;
+  border-radius: 5px;
+  background: #262a30;
+  border: 1px solid #494b4f;
   :hover {
-    background: ${(props) => (props.disabled ? "" : "#ffffff11")};
+    border: ${(props) => (props.disabled ? "" : "1px solid #7a7b80")};
   }
-  filter: ${({ disabled }) => (disabled ? "grayscale(1)" : "")};
 
   animation: fadeIn 0.3s 0s;
   @keyframes fadeIn {

+ 7 - 5
dashboard/src/main/home/sidebar/ClusterSection.tsx

@@ -8,7 +8,6 @@ import settings from "assets/settings.svg";
 import monojob from "assets/monojob.png";
 import monoweb from "assets/monoweb.png";
 import sliders from "assets/sliders.svg";
-import cluster from "assets/cluster.svg";
 
 import SidebarLink from "./SidebarLink";
 
@@ -35,6 +34,10 @@ export const ClusterSection: React.FC<Props> = ({
     }
   }, [currentCluster]);
 
+  useEffect(() => {
+    setIsExpanded(false);
+  }, [currentProject]);
+
   const renderClusterContent = (cluster: any) => {
     let clusterId = cluster.id;
 
@@ -145,15 +148,14 @@ export const ClusterSection: React.FC<Props> = ({
         onClick={() => setIsExpanded(!isExpanded)}
         active={
           !isExpanded &&
-          cluster.id === currentCluster.id && (
-            window.location.pathname.startsWith("/cluster-dashboard") ||
+          cluster.id === currentCluster.id &&
+          (window.location.pathname.startsWith("/cluster-dashboard") ||
             window.location.pathname.startsWith("/preview-environments") ||
             window.location.pathname.startsWith("/stacks") ||
             window.location.pathname.startsWith("/databases") ||
             window.location.pathname.startsWith("/env-groups") ||
             window.location.pathname.startsWith("/jobs") ||
-            window.location.pathname.startsWith("/applications")
-          )
+            window.location.pathname.startsWith("/applications"))
         }
       >
         <LinkWrapper>

+ 3 - 3
dashboard/src/main/home/sidebar/Sidebar.tsx

@@ -369,7 +369,7 @@ const CollapseButton = styled.div`
 
 const StyledSidebar = styled.section`
   font-family: "Work Sans", sans-serif;
-  width: 235px;
+  width: 240px;
   position: relative;
   padding-top: 20px;
   height: 100vh;
@@ -379,7 +379,7 @@ const StyledSidebar = styled.section`
   animation-fill-mode: forwards;
   @keyframes showSidebar {
     from {
-      margin-left: -235px;
+      margin-left: -240px;
     }
     to {
       margin-left: 0px;
@@ -390,7 +390,7 @@ const StyledSidebar = styled.section`
       margin-left: 0px;
     }
     to {
-      margin-left: -235px;
+      margin-left: -240px;
     }
   }
 `;

+ 1 - 0
dashboard/src/shared/api.tsx

@@ -1304,6 +1304,7 @@ const upgradeChartValues = baseApi<
   {
     values: string;
     version?: string;
+    latest_revision?: number;
   },
   {
     id: number;

+ 3 - 3
dashboard/src/shared/common.tsx

@@ -15,7 +15,7 @@ export const infraNames: any = {
 export const integrationList: any = {
   kubernetes: {
     icon:
-      "https://uxwing.com/wp-content/themes/uxwing/download/10-brands-and-social-media/kubernetes.png",
+      "https://upload.wikimedia.org/wikipedia/labs/thumb/b/ba/Kubernetes-icon-color.svg/2110px-Kubernetes-icon-color.svg.png",
     label: "Kubernetes",
     buttonText: "Add a Cluster",
   },
@@ -33,8 +33,8 @@ export const integrationList: any = {
   registry: {
     icon:
       "https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png",
-    label: "Docker Registry",
-    buttonText: "Add a Registry",
+    label: "Docker registry",
+    buttonText: "Add a registry",
   },
   gke: {
     icon: "https://sysdig.com/wp-content/uploads/2016/08/GKE_color.png",

BIN
porter-0.36.0.tgz