소스 검색

preview env frontend fixes

portersupport 4 년 전
부모
커밋
f976117938

+ 1 - 1
api/server/handlers/environment/list_deployments_by_cluster.go

@@ -139,7 +139,7 @@ func fetchOpenPullRequests(
 
 	var prs []*types.PullRequest
 
-	if resp != nil && resp.StatusCode == 404 {
+	if resp.StatusCode == 404 {
 		return prs, nil
 	}
 

+ 3 - 1
dashboard/src/components/DocsHelper.tsx

@@ -5,7 +5,7 @@ import { ClickAwayListener } from "@material-ui/core";
 
 type Props = {
   tooltipText: string;
-  link: string;
+  link?: string;
   placement?: TooltipPlacement;
   disableMargin?: boolean;
 };
@@ -45,9 +45,11 @@ const DocsHelper: React.FC<Props> = ({
             <Tooltip placement={placement}>
               <StyledContent onClick={handleTooltipOpen}>
                 {tooltipText}
+                {link && (
                 <A target="_blank" href={link}>
                   Documentation {">"}
                 </A>
+                )}
               </StyledContent>
             </Tooltip>
           )}

+ 8 - 1
dashboard/src/components/OptionsDropdown.tsx

@@ -39,6 +39,10 @@ const OptionsButton = styled.button`
     background: #32343a;
     cursor: pointer;
   }
+
+  > i {
+    font-size: 20px;
+  }
 `;
 
 const DropdownMenu = styled.div`
@@ -51,6 +55,8 @@ const DropdownMenu = styled.div`
   background: #26282f;
   box-shadow: 0 8px 20px 0px #00000088;
   color: white;
+  overflow: hidden;
+  border-radius: 5px;
 `;
 
 const DropdownOption = styled.div`
@@ -60,6 +66,7 @@ const DropdownOption = styled.div`
   cursor: pointer;
   padding-left: 10px;
   padding-right: 10px;
+  font-weight: 500;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
@@ -78,7 +85,7 @@ const DropdownOption = styled.div`
   }
 
   > i {
-    margin-right: 5px;
+    margin-right: 7px;
     font-size: 16px;
   }
 `;

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

@@ -824,7 +824,7 @@ const StyledCard = styled.div`
   font-size: 13px;
   animation: ${fadeIn} 0.5s;
 
-  background: #2b2e36;
+  background: #2b2e3699;
   margin-bottom: 15px;
   overflow: hidden;
   border: 1px solid #ffffff0a;

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

@@ -476,7 +476,7 @@ const StartedText = styled.div`
 const StyledJob = styled.div`
   display: flex;
   flex-direction: column;
-  background: #2b2e36;
+  background: #2b2e3699;
   margin-bottom: 20px;
   border-radius: 5px;
   overflow: hidden;

+ 101 - 48
dashboard/src/main/home/cluster-dashboard/preview-environments/ConnectNewRepo.tsx

@@ -12,7 +12,8 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import { useRouting } from "shared/routing";
 import { Environment } from "./types";
-import { PreviewEnvironmentsHeader } from "./components/PreviewEnvironmentsHeader";
+import DashboardHeader from "../DashboardHeader";
+import PullRequestIcon from "assets/pull_request_icon.svg";
 import CheckboxRow from "components/form-components/CheckboxRow";
 
 const ConnectNewRepo: React.FC = () => {
@@ -95,21 +96,20 @@ const ConnectNewRepo: React.FC = () => {
 
   return (
     <>
-      <PreviewEnvironmentsHeader />
-      <LineBreak />
-      <ControlRow>
-        <BackButton to={`/preview-environments`}>
-          <i className="material-icons">close</i>
-        </BackButton>
-        <Title>Enable Preview Environments</Title>
-      </ControlRow>
-
-      <CheckboxRow
-        label="Enable automatic deployments"
-        isRequired
-        checked={enableAutomaticDeployments}
-        toggle={() => setEnableAutomaticDeployments((prev) => !prev)}
+      <DashboardHeader
+        image={PullRequestIcon}
+        title="Preview Environments"
+        description="Create full-stack preview environments for your pull requests."
       />
+
+      <HeaderSection>
+        <Button to={`/preview-environments`}>
+          <i className="material-icons">keyboard_backspace</i>
+          Back
+        </Button>
+        <Title>Enable Preview Environments on a Repository</Title>
+      </HeaderSection>
+
       <Heading>Select a Repository</Heading>
       <br />
       <RepoList
@@ -125,11 +125,27 @@ const ConnectNewRepo: React.FC = () => {
         Note: you will need to add a <CodeBlock>porter.yaml</CodeBlock> file to
         create a preview environment.
         <DocsHelper
+          disableMargin
           tooltipText="A Porter YAML file is a declarative set of resources that Porter uses to build and update your preview environment deployments."
           link="https://docs.porter.run/preview-environments/porter-yaml-reference"
         />
       </HelperContainer>
 
+      <FlexWrap>
+        <CheckboxRow
+          label="Enable automatic deployments"
+          checked={enableAutomaticDeployments}
+          toggle={() => setEnableAutomaticDeployments((prev) => !prev)}
+        />
+        <Div>
+          <DocsHelper
+            disableMargin
+            tooltipText="Automatically create a Preview Environment for each new pull request in the repository. By default, preview environments must be manually created per-PR."
+            placement="top-start"
+          />
+        </Div>
+      </FlexWrap>
+
       <ActionContainer>
         <SaveButton
           text="Add Repository"
@@ -147,55 +163,59 @@ const ConnectNewRepo: React.FC = () => {
 
 export default ConnectNewRepo;
 
-const LineBreak = styled.div`
-  width: calc(100% - 0px);
-  height: 2px;
-  background: #ffffff20;
-  margin: 10px 0px 35px;
+const Div = styled.div`
+  margin-bottom: -7px;
 `;
 
-const ControlRow = styled.div`
+const FlexWrap = styled.div`
   display: flex;
-  margin-left: auto;
   align-items: center;
-  margin-bottom: 35px;
-  padding-left: 0px;
 `;
 
-const BackButton = styled(DynamicLink)`
+const Button = styled(DynamicLink)`
   display: flex;
-  width: 37px;
-  z-index: 1;
-  cursor: pointer;
-  height: 37px;
+  flex-direction: row;
   align-items: center;
-  justify-content: center;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  background: #ffffff11;
+  justify-content: space-between;
+  font-size: 13px;
+  cursor: pointer;
+  font-family: "Work Sans", sans-serif;
+  border-radius: 20px;
   color: white;
-  > i {
-    font-size: 20px;
-  }
-
+  height: 35px;
+  margin-left: -2px;
+  padding: 0px 8px;
+  padding-bottom: 1px;
+  font-weight: 500;
+  padding-right: 15px;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  cursor: pointer;
+  border: 2px solid #969fbbaa;
   :hover {
-    background: #ffffff22;
-    > img {
-      opacity: 1;
-    }
+    background: #ffffff11;
   }
-`;
 
-const Title = styled(TitleSection)`
-  margin-left: 10px;
-  margin-bottom: 0;
-  font-size: 18px;
+  > i {
+    color: white;
+    width: 18px;
+    height: 18px;
+    color: #969fbbaa;
+    font-weight: 600;
+    font-size: 14px;
+    border-radius: 20px;
+    display: flex;
+    align-items: center;
+    margin-right: 5px;
+    justify-content: center;
+  }
 `;
 
 const ActionContainer = styled.div`
   display: flex;
   justify-content: flex-end;
-  margin-top: 50px;
+  margin-top: 20px;
 `;
 
 const CodeBlock = styled.span`
@@ -211,7 +231,7 @@ const CodeBlock = styled.span`
 
 const HelperContainer = styled.div`
   margin-top: 24px;
-  width: 600px;
+  width: 555px;
   display: flex;
   justify-content: start;
   align-items: center;
@@ -219,3 +239,36 @@ const HelperContainer = styled.div`
   line-height: 1.6em;
   font-size: 13px;
 `;
+
+const Title = styled.div`
+  font-size: 20px;
+  font-weight: 500;
+  font-family: "Work Sans", sans-serif;
+  margin-left: 15px;
+  border-radius: 2px;
+  color: #ffffff;
+`;
+
+const HeaderSection = styled.div`
+  display: flex;
+  align-items: center;
+  margin-bottom: 40px;
+
+  > i {
+    cursor: pointer;
+    font-size 20px;
+    color: #969Fbbaa;
+    padding: 2px;
+    border: 2px solid #969fbbaa;
+    border-radius: 100px;
+    :hover {
+      background: #ffffff11;
+    }
+  }
+
+  > img {
+    width: 20px;
+    margin-left: 17px;
+    margin-right: 7px;
+  }
+`;

+ 49 - 65
dashboard/src/main/home/cluster-dashboard/preview-environments/PreviewEnvironmentsHome.tsx

@@ -1,5 +1,4 @@
 import Loading from "components/Loading";
-import TabSelector from "components/TabSelector";
 import React, { useContext, useEffect, useState } from "react";
 import { useHistory, useLocation } from "react-router";
 import api from "shared/api";
@@ -7,7 +6,8 @@ import { Context } from "shared/Context";
 import { useRouting } from "shared/routing";
 import styled from "styled-components";
 import ButtonEnablePREnvironments from "./components/ButtonEnablePREnvironments";
-import { PreviewEnvironmentsHeader } from "./components/PreviewEnvironmentsHeader";
+import DashboardHeader from "../DashboardHeader";
+import PullRequestIcon from "assets/pull_request_icon.svg";
 import DeploymentList from "./deployments/DeploymentList";
 import EnvironmentsList from "./environments/EnvironmentsList";
 import { environments } from "./mocks";
@@ -24,8 +24,8 @@ const PreviewEnvironmentsHome = () => {
   const [isLoading, setIsLoading] = useState(true);
   const [hasError, setHasError] = useState(false);
   const [environments, setEnvironments] = useState([]);
+  const [selectedRepo, setSelectedRepo] = useState("");
 
-  const [currentTab, setCurrentTab] = useState<TabEnum>("repositories");
   const { getQueryParam, pushQueryParams } = useRouting();
   const location = useLocation();
   const history = useHistory();
@@ -103,35 +103,25 @@ const PreviewEnvironmentsHome = () => {
   }, [currentCluster, currentProject]);
 
   useEffect(() => {
-    const current_tab = getQueryParam("current_tab");
+    const current_repo = getQueryParam("repository");
+    setSelectedRepo(current_repo);
+  }, [location.search, history]);
 
-    if (!AvailableTabs.includes(current_tab)) {
-      pushQueryParams({}, ["current_tab"]);
-      return;
+  const renderMain = () => {
+    if (isLoading) {
+      return (
+        <Placeholder>
+          <Loading />
+        </Placeholder>
+      );
     }
-
-    if (current_tab !== currentTab) {
-      setCurrentTab(current_tab);
+  
+    if (hasError) {
+      return <Placeholder>Something went wrong, please try again</Placeholder>;
     }
-  }, [location.search, history]);
-
-  if (isLoading) {
-    return (
-      <Placeholder>
-        <Loading />
-      </Placeholder>
-    );
-  }
-
-  if (hasError) {
-    return <Placeholder>Something went wrong, please try again</Placeholder>;
-  }
-
-  if (!hasGHAccountsLinked) {
-    return (
-      <>
-        <PreviewEnvironmentsHeader />
-        <LineBreak />
+  
+    if (!hasGHAccountsLinked) {
+      return (
         <Placeholder>
           <Title>There are no repositories linked</Title>
           <Subtitle>
@@ -140,15 +130,11 @@ const PreviewEnvironmentsHome = () => {
           </Subtitle>
           <ButtonEnablePREnvironments />
         </Placeholder>
-      </>
-    );
-  }
-
-  if (!hasEnvironments) {
-    return (
-      <>
-        <PreviewEnvironmentsHeader />
-        <LineBreak />
+      );
+    }
+  
+    if (!hasEnvironments) {
+      return (
         <Placeholder>
           <Title>Preview environments are not enabled on this cluster</Title>
           <Subtitle>
@@ -157,43 +143,41 @@ const PreviewEnvironmentsHome = () => {
           </Subtitle>
           <ButtonEnablePREnvironments />
         </Placeholder>
-      </>
+      );
+    }
+
+    if (!selectedRepo) {
+      return (
+        <EnvironmentsList
+          environments={environments}
+          setEnvironments={setEnvironments}
+        />
+      );
+    }
+
+    return (
+      <DeploymentList
+        // selectedRepo={selectedRepo}
+        environments={environments}
+      />
     );
   }
 
-  const handleSetTab = (tab: TabEnum) => {
-    pushQueryParams({ current_tab: tab });
-    setCurrentTab(tab);
-  };
-
   return (
     <>
-      <PreviewEnvironmentsHeader />
-      <TabSelector
-        options={[
-          {
-            label: "Linked Repositories",
-            value: "repositories",
-            component: (
-              <EnvironmentsList
-                environments={environments}
-                setEnvironments={setEnvironments}
-              />
-            ),
-          },
-          {
-            label: "Pull requests",
-            value: "pull_requests",
-            component: <DeploymentList environments={environments} />,
-          },
-        ]}
-        currentTab={currentTab}
-        setCurrentTab={handleSetTab}
+      <DashboardHeader
+        image={PullRequestIcon}
+        title="Preview Environments"
+        description="Create full-stack preview environments for your pull requests."
       />
+      {renderMain()}
     </>
   );
 };
 
+/*
+<DeploymentList environments={environments} />
+*/
 export default PreviewEnvironmentsHome;
 
 const mockRequest = () =>

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

@@ -87,29 +87,33 @@ const DeploymentCard: React.FC<{
       <DataContainer>
         <PRName>
           <PRIcon src={pr_icon} alt="pull request icon" />
-          <DynamicLink
-            to={`https://github.com/${deployment.gh_repo_owner}/${deployment.gh_repo_name}/pull/${deployment.pull_request_id}`}
-            target="_blank"
-          >
-            {deployment.gh_pr_name} #{deployment.pull_request_id}
-          </DynamicLink>
+          {deployment.gh_pr_name}
           {deployment.gh_pr_branch_from && deployment.gh_pr_branch_into ? (
             <MergeInfoWrapper>
               <MergeInfo
                 onMouseOver={() => setShowMergeInfoTooltip(true)}
                 onMouseOut={() => setShowMergeInfoTooltip(false)}
               >
-                From: {deployment.gh_pr_branch_from} Into:{" "}
+                {deployment.gh_pr_branch_from}
+                <i className="material-icons">arrow_forward</i>
                 {deployment.gh_pr_branch_into}
               </MergeInfo>
               {showMergeInfoTooltip && (
                 <Tooltip>
-                  From: {deployment.gh_pr_branch_from} Into:{" "}
-                  {deployment.gh_pr_branch_into}
+                  {deployment.gh_pr_branch_from} {"->"} {deployment.gh_pr_branch_into}
                 </Tooltip>
               )}
             </MergeInfoWrapper>
           ) : null}
+          <RepoLink
+            onClick={e => {
+              e.stopPropagation();
+              window.open(`https://github.com/${deployment.gh_repo_owner}/${deployment.gh_repo_name}/pull/${deployment.pull_request_id}`, "_blank")
+            }}
+          >
+            <i className="material-icons">open_in_new</i>
+            View PR
+          </RepoLink>
         </PRName>
 
         <Flex>
@@ -120,19 +124,8 @@ const DeploymentCard: React.FC<{
             </Status>
           </StatusContainer>
           <DeploymentImageContainer>
-            <DeploymentTypeIcon src={integrationList.repo.icon} />
-            <RepositoryName
-              onMouseOver={() => {
-                setShowRepoTooltip(true);
-              }}
-              onMouseOut={() => {
-                setShowRepoTooltip(false);
-              }}
-            >
-              {repository}
-            </RepositoryName>
-            {showRepoTooltip && <Tooltip>{repository}</Tooltip>}
             <InfoWrapper>
+              <SepDot>•</SepDot>
               <LastDeployed>
                 Last updated {readableDate(deployment.updated_at)}
               </LastDeployed>
@@ -210,6 +203,34 @@ const DeploymentCard: React.FC<{
 
 export default DeploymentCard;
 
+const RepoLink = styled.div`
+  height: 22px;
+  border-radius: 50px;
+  margin-left: 4px;
+  display: flex;
+  font-size: 12px;
+  cursor: pointer;
+  color: #a7a6bb;
+  align-items: center;
+  justify-content: center;
+  :hover {
+    color: #ffffff;
+    > i {
+      color: #ffffff;
+    }
+  }
+
+  > i {
+    margin-right: 5px;
+    color: #a7a6bb;
+    font-size: 16px;
+  }
+`;
+
+const SepDot = styled.div`
+  color: #aaaabb66;
+`;
+
 const DeleteMessage = styled.div`
   display: flex;
   align-items: flex-end;
@@ -260,22 +281,22 @@ const PRName = styled.div`
   font-weight: 500;
   color: #ffffff;
   display: flex;
+  font-size: 14px;
   align-items: center;
   margin-bottom: 10px;
 `;
 
 const DeploymentCardWrapper = styled.div`
   display: flex;
-  align-items: center;
+  background: #2b2e3699;
   justify-content: space-between;
-  border: 1px solid #ffffff44;
-  background: #ffffff08;
-  margin-bottom: 5px;
-  border-radius: 10px;
-  padding: 14px;
-  overflow: hidden;
-  height: 80px;
+  border-radius: 5px;
   font-size: 13px;
+  height: 75px;
+  padding: 12px;
+  padding-left: 14px;
+  border: 1px solid #ffffff0f;
+
   animation: fadeIn 0.5s;
   @keyframes fadeIn {
     from {
@@ -358,12 +379,11 @@ const DeploymentImageContainer = styled.div`
   font-size: 13px;
   position: relative;
   display: flex;
-  margin-left: 15px;
   align-items: center;
   font-weight: 400;
   justify-content: center;
   color: #ffffff66;
-  padding-left: 5px;
+  padding-left: 10px;
 `;
 
 const Icon = styled.img`
@@ -421,8 +441,8 @@ const InfoWrapper = styled.div`
 
 const LastDeployed = styled.div`
   font-size: 13px;
-  margin-left: 14px;
   margin-top: -1px;
+  margin-left: 10px;
   display: flex;
   align-items: center;
   color: #aaaabb66;
@@ -438,11 +458,17 @@ const MergeInfoWrapper = styled.div`
 const MergeInfo = styled.div`
   font-size: 13px;
   margin-left: 14px;
-  margin-top: -1px;
   align-items: center;
   color: #aaaabb66;
   white-space: nowrap;
+  display: flex;
+  align-items: center;
   text-overflow: ellipsis;
   overflow: hidden;
   max-width: 300px;
+
+  > i {
+    font-size: 16px;
+    margin: 0 2px;
+  }
 `;

+ 119 - 107
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentList.tsx

@@ -35,7 +35,7 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
     statusSelectorVal,
     setStatusSelectorVal,
   ] = useState<AvailableStatusFiltersType>("all");
-  const [selectedRepo, setSelectedRepo] = useState("all");
+  const [selectedRepo, setSelectedRepo] = useState("");
 
   const { currentProject, currentCluster } = useContext(Context);
   const { getQueryParam, pushQueryParams } = useRouting();
@@ -58,15 +58,11 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
     const selected_repo = getQueryParam("repository");
 
     const repo = environments.find(
-      (env) => `${env.git_repo_owner}/${env.git_repo_name}` === selected_repo
+      env => `${env.git_repo_owner}/${env.git_repo_name}` === selected_repo
     );
 
-    if (!repo) {
-      pushQueryParams({}, ["repository"]);
-      return;
-    }
-
-    if (selected_repo !== selectedRepo) {
+    if (repo && true) {
+      console.log("tested", repo);
       setSelectedRepo(`${repo.git_repo_owner}/${repo.git_repo_name}`);
     }
   }, [location.search, history]);
@@ -85,7 +81,7 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
   }, [location.search, history]);
 
   useEffect(() => {
-    pushQueryParams({}, ["status_filter", "repository"]);
+    pushQueryParams({}, ["status_filter"]);
   }, []);
 
   useEffect(() => {
@@ -182,10 +178,6 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
     });
   }, [selectedRepo, pullRequests]);
 
-  if (hasError) {
-    return <Placeholder>Error</Placeholder>;
-  }
-
   const renderDeploymentList = () => {
     if (isLoading) {
       return (
@@ -214,15 +206,6 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
 
     return (
       <>
-        {filteredPullRequests.map((pr) => {
-          return (
-            <PullRequestCard
-              key={pr.pr_title}
-              pullRequest={pr}
-              onCreation={handlePreviewEnvironmentManualCreation}
-            />
-          );
-        })}
         {filteredDeployments.map((d) => {
           return (
             <DeploymentCard
@@ -233,99 +216,98 @@ const DeploymentList = ({ environments }: { environments: Environment[] }) => {
             />
           );
         })}
+        {filteredPullRequests.map((pr) => {
+          return (
+            <PullRequestCard
+              key={pr.pr_title}
+              pullRequest={pr}
+              onCreation={handlePreviewEnvironmentManualCreation}
+            />
+          );
+        })}
       </>
     );
   };
 
-  const repoOptions = environments.map((env) => ({
-    label: `${env.git_repo_owner}/${env.git_repo_name}`,
-    value: `${env.git_repo_owner}/${env.git_repo_name}`,
-  }));
-
   const handleStatusFilterChange = (value: string) => {
     pushQueryParams({ status_filter: value });
     setStatusSelectorVal(value);
   };
 
-  const handleRepoFilterChange = (value: string) => {
-    pushQueryParams({ repository: value });
-    setSelectedRepo(value);
-  };
+  const renderMain = () => {
+    return (
+      <Container>
+        <ControlRow>
+          <ActionsWrapper>
+            <StyledStatusSelector>
+              <Label>
+                <i className="material-icons">filter_alt</i>
+                Status
+              </Label>
+              <Selector
+                activeValue={statusSelectorVal}
+                setActiveValue={handleStatusFilterChange}
+                options={[
+                  {
+                    value: "all",
+                    label: "All",
+                  },
+                  {
+                    value: "creating",
+                    label: "Creating",
+                  },
+                  {
+                    value: "failed",
+                    label: "Failed",
+                  },
+                  {
+                    value: "created",
+                    label: "Created",
+                  },
+                  {
+                    value: "inactive",
+                    label: "Inactive",
+                  },
+                  {
+                    value: "not_deployed",
+                    label: "Not deployed",
+                  },
+                ]}
+                dropdownLabel="Status"
+                width="150px"
+                dropdownWidth="230px"
+                closeOverlay={true}
+              />
+            </StyledStatusSelector>
+
+            <RefreshButton color={"#7d7d81"} onClick={handleRefresh}>
+              <i className="material-icons">refresh</i>
+            </RefreshButton>
+          </ActionsWrapper>
+        </ControlRow>
+        <EventsGrid>{renderDeploymentList()}</EventsGrid>
+      </Container>
+    );
+  }
 
   return (
-    <Container>
-      <ControlRow>
-        <ActionsWrapper>
-          <StyledStatusSelector>
-            <Label>
-              <i className="material-icons">filter_alt</i>
-              Status
-            </Label>
-            <Selector
-              activeValue={statusSelectorVal}
-              setActiveValue={handleStatusFilterChange}
-              options={[
-                {
-                  value: "all",
-                  label: "All",
-                },
-                {
-                  value: "creating",
-                  label: "Creating",
-                },
-                {
-                  value: "failed",
-                  label: "Failed",
-                },
-                {
-                  value: "created",
-                  label: "Created",
-                },
-                {
-                  value: "inactive",
-                  label: "Inactive",
-                },
-                {
-                  value: "not_deployed",
-                  label: "Not deployed",
-                },
-              ]}
-              dropdownLabel="Status"
-              width="150px"
-              dropdownWidth="230px"
-              closeOverlay={true}
-            />
-          </StyledStatusSelector>
-          <StyledStatusSelector>
-            <Label>
-              <i className="material-icons">filter_alt</i>
-              Repository
-            </Label>
-            <Selector
-              activeValue={selectedRepo}
-              setActiveValue={handleRepoFilterChange}
-              options={[
-                {
-                  label: "All",
-                  value: "all",
-                },
-                ...repoOptions,
-              ]}
-              dropdownLabel="Repository"
-              width="200px"
-              dropdownWidth="300px"
-              closeOverlay
-            />
-          </StyledStatusSelector>
-
-          <RefreshButton color={"#7d7d81"} onClick={handleRefresh}>
-            <i className="material-icons">refresh</i>
-          </RefreshButton>
-        </ActionsWrapper>
-      </ControlRow>
-      <EventsGrid>{renderDeploymentList()}</EventsGrid>
-    </Container>
-  );
+    <>
+      <Flex>
+        <i
+          className="material-icons"
+          onClick={() => pushQueryParams({}, ["status_filter", "repository"])}
+        >
+          keyboard_backspace
+        </i>
+        <Icon
+          src="https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png"
+          alt="git repository icon"
+        />
+        <Title>{selectedRepo}</Title>
+      </Flex>
+      {renderMain()}
+    </>
+  )
 };
 
 export default DeploymentList;
@@ -341,6 +323,38 @@ const mockRequest = () =>
     );
   });
 
+const Flex = styled.div`
+  display: flex;
+  align-items: center;
+
+  > i {
+    cursor: pointer;
+    font-size 24px;
+    color: #969Fbbaa;
+    padding: 3px;
+    border-radius: 100px;
+    :hover {
+      background: #ffffff11;
+    }
+  }
+`;
+
+const Icon = styled.img`
+  width: 25px;
+  height: 25px;
+  margin-right: 6px;
+  margin-left: 14px;
+`;
+
+const Title = styled.div`
+  font-size: 20px;
+  font-weight: 500;
+  font-family: "Work Sans", sans-serif;
+  margin-left: 10px;
+  border-radius: 2px;
+  color: #ffffff;
+`;
+
 const ActionsWrapper = styled.div`
   display: flex;
 `;
@@ -366,13 +380,11 @@ const RefreshButton = styled.button`
 
 const Placeholder = styled.div`
   padding: 30px;
-  margin-top: 35px;
   padding-bottom: 40px;
   font-size: 13px;
   color: #ffffff44;
   min-height: 400px;
-  height: 50vh;
-  background: #ffffff11;
+  height: 40vh;
   border-radius: 8px;
   width: 100%;
   display: flex;

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

@@ -62,19 +62,15 @@ const PullRequestCard = ({
         <DataContainer>
           <PRName>
             <PRIcon src={pr_icon} alt="pull request icon" />
-            <DynamicLink
-              to={`https://github.com/${pullRequest.repo_owner}/${pullRequest.repo_name}/pull/${pullRequest.pr_number}`}
-              target="_blank"
-            >
-              {pullRequest.pr_title}
-            </DynamicLink>
-
+            {pullRequest.pr_title}
             <InfoWrapper>
               <MergeInfo
                 onMouseOver={() => setShowMergeInfoTooltip(true)}
                 onMouseOut={() => setShowMergeInfoTooltip(false)}
               >
-                From: {pullRequest.branch_from} Into: {pullRequest.branch_into}
+                {pullRequest.branch_from}
+                <i className="material-icons">arrow_forward</i>
+                {pullRequest.branch_into}
               </MergeInfo>
               {showMergeInfoTooltip && (
                 <Tooltip>
@@ -83,6 +79,15 @@ const PullRequestCard = ({
                 </Tooltip>
               )}
             </InfoWrapper>
+            <RepoLink
+              onClick={e => {
+                e.stopPropagation();
+                window.open(`https://github.com/${pullRequest.repo_owner}/${pullRequest.repo_name}/pull/${pullRequest.pr_number}`, "_blank")
+              }}
+            >
+              <i className="material-icons">open_in_new</i>
+              View PR
+            </RepoLink>
           </PRName>
 
           <Flex>
@@ -92,20 +97,6 @@ const PullRequestCard = ({
                 Not deployed
               </Status>
             </StatusContainer>
-            <DeploymentImageContainer>
-              <DeploymentTypeIcon src={integrationList.repo.icon} />
-              <RepositoryName
-                onMouseOver={() => {
-                  setShowRepoTooltip(true);
-                }}
-                onMouseOut={() => {
-                  setShowRepoTooltip(false);
-                }}
-              >
-                {repository}
-              </RepositoryName>
-              {showRepoTooltip && <Tooltip>{repository}</Tooltip>}
-            </DeploymentImageContainer>
           </Flex>
         </DataContainer>
         <Flex>
@@ -131,6 +122,30 @@ const PullRequestCard = ({
 
 export default PullRequestCard;
 
+const RepoLink = styled.div`
+  height: 22px;
+  border-radius: 50px;
+  margin-left: 4px;
+  display: flex;
+  font-size: 12px;
+  cursor: pointer;
+  color: #a7a6bb;
+  align-items: center;
+  justify-content: center;
+  :hover {
+    color: #ffffff;
+    > i {
+      color: #ffffff;
+    }
+  }
+
+  > i {
+    margin-right: 5px;
+    color: #a7a6bb;
+    font-size: 16px;
+  }
+`;
+
 const Flex = styled.div`
   display: flex;
   align-items: center;
@@ -147,15 +162,15 @@ const PRName = styled.div`
 
 const DeploymentCardWrapper = styled.div`
   display: flex;
-  align-items: center;
+  background: #2b2e3699;
   justify-content: space-between;
-  border: 1px solid #ffffff44;
-  background: #ffffff08;
-  margin-bottom: 5px;
-  border-radius: 10px;
-  padding: 14px;
-  height: 80px;
+  border-radius: 5px;
   font-size: 13px;
+  height: 75px;
+  padding: 12px;
+  padding-left: 14px;
+  border: 1px solid #ffffff0f;
+
   animation: fadeIn 0.5s;
   @keyframes fadeIn {
     from {
@@ -272,11 +287,17 @@ const InfoWrapper = styled.div`
 const MergeInfo = styled.div`
   font-size: 13px;
   margin-left: 14px;
-  margin-top: -1px;
   align-items: center;
   color: #aaaabb66;
   white-space: nowrap;
+  display: flex;
+  align-items: center;
   text-overflow: ellipsis;
   overflow: hidden;
   max-width: 300px;
-`;
+
+  > i {
+    font-size: 16px;
+    margin: 0 2px;
+  }
+`;

+ 88 - 46
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentCard.tsx

@@ -43,7 +43,6 @@ const EnvironmentCard = ({ environment, onDelete }: Props) => {
 
   const showOpenPrs = () => {
     pushFiltered("/preview-environments", [], {
-      current_tab: "pull_requests",
       repository: `${git_repo_owner}/${git_repo_name}`,
     });
   };
@@ -89,25 +88,23 @@ const EnvironmentCard = ({ environment, onDelete }: Props) => {
     <>
       {showDeleteModal ? (
         <Modal
-          title={`Are you sure you wanna remove preview environments for ${git_repo_owner}/${git_repo_name}`}
+          title={`Remove Preview Envs for ${git_repo_owner}/${git_repo_name}`}
           width="800px"
           height="260px"
           onRequestClose={closeForm}
         >
           <Warning highlight>
-            ⚠️ Removing this repository from preview environments will delete
-            all the deployments associated. Meaning you will not be able to
-            access those preview environments no more.
+            ⚠️ All Preview Environment deployments associated with this repo will be deleted.
           </Warning>
           <InputRow
             type="text"
-            label="Please write down the repo name before proceeding"
+            label="Enter the full name of the repository to delete Preview Environments:"
             value={deleteConfirmationRepoName}
+            placeholder={`${git_repo_owner}/${git_repo_name}`}
             setValue={(x: string) => setDeleteConfirmationRepoName(x)}
-            width={"300px"}
+            width={"500px"}
           />
           <ActionWrapper>
-            <CancelButton onClick={closeForm}>Cancel</CancelButton>
             <DeleteButton
               onClick={() => handleDelete()}
               disabled={!canDelete()}
@@ -117,46 +114,51 @@ const EnvironmentCard = ({ environment, onDelete }: Props) => {
           </ActionWrapper>
         </Modal>
       ) : null}
-      <EnvironmentCardWrapper>
+      <EnvironmentCardWrapper onClick={showOpenPrs}>
         <DataContainer>
           <RepoName>
             <Icon
               src="https://git-scm.com/images/logos/downloads/Git-Icon-1788C.png"
               alt="git repository icon"
             />
-            <DynamicLink
-              to={`https://github.com/${git_repo_owner}/${git_repo_name}`}
-              target="_blank"
+            {git_repo_owner}/{git_repo_name}
+            <RepoLink
+              onClick={e => {
+                e.stopPropagation();
+                window.open(`https://github.com/${git_repo_owner}/${git_repo_name}`, "_blank")
+              }}
             >
-              {git_repo_owner}/{git_repo_name}
-            </DynamicLink>
+              <i className="material-icons">open_in_new</i>
+              View Repo
+            </RepoLink>
           </RepoName>
           <Status>
-            {deployment_count > 0 ? (
-              <span>
-                Pull {deployment_count > 1 ? "requests" : "request"} deployed:{" "}
-                {deployment_count || 0}
-              </span>
-            ) : (
-              <span>
-                There is no pull request deployed for this environment
-              </span>
-            )}
             {deployment_count > 0 ? (
               <>
-                <Dot>•</Dot>
                 <StatusDot status={last_deployment_status} />
-                Last PR status was {capitalize(last_deployment_status || "")}
+                Last PR status was "{capitalize(last_deployment_status || "")}"
+                <Dot>•</Dot>
               </>
             ) : null}
+            {deployment_count > 0 ? (
+              <Span>
+                {deployment_count || 0}{" "}
+                pull {deployment_count > 1 ? "requests" : "request"} deployed
+              </Span>
+            ) : (
+              <Span>
+                There is no pull request deployed for this environment
+              </Span>
+            )}
           </Status>
         </DataContainer>
-        <Options.Dropdown expandIcon="more_vert" shrinkIcon="more_vert">
-          <Options.Option onClick={showOpenPrs}>View opened PRs</Options.Option>
-          <Options.Option onClick={() => setShowDeleteModal(true)}>
-            Delete
-          </Options.Option>
-        </Options.Dropdown>
+        <OptionWrapper>
+          <Options.Dropdown expandIcon="more_vert" shrinkIcon="more_vert">
+            <Options.Option onClick={() => setShowDeleteModal(true)}>
+              <i className="material-icons">delete</i> Delete
+            </Options.Option>
+          </Options.Dropdown>
+        </OptionWrapper>
       </EnvironmentCardWrapper>
     </>
   );
@@ -164,16 +166,53 @@ const EnvironmentCard = ({ environment, onDelete }: Props) => {
 
 export default EnvironmentCard;
 
-const EnvironmentCardWrapper = styled.div`
+const Span = styled.span`
+  color: #aaaabb66;
+`;
+
+const OptionWrapper = styled.div`
   display: flex;
   align-items: center;
+  justify-content: center;
+`;
+
+const RepoLink = styled.div`
+  height: 22px;
+  border-radius: 50px;
+  margin-left: 10px;
+  display: flex;
+  font-size: 12px;
+  color: #a7a6bb;
+  align-items: center;
+  justify-content: center;
+  :hover {
+    color: #ffffff;
+    > i {
+      color: #ffffff;
+    }
+  }
+
+  > i {
+    margin-right: 5px;
+    color: #a7a6bb;
+    font-size: 16px;
+  }
+`;
+
+const EnvironmentCardWrapper = styled.div`
+  display: flex;
+  background: #2b2e3699;
   justify-content: space-between;
-  border: 1px solid #ffffff44;
-  background: #ffffff08;
-  border-radius: 10px;
-  padding: 14px;
-  min-height: 80px;
-  font-size: 13px;
+  border-radius: 5px;
+  cursor: pointer;
+  height: 75px;
+  padding: 12px;
+  padding-left: 14px;
+  border: 1px solid #ffffff0f;
+
+  :hover {
+    border: 1px solid #ffffff3c;
+  }
   animation: fadeIn 0.5s;
   @keyframes fadeIn {
     from {
@@ -192,7 +231,8 @@ const DataContainer = styled.div`
 
 const RepoName = styled.div`
   display: flex;
-  font-size: 16px;
+  font-size: 14px;
+  font-weight: 500;
   align-items: center;
 `;
 
@@ -218,13 +258,13 @@ const StatusDot = styled.div`
       ? "#00d12a"
       : "#f5cb42"};
   border-radius: 20px;
-  margin-left: 3px;
+  margin-left: 4px;
 `;
 
 const Icon = styled.img`
-  width: 20px;
-  height: 20px;
-  margin-right: 5px;
+  width: 18px;
+  height: 18px;
+  margin-right: 12px;
 `;
 
 const Button = styled.button`
@@ -233,9 +273,10 @@ const Button = styled.button`
   align-items: center;
   justify-content: space-between;
   font-size: 13px;
+  margin-top: 13px;
   cursor: pointer;
   font-family: "Work Sans", sans-serif;
-  border-radius: 10px;
+  border-radius: 5px;
   color: white;
   height: 35px;
   padding: 10px 16px;
@@ -287,7 +328,7 @@ const Warning = styled.div`
   display: flex;
   border-radius: 3px;
   width: calc(100%);
-  margin-top: 10px;
+  margin-top: 18px;
   margin-left: 2px;
   line-height: 1.4em;
   align-items: center;
@@ -302,5 +343,6 @@ const Warning = styled.div`
 
 const Dot = styled.div`
   margin-right: 9px;
+  color: #aaaabb66;
   margin-left: 9px;
 `;

+ 7 - 11
dashboard/src/main/home/sidebar/Sidebar.tsx

@@ -7,7 +7,7 @@ import monojob from "assets/monojob.png";
 import monoweb from "assets/monoweb.png";
 import settings from "assets/settings.svg";
 import sliders from "assets/sliders.svg";
-import CodeBranchIcon from "assets/code-branch-icon";
+import PullRequestIcon from "assets/pull_request_icon.svg";
 
 import { Context } from "shared/Context";
 
@@ -179,8 +179,8 @@ class Sidebar extends Component<PropsType, StateType> {
             )}
           {currentProject?.preview_envs_enabled && (
             <NavButton to="/preview-environments">
-              <InlineSVGWrapper>
-                <StyledCodeBranchIcon />
+              <InlineSVGWrapper id="Flat" fill="#FFFFFF" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
+                <path d="M103.99951,68a36,36,0,1,0-44,35.0929v49.8142a36,36,0,1,0,16,0V103.0929A36.05516,36.05516,0,0,0,103.99951,68Zm-56,0a20,20,0,1,1,20,20A20.0226,20.0226,0,0,1,47.99951,68Zm40,120a20,20,0,1,1-20-20A20.0226,20.0226,0,0,1,87.99951,188ZM196.002,152.907l-.00146-33.02563a55.63508,55.63508,0,0,0-16.40137-39.59619L155.31348,56h20.686a8,8,0,0,0,0-16h-40c-.02978,0-.05859.00415-.08838.00446-.2334.00256-.46631.01245-.69824.03527-.12891.01258-.25391.03632-.38086.05494-.13135.01928-.26318.03424-.39355.06-.14014.02778-.27686.06611-.41455.10114-.11475.02924-.23047.05426-.34424.08862-.13428.04059-.26367.0907-.395.13806-.11524.04151-.231.07929-.34473.12629-.12109.05011-.23681.10876-.35449.16455-.11914.05621-.23926.10907-.356.17144-.11133.0597-.21728.12757-.32519.1922-.11621.06928-.23389.13483-.34668.21051-.11719.07831-.227.16553-.33985.24976-.09668.07227-.1958.1394-.28955.21655-.18652.1529-.36426.31531-.53564.48413-.01612.01593-.03418.02918-.05029.04529-.02051.02051-.0376.04321-.05762.06391-.16358.16711-.32178.33941-.47022.52032-.083.10059-.15527.20648-.23193.31006-.07861.10571-.16064.20862-.23438.3183-.08056.12072-.15087.24591-.2246.36993-.05958.1-.12208.19757-.17725.30036-.06787.12591-.125.25531-.18506.384-.05078.1084-.10547.21466-.15137.32568-.05127.12463-.09326.25189-.13867.37848-.04248.11987-.08887.238-.126.36047-.03857.12775-.06738.25757-.09912.38678-.03125.124-.06591.24622-.0913.37244-.02979.15088-.04786.30328-.06934.45544-.01465.10645-.03516.21094-.0459.31867q-.03955.39752-.04.79706V88a8,8,0,0,0,16,0V67.31378l24.28516,24.28485a39.73874,39.73874,0,0,1,11.71582,28.28321l.00146,33.02533a36.00007,36.00007,0,1,0,16-.00019ZM188.00244,208a20,20,0,1,1,20-20A20.0226,20.0226,0,0,1,188.00244,208Z"/>
               </InlineSVGWrapper>
               <EllipsisTextWrapper
                 onMouseOver={() => {
@@ -202,10 +202,7 @@ class Sidebar extends Component<PropsType, StateType> {
                   }));
                 }}
               >
-                Preview environments
-                {this.state.showLinkTooltip["prev_envs"] && (
-                  <Tooltip>Preview environments</Tooltip>
-                )}
+                Preview Envs
               </EllipsisTextWrapper>
             </NavButton>
           )}
@@ -387,18 +384,17 @@ const Img = styled.img<{ enlarge?: boolean }>`
   margin-right: 10px;
 `;
 
-const StyledCodeBranchIcon = styled(CodeBranchIcon)`
+const InlineSVGWrapper = styled.svg`
   width: 32px;
   height: 32px;
   padding: 8px;
+  padding-left: 0;
 
   > path {
-    fill: #ffffff99;
+    fill: #ffffff;
   }
 `;
 
-const InlineSVGWrapper = styled.div``;
-
 const EllipsisTextWrapper = styled.span`
   display: block;
   overflow: hidden;