2
0
Soham Parekh 3 жил өмнө
parent
commit
242f42f1de

+ 63 - 0
dashboard/package-lock.json

@@ -1526,6 +1526,38 @@
       "integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw==",
       "dev": true
     },
+    "@tanstack/match-sorter-utils": {
+      "version": "8.5.14",
+      "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.5.14.tgz",
+      "integrity": "sha512-lVNhzTcOJ2bZ4IU+PeCPQ36vowBHvviJb2ZfdRFX5uhy7G0jM8N34zAMbmS5ZmVH8D2B7oU82OWo0e/5ZFzQrw==",
+      "requires": {
+        "remove-accents": "0.4.2"
+      }
+    },
+    "@tanstack/query-core": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.13.0.tgz",
+      "integrity": "sha512-PzmLQcEgC4rl2OzkiPHYPC9O79DFcMGaKsOzDEP+U4PJ+tbkcEP+Z+FQDlfvX8mCwYC7UNH7hXrQ5EdkGlJjVg=="
+    },
+    "@tanstack/react-query": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.13.0.tgz",
+      "integrity": "sha512-dI/5hJ/pGQ74P5hxBLC9h6K0/Cap2T3k0ZjjjFLBCNnohDYgl7LNmMopzrRzBHk2mMjf2hgXHIzcKNG8GOZ5hg==",
+      "requires": {
+        "@tanstack/query-core": "4.13.0",
+        "use-sync-external-store": "^1.2.0"
+      }
+    },
+    "@tanstack/react-query-devtools": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.13.0.tgz",
+      "integrity": "sha512-Gv33auVlcUMrnj5qXJuhhTJtBs8bKp7v3TFRysnS+VlLOmdj9gwl5bc0e0/URL7m+PQoR1Rr55yzQ5bmZcWm1g==",
+      "requires": {
+        "@tanstack/match-sorter-utils": "^8.1.1",
+        "superjson": "^1.10.0",
+        "use-sync-external-store": "^1.2.0"
+      }
+    },
     "@testing-library/dom": {
       "version": "6.16.0",
       "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.16.0.tgz",
@@ -3884,6 +3916,14 @@
       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
       "dev": true
     },
+    "copy-anything": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.2.tgz",
+      "integrity": "sha512-CzATjGXzUQ0EvuvgOCI6A4BGOo2bcVx8B+eC2nF862iv9fopnPQwlrbACakNCHRIJbCSBj+J/9JeDf60k64MkA==",
+      "requires": {
+        "is-what": "^4.1.6"
+      }
+    },
     "copy-concurrently": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
@@ -6318,6 +6358,11 @@
         "call-bind": "^1.0.0"
       }
     },
+    "is-what": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.7.tgz",
+      "integrity": "sha512-DBVOQNiPKnGMxRMLIYSwERAS5MVY1B7xYiGnpgctsOFvVDz9f9PFXXxMcTOHuoqYp4NK9qFYQaIC1NRRxLMpBQ=="
+    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -8405,6 +8450,11 @@
       "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
       "dev": true
     },
+    "remove-accents": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz",
+      "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA=="
+    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -9562,6 +9612,14 @@
         "supports-color": "^5.5.0"
       }
     },
+    "superjson": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.11.0.tgz",
+      "integrity": "sha512-6PfAg1FKhqkwWvPb2uXhH4MkMttdc17eJ91+Aoz4s1XUEDZFmLfFx/xVA3wgkPxAGy5dpozgGdK6V/n20Wj9yg==",
+      "requires": {
+        "copy-anything": "^3.0.2"
+      }
+    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -10110,6 +10168,11 @@
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
       "dev": true
     },
+    "use-sync-external-store": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA=="
+    },
     "util": {
       "version": "0.11.1",
       "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",

+ 2 - 0
dashboard/package.json

@@ -9,6 +9,8 @@
     "@material-ui/lab": "^4.0.0-alpha.61",
     "@sentry/react": "^6.13.2",
     "@sentry/tracing": "^6.13.2",
+    "@tanstack/react-query": "^4.13.0",
+    "@tanstack/react-query-devtools": "^4.13.0",
     "@visx/axis": "^1.6.1",
     "@visx/curve": "^1.0.0",
     "@visx/event": "^1.3.0",

+ 13 - 8
dashboard/src/App.tsx

@@ -2,20 +2,25 @@ import React, { Component } from "react";
 import { BrowserRouter } from "react-router-dom";
 import PorterErrorBoundary from "shared/error_handling/PorterErrorBoundary";
 import styled, { createGlobalStyle } from "styled-components";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 
 import MainWrapper from "./main/MainWrapper";
 
+const queryClient = new QueryClient();
+
 export default class App extends Component {
   render() {
     return (
-      <StyledMain>
-        <GlobalStyle />
-        <PorterErrorBoundary errorBoundaryLocation="globalErrorBoundary">
-          <BrowserRouter>
-            <MainWrapper />
-          </BrowserRouter>
-        </PorterErrorBoundary>
-      </StyledMain>
+      <QueryClientProvider client={queryClient}>
+        <StyledMain>
+          <GlobalStyle />
+          <PorterErrorBoundary errorBoundaryLocation="globalErrorBoundary">
+            <BrowserRouter>
+              <MainWrapper />
+            </BrowserRouter>
+          </PorterErrorBoundary>
+        </StyledMain>
+      </QueryClientProvider>
     );
   }
 }

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

@@ -202,6 +202,14 @@ const DeploymentCard: React.FC<{
           <PRIcon src={pr_icon} alt="pull request icon" />
           <EllipsisTextWrapper tooltipText={deployment.gh_pr_name}>
             <StyledLink
+              onClick={(e) => {
+                e.preventDefault();
+                e.stopPropagation();
+                window.open(
+                  `https://github.com/${deployment.gh_repo_owner}/${deployment.gh_repo_name}/pull/${deployment.pull_request_id}`,
+                  "_blank"
+                );
+              }}
               to={`https://github.com/${deployment.gh_repo_owner}/${deployment.gh_repo_name}/pull/${deployment.pull_request_id}`}
               target="_blank"
             >

+ 145 - 18
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/CreateEnvironment.tsx

@@ -6,38 +6,101 @@ import styled from "styled-components";
 import { CellProps } from "react-table";
 import { Context } from "shared/Context";
 import { useParams } from "react-router";
-import { PRDeployment } from "../types";
+import { PRDeployment, PullRequest } from "../types";
 import DashboardHeader from "../../DashboardHeader";
 import PullRequestIcon from "assets/pull_request_icon.svg";
 import Helper from "components/form-components/Helper";
 import Table from "components/Table";
 import pr_icon from "assets/pull_request_icon.svg";
 import { EllipsisTextWrapper, RepoLink } from "../components/styled";
+import { useQuery, useQueryClient } from "@tanstack/react-query";
+import { getPRDeploymentList, validatePorterYAML } from "../utils";
+import Banner from "components/Banner";
+import Modal from "main/home/modals/Modal";
 
 const dummyData: any = [
   {
-    name: "this is a name",
-    branches: "asdf",
+    pr_title: "pr_title1",
+    pr_number: 1,
+    repo_owner: "repo_owner",
+    repo_name: "repo_name",
+    branch_from: "test1",
+    branch_into: "test",
   },
   {
-    name: "this is a name",
-    branches: "asdf",
+    pr_title: "pr_title2",
+    pr_number: 2,
+    repo_owner: "repo_owner",
+    repo_name: "repo_name",
+    branch_from: "test2",
+    branch_into: "test",
   },
   {
-    name: "this is a name",
-    branches: "asdf",
+    pr_title: "pr_title3",
+    pr_number: 3,
+    repo_owner: "repo_owner",
+    repo_name: "repo_name",
+    branch_from: "test3",
+    branch_into: "test",
   },
 ];
 
 const CreateEnvironment: React.FC = () => {
+  // TODO Soham: Replace any
+  const queryClient = useQueryClient();
+  const [modalContent, setModalContent] = useState<React.ReactNode>();
+  const { currentProject, currentCluster, setCurrentError } = useContext(
+    Context
+  );
   const { environment_id, repo_name, repo_owner } = useParams<{
     environment_id: string;
     repo_name: string;
     repo_owner: string;
   }>();
 
+  const { isLoading: getPullRequestsLoading, data: pullRequests } = useQuery<
+    PullRequest[]
+  >(
+    ["pullRequests", currentProject.id, currentCluster.id, environment_id],
+    async () => {
+      try {
+        const res = await getPRDeploymentList({
+          projectID: currentProject.id,
+          clusterID: currentCluster.id,
+          environmentID: Number(environment_id),
+        });
+
+        return res.data.pull_requests || [];
+      } catch (err) {
+        setCurrentError(err);
+      }
+
+      // TODO Soham: Replace with actual data
+      return dummyData; // [];
+    }
+  );
+  
+  const [selectedPR, setSelectedPR] = useState<PullRequest>();
+  const [loading, setLoading] = useState(false);
+  const [porterYAMLErrors, setPorterYAMLErrors] = useState<string[]>([]);
+
   const selectedRepo = `${repo_owner}/${repo_name}`;
 
+  const handlePRRowItemClick = async (pullRequest: PullRequest) => {
+    setSelectedPR(pullRequest);
+    setLoading(true);
+
+    const res = await validatePorterYAML({
+      projectID: currentProject.id,
+      clusterID: currentCluster.id,
+      environmentID: Number(environment_id),
+    });
+
+    setPorterYAMLErrors(res.data.errors ?? []);
+
+    setLoading(false);
+  };
+
   const columns = React.useMemo(
     () => [
       {
@@ -47,15 +110,22 @@ const CreateEnvironment: React.FC = () => {
             Header: "Open pull requests",
             accessor: "name",
             width: 140,
-            Cell: ({ row }: CellProps<any>) => {
+            Cell: ({
+              row: { original: pullRequest },
+            }: CellProps<PullRequest>) => {
               return (
-                <div style={{
-                  cursor: 'pointer',
-                }} onClick={() => alert("Hello world")}>
+                <div
+                  style={{
+                    cursor: "pointer",
+                  }}
+                  onClick={() => {
+                    handlePRRowItemClick(pullRequest);
+                  }}
+                >
                   <PRName>
                     <PRIcon src={pr_icon} alt="pull request icon" />
-                    <EllipsisTextWrapper tooltipText="test">
-                      "test"
+                    <EllipsisTextWrapper tooltipText={pullRequest.pr_title}>
+                      {pullRequest.pr_title}
                     </EllipsisTextWrapper>
                     <Spacer />
                     <RepoLink to="" target="_blank">
@@ -72,9 +142,9 @@ const CreateEnvironment: React.FC = () => {
                       <SepDot>•</SepDot>
                       <MergeInfoWrapper>
                         <MergeInfo>
-                          from-this-branch
+                          {pullRequest.branch_from}
                           <i className="material-icons">arrow_forward</i>
-                          to-this-branch
+                          {pullRequest.branch_into}
                         </MergeInfo>
                       </MergeInfoWrapper>
                     </DeploymentImageContainer>
@@ -86,7 +156,7 @@ const CreateEnvironment: React.FC = () => {
         ],
       },
     ],
-    []
+    [pullRequests]
   );
 
   return (
@@ -117,10 +187,45 @@ const CreateEnvironment: React.FC = () => {
       <Br height="10px" />
       <Table
         columns={columns}
-        data={dummyData}
+        data={pullRequests}
         placeholder="No open pull requests found."
       />
-      <SubmitButton>Create preview deployment</SubmitButton>
+      {modalContent ? (
+        <Modal onRequestClose={() => setModalContent(null)} height="auto">
+          {modalContent}
+        </Modal>
+      ) : null}
+      {selectedPR && porterYAMLErrors.length ? (
+        <ValidationErrorBannerWrapper>
+          <Banner type="warning">
+            We found some errors in the porter.yaml file on your default branch.
+            &nbsp;
+            <LearnMoreButton
+              onClick={() =>
+                setModalContent(
+                  <Message>
+                    {porterYAMLErrors.map((el) => {
+                      return (
+                        <div>
+                          {"- "}
+                          {el}
+                        </div>
+                      );
+                    })}
+                  </Message>
+                )
+              }
+            >
+              Learn more
+            </LearnMoreButton>
+          </Banner>
+        </ValidationErrorBannerWrapper>
+      ) : null}
+      <SubmitButton
+        disabled={loading || !selectedPR || porterYAMLErrors.length > 0}
+      >
+        Create preview deployment
+      </SubmitButton>
     </>
   );
 };
@@ -412,3 +517,25 @@ const Button = styled(DynamicLink)`
     justify-content: center;
   }
 `;
+
+const ValidationErrorBannerWrapper = styled.div`
+  margin-block: 20px;
+`;
+
+const LearnMoreButton = styled.div`
+  fontweight: bold;
+  cursor: pointer;
+  &:hover {
+    text-decoration: underline;
+  }
+`;
+
+const Message = styled.div`
+  padding: 20px;
+  background: #26292e;
+  border-radius: 5px;
+  line-height: 1.5em;
+  border: 1px solid #aaaabb33;
+  font-size: 13px;
+  margin-top: 40px;
+`;