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

styles broken: Implemented pagination for job runs on expanded job chart

jnfrati 4 лет назад
Родитель
Сommit
3aa5cf64d3

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

@@ -5,6 +5,8 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import JobResource from "./JobResource";
 import useAuth from "shared/auth/useAuth";
+import usePagination from "shared/hooks/usePagination";
+import Selector from "components/Selector";
 
 type PropsType = {
   jobs: any[];
@@ -27,6 +29,22 @@ const JobListFC = (props: PropsType): JSX.Element => {
   const [deletionCandidate, setDeletionCandidate] = useState(null);
   const [deletionJob, setDeletionJob] = useState(null);
 
+  const {
+    firstContentIndex,
+    lastContentIndex,
+    nextPage,
+    page,
+    prevPage,
+    totalPages,
+    pageSize,
+    setPageSize,
+    canNextPage,
+    canPreviousPage,
+  } = usePagination({
+    count: props.jobs?.length,
+    initialPageSize: 10,
+  });
+
   const deleteJob = () => {
     let job = deletionCandidate;
     setCurrentOverlay(null);
@@ -66,39 +84,123 @@ const JobListFC = (props: PropsType): JSX.Element => {
   }
 
   return (
-    <JobListWrapper>
-      {props.jobs.map((job: any, i: number) => {
-        return (
-          <JobResource
-            key={job?.metadata?.name}
-            expandJob={props.expandJob}
-            job={job}
-            handleDelete={() => {
-              setDeletionCandidate(job);
-              setCurrentOverlay({
-                message: "Are you sure you want to delete this job run?",
-                onYes: deleteJob,
-                onNo: () => {
-                  setDeletionCandidate(null);
-                  setCurrentOverlay(null);
-                },
-              });
-            }}
-            deleting={deletionJob?.metadata?.name == job.metadata?.name}
-            readOnly={!isAuthorized("job", "", ["get", "update", "delete"])}
-            isDeployedFromGithub={props.isDeployedFromGithub}
-            repositoryUrl={props.repositoryUrl}
-            currentChartVersion={props.currentChartVersion}
-            latestChartVersion={props.latestChartVersion}
-          />
-        );
-      })}
-    </JobListWrapper>
+    <>
+      <JobListWrapper>
+        {props.jobs
+          .slice(firstContentIndex, lastContentIndex)
+          .map((job: any, i: number) => {
+            return (
+              <JobResource
+                key={job?.metadata?.name}
+                expandJob={props.expandJob}
+                job={job}
+                handleDelete={() => {
+                  setDeletionCandidate(job);
+                  setCurrentOverlay({
+                    message: "Are you sure you want to delete this job run?",
+                    onYes: deleteJob,
+                    onNo: () => {
+                      setDeletionCandidate(null);
+                      setCurrentOverlay(null);
+                    },
+                  });
+                }}
+                deleting={deletionJob?.metadata?.name == job.metadata?.name}
+                readOnly={!isAuthorized("job", "", ["get", "update", "delete"])}
+                isDeployedFromGithub={props.isDeployedFromGithub}
+                repositoryUrl={props.repositoryUrl}
+                currentChartVersion={props.currentChartVersion}
+                latestChartVersion={props.latestChartVersion}
+              />
+            );
+          })}
+      </JobListWrapper>
+      <FlexEnd style={{ marginTop: "15px" }}>
+        <PageCountWrapper>
+          Page size:
+          <Selector
+            activeValue={String(pageSize)}
+            options={[
+              {
+                label: "10",
+                value: "10",
+              },
+              {
+                label: "20",
+                value: "20",
+              },
+              {
+                label: "50",
+                value: "50",
+              },
+              {
+                label: "100",
+                value: "100",
+              },
+            ]}
+            setActiveValue={(val) => setPageSize(Number(val))}
+            width="70px"
+          ></Selector>
+        </PageCountWrapper>
+        <PaginationActionsWrapper>
+          <PaginationAction disabled={!canPreviousPage} onClick={prevPage}>
+            {"<"}
+          </PaginationAction>
+          <PageCounter>
+            {page} of {totalPages}
+          </PageCounter>
+          <PaginationAction disabled={!canNextPage} onClick={nextPage}>
+            {">"}
+          </PaginationAction>
+        </PaginationActionsWrapper>
+      </FlexEnd>
+    </>
   );
 };
 
 export default JobListFC;
 
+const FlexEnd = styled.div`
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  width: 100%;
+`;
+
+const PaginationActionsWrapper = styled.div``;
+
+const PageCountWrapper = styled.div`
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  min-width: 160px;
+  margin-right: 10px;
+`;
+
+const PaginationAction = styled.button`
+  border: none;
+  background: unset;
+  color: white;
+  padding: 10px;
+  cursor: pointer;
+  border-radius: 5px;
+  :hover {
+    background: #ffffff40;
+  }
+
+  :disabled {
+    color: #ffffff88;
+    cursor: unset;
+    :hover {
+      background: unset;
+    }
+  }
+`;
+
+const PageCounter = styled.span`
+  margin: 0 5px;
+`;
+
 const Placeholder = styled.div`
   width: 100%;
   min-height: 250px;

+ 103 - 0
dashboard/src/shared/hooks/usePagination.ts

@@ -0,0 +1,103 @@
+/**
+ * Improved version using as base the usePagination hook by gh user @damiisdandy
+ * Base hook on his repo https://github.com/damiisdandy/use-pagination
+ */
+
+import { useState } from "react";
+
+interface UsePaginationProps {
+  count: number;
+  initialPageSize?: number;
+}
+
+interface UsePaginationReturn {
+  page: number;
+  totalPages: number;
+  setPage: (page: number) => void;
+  nextPage: () => void;
+  prevPage: () => void;
+  firstContentIndex: number;
+  lastContentIndex: number;
+  pageSize: number;
+  setPageSize: (pageSize: number) => void;
+  canNextPage: boolean;
+  canPreviousPage: boolean;
+}
+
+type UsePagination = (props: UsePaginationProps) => UsePaginationReturn;
+
+const usePagination: UsePagination = ({ count, initialPageSize }) => {
+  const [pageSize, setPageSize] = useState(() => {
+    if (typeof initialPageSize === "number" && initialPageSize !== NaN) {
+      return initialPageSize;
+    }
+
+    return 10;
+  });
+
+  const [page, setPage] = useState(1);
+  // number of pages in total (total items / content on each page)
+  const pageCount = Math.ceil(count / pageSize);
+  // index of last item of current page
+  const lastContentIndex = page * pageSize;
+  // index of first item of current page
+  const firstContentIndex = lastContentIndex - pageSize;
+
+  // change page based on direction either front or back
+  const changePage = (direction: boolean) => {
+    setPage((state) => {
+      // move forward
+      if (direction) {
+        // if page is the last page, do nothing
+        if (state === pageCount) {
+          return state;
+        }
+        return state + 1;
+        // go back
+      } else {
+        // if page is the first page, do nothing
+        if (state === 1) {
+          return state;
+        }
+        return state - 1;
+      }
+    });
+  };
+
+  const setPageSAFE = (num: number) => {
+    // if number is greater than number of pages, set to last page
+    if (num > pageCount) {
+      setPage(pageCount);
+      // if number is less than 1, set page to first page
+    } else if (num < 1) {
+      setPage(1);
+    } else {
+      setPage(num);
+    }
+  };
+
+  const setPageSizeSAFE = (pageSize: number) => {
+    if (typeof initialPageSize === "number" && initialPageSize !== NaN) {
+      setPageSize(pageSize);
+    }
+  };
+
+  const canNextPage = page <= pageCount - 1;
+  const canPreviousPage = page > 1;
+
+  return {
+    totalPages: pageCount,
+    nextPage: () => changePage(true),
+    prevPage: () => changePage(false),
+    setPage: setPageSAFE,
+    firstContentIndex,
+    lastContentIndex,
+    page,
+    pageSize,
+    setPageSize: setPageSizeSAFE,
+    canNextPage,
+    canPreviousPage,
+  };
+};
+
+export default usePagination;