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

Project selection and metadata styling updates (#3342)

sdess09 2 лет назад
Родитель
Сommit
f8baeaea72

+ 15 - 30
dashboard/package-lock.json

@@ -16426,8 +16426,7 @@
     "@icons/material": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
-      "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
-      "requires": {}
+      "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
     },
     "@ironplans/api": {
       "version": "0.4.1",
@@ -16607,8 +16606,7 @@
     "@material-ui/types": {
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
-      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
-      "requires": {}
+      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A=="
     },
     "@material-ui/utils": {
       "version": "4.11.3",
@@ -16923,8 +16921,7 @@
       "version": "7.2.1",
       "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz",
       "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "@types/body-parser": {
       "version": "1.19.2",
@@ -18141,15 +18138,13 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
       "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "ajv-keywords": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
       "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "anser": {
       "version": "2.1.1",
@@ -21086,8 +21081,7 @@
     "goober": {
       "version": "2.1.12",
       "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.12.tgz",
-      "integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==",
-      "requires": {}
+      "integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q=="
     },
     "good-listener": {
       "version": "1.2.2",
@@ -21473,8 +21467,7 @@
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
       "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "ieee754": {
       "version": "1.2.1",
@@ -22351,8 +22344,7 @@
     "markdown-to-jsx": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.2.0.tgz",
-      "integrity": "sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg==",
-      "requires": {}
+      "integrity": "sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg=="
     },
     "material-colors": {
       "version": "1.2.6",
@@ -23270,8 +23262,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
       "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-modules-local-by-default": {
       "version": "4.0.0",
@@ -23568,8 +23559,7 @@
     "react-animate-height": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/react-animate-height/-/react-animate-height-3.1.1.tgz",
-      "integrity": "sha512-UkC6+V3ZlCneBRaSM7aUctDJ+PRP6ztcGtxvU7MTeoMMWPhz8BQNaX7QWaZrkzp1ih1G8uZZ+DI9nfLvtD6OdQ==",
-      "requires": {}
+      "integrity": "sha512-UkC6+V3ZlCneBRaSM7aUctDJ+PRP6ztcGtxvU7MTeoMMWPhz8BQNaX7QWaZrkzp1ih1G8uZZ+DI9nfLvtD6OdQ=="
     },
     "react-beautiful-dnd": {
       "version": "13.1.1",
@@ -23688,8 +23678,7 @@
     "react-onclickoutside": {
       "version": "6.12.2",
       "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.2.tgz",
-      "integrity": "sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA==",
-      "requires": {}
+      "integrity": "sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA=="
     },
     "react-popper": {
       "version": "2.3.0",
@@ -23761,8 +23750,7 @@
     "react-table": {
       "version": "7.8.0",
       "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
-      "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
-      "requires": {}
+      "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA=="
     },
     "react-transition-group": {
       "version": "4.4.5",
@@ -25544,14 +25532,12 @@
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
       "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
-      "dev": true,
-      "requires": {}
+      "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==",
-      "requires": {}
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA=="
     },
     "util": {
       "version": "0.11.1",
@@ -26845,8 +26831,7 @@
       "version": "7.5.9",
       "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
       "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "xtend": {
       "version": "4.0.2",

+ 58 - 18
dashboard/src/main/home/project-settings/Metadata.tsx

@@ -17,7 +17,9 @@ import CopyToClipboard from "components/CopyToClipboard";
 import copy from "assets/copy-left.svg"
 import Icon from "components/porter/Icon";
 import { ClusterType } from "shared/types";
-
+import globe from "assets/globe.svg"
+import infra from "assets/infra.png";
+import gear from "assets/gear.svg"
 type Props = {
 };
 
@@ -28,18 +30,20 @@ const Metadata: React.FC<Props> = ({
     const [clusters, setClusters] = useState<ClusterType[]>([]);
     const [registries, setRegistries] = useState<any[]>(null);
     // Add name as a property of the component
-    const IdTextWithCopy = ({ id, name }: { id: number, name: string }) => (
+    const IdTextWithCopy = ({ id, name, icon }: { id: number, name: string, icon: any }) => (
         <IdContainer>
-            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
-                <span style={{ fontSize: '0.8em', marginRight: '10px' }}> {name}</span>
-                <div style={{ display: 'flex', alignItems: 'center' }}>
-                    <span style={{ fontSize: '0.8em', marginRight: '5px' }}>Id: {id}</span>
+            <Container>
+                <Icon src={icon} height={"14px"} />
+                <IconWithName>{name}</IconWithName>
+                <CopyContainer>
+                    <IdText>Id: {id}</IdText>
                     <CopyToClipboard text={id.toString()}>
-                        <img src={copy} alt="copy" style={{ cursor: "pointer", marginLeft: "5px", marginRight: "5px", width: "10px", height: "10px" }} />
+                        <CopyIcon src={copy} alt="copy" />
                     </CopyToClipboard>
-                </div>
-            </div>
+                </CopyContainer>
+            </Container>
         </IdContainer>
+
     );
 
 
@@ -74,26 +78,30 @@ const Metadata: React.FC<Props> = ({
 
     return (
         <>
-            <Text>Project Id: </Text>
-            <IdTextWithCopy id={currentProject?.id} name={currentProject?.name} /> {/* Assuming currentProject has name field */}
-            <Spacer y={1} />
+            <Text>Project</Text>
+            <IdTextWithCopy id={currentProject?.id} name={currentProject?.name} icon={globe} /> {/* Assuming currentProject has name field */}
+            <Spacer y={.5} />
             {clusters?.length > 0 && <>
-                <Text>Cluster Ids:</Text>
+                <Text>Clusters</Text>
                 {clusters?.length > 0 &&
                     clusters.map((cluster, index) =>
-                        <IdTextWithCopy key={index} id={cluster.id} name={cluster.name} />
+                        <>
+                            <IdTextWithCopy key={index} id={cluster.id} name={cluster.name} icon={infra} />
+                        </>
                     )
                 }
             </>
             }
-            <Spacer y={1} />
+            <Spacer y={.5} />
 
             {registries?.length > 0 &&
                 <>
-                    <Text>Registry Ids:</Text>
+                    <Text>Registries</Text>
                     {registries?.length > 0 &&
                         registries.map((registry, index) =>
-                            <IdTextWithCopy key={index} id={registry.id} name={registry.name} />
+                            <>
+                                <Icon src={globe} /> <IdTextWithCopy key={index} id={registry.id} name={registry.name} icon={gear} />
+                            </>
                         )
                     }
                 </>}
@@ -111,6 +119,7 @@ const IdContainer = styled.div`
     display: block;
     width: 100%;
     border-radius: 5px;
+    background: ${(props) => props.theme.fg};
     border: 1px solid ${({ theme }) => theme.border};
     margin-bottom: 10px;
     margin-top: 5px;
@@ -121,4 +130,35 @@ const IdContainer = styled.div`
 // border-radius: 5px;
 // background: ${({ theme }) => theme.fg}};
 // border: 1px solid ${({ theme }) => theme.border};
-// `;
+// `;
+
+const Container = styled.div`
+  padding: 5px;
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+`;
+
+const IconWithName = styled.span`
+  font-size: 0.8em;
+  margin-left: 10px;
+`;
+
+const CopyContainer = styled.div`
+  display: flex;
+  align-items: center;
+  margin-left: auto;
+`;
+
+const IdText = styled.span`
+  font-size: 0.8em;
+  margin-right: 5px;
+`;
+
+const CopyIcon = styled.img`
+  cursor: pointer;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 10px;
+  height: 10px;
+`;

+ 67 - 31
dashboard/src/main/home/sidebar/ProjectButton.tsx

@@ -51,33 +51,29 @@ const ProjectButton: React.FC<PropsType> = (props) => {
   if (currentProject) {
     return (
       <StyledProjectSection ref={wrapperRef}>
+        {showGHAModal && currentProject != null && (
+          <ProjectSelectionModal
+            currentProject={props.currentProject}
+            projects={props.projects}
+            closeModal={() => setShowGHAModal(false)}
+          />
+        )}
         <MainSelector
-          onClick={handleExpand}
-          expanded={expanded}
-          hasMultipleProjects={props.projects.length > 1}
-        >
+          projectsLength={props.projects.length}
+          isPorterUser={user.isPorterUser}
+          onClick={() => (props.projects.length > 1 || user.isPorterUser) && setShowGHAModal(true)} >
           <ProjectIcon>
             <ProjectImage src={gradient} />
             <Letter>{currentProject.name[0].toUpperCase()}</Letter>
           </ProjectIcon>
-          <ProjectName
-            hasMultipleProjects={props.projects.length > 1}
-            title={currentProject.name} // Add this line
-          >
-            {currentProject.name}
-          </ProjectName>
+          <ProjectName>{currentProject.name}</ProjectName>
           <Spacer inline x={.5} />
 
-          {(props.projects.length > 1 || user?.isPorterUser) && <RefreshButton onClick={() => setShowGHAModal(true)}>
+          {(props.projects.length > 1 || user.isPorterUser) && <RefreshButton>
             <img src={swap} />
           </RefreshButton>}
-          {showGHAModal && currentProject != null && (
-            <ProjectSelectionModal
-              currentProject={props.currentProject}
-              projects={props.projects}
-              closeModal={() => setShowGHAModal(false)}
-            />
-          )}
+
+          {/* <i className="material-icons">arrow_drop_down</i> */}
         </MainSelector>
         {/* {renderDropdown()} */}
       </StyledProjectSection >
@@ -131,7 +127,48 @@ const InitializeButton = styled.div`
   }
 `;
 
+const Option = styled.div`
+  width: 100%;
+  border-top: 1px solid #00000000;
+  border-bottom: 1px solid
+    ${(props: { selected: boolean; lastItem?: boolean }) =>
+    props.lastItem ? "#ffffff00" : "#ffffff15"};
+  height: 45px;
+  display: flex;
+  align-items: center;
+  font-size: 13px;
+  align-items: center;
+  padding-left: 10px;
+  cursor: pointer;
+  padding-right: 10px;
+  background: ${(props: { selected: boolean; lastItem?: boolean }) =>
+    props.selected ? "#ffffff11" : ""};
+  :hover {
+    background: ${(props: { selected: boolean; lastItem?: boolean }) =>
+    props.selected ? "" : "#ffffff22"};
+  }
 
+  > i {
+    font-size: 18px;
+    margin-right: 12px;
+    margin-left: 5px;
+    color: #ffffff44;
+  }
+`;
+
+const Dropdown = styled.div`
+  position: absolute;
+  right: 13px;
+  top: calc(100% + 5px);
+  background: #26282f;
+  width: 210px;
+  max-height: 500px;
+  border-radius: 3px;
+  z-index: 999;
+  overflow-y: auto;
+  margin-bottom: 10px;
+  box-shadow: 0 5px 15px 5px #00000077;
+`;
 
 const Letter = styled.div`
   height: 100%;
@@ -155,10 +192,10 @@ const ProjectIcon = styled.div`
   width: 25px;
   min-width: 25px;
   height: 25px;
-  border-radius: 2px;
+  border-radius: 3px;
   overflow: hidden;
   position: relative;
-  margin-right: 6px;
+  margin-right: 10px;
   font-weight: 400;
 `;
 const ProjectIconAlt = styled(ProjectIcon)`
@@ -170,17 +207,17 @@ const ProjectIconAlt = styled(ProjectIcon)`
 
 const StyledProjectSection = styled.div`
   position: relative;
-  margin-left: 2px;
+  margin-left: 3px;
   color: ${props => props.theme.text.primary};
 `;
 
-const MainSelector = styled.div<{ expanded: boolean, hasMultipleProjects: boolean }>`
+const MainSelector = styled.div`
   display: flex;
   align-items: center;
-  justify-content: ${props => props.hasMultipleProjects ? 'space-between' : 'flex-start'};
+  justify-content: space-between;
   margin: 10px 0 0;
   font-size: 14px;
-  cursor: pointer;
+  cursor: ${props => (props.projectsLength > 1 || props.isPorterUser) ? "pointer" : "default"};
   padding: 10px 20px;
   position: relative;
   :hover {
@@ -197,17 +234,16 @@ const MainSelector = styled.div<{ expanded: boolean, hasMultipleProjects: boolea
     align-items: center;
     justify-content: center;
     border-radius: 20px;
-    background: ${props => props.expanded ? "#ffffff22" : ""};
+    background: "#ffffff22" 
   }
 `;
 
-const ProjectName = styled.div<{ hasMultipleProjects: boolean }>`
+const ProjectName = styled.div`
   overflow: hidden;
   white-space: nowrap;
-  text-overflow: ${props => props.hasMultipleProjects ? 'ellipsis' : 'clip'};
-  flex-grow: ${props => props.hasMultipleProjects ? 1 : 0};
-  padding-right: ${props => props.hasMultipleProjects ? '1px' : '0'};
-  max-width: ${props => props.hasMultipleProjects ? 'auto' : '26ch'}; // Limit to max 25 characters when no multiple projects
+  text-overflow: ellipsis;
+  flex-grow: 1; // <-- Add flex-grow here
+  padding-right: 20px; // <-- Add padding-right here
 `;
 
 const RefreshButton = styled.div`
@@ -225,6 +261,6 @@ const RefreshButton = styled.div`
     display: flex;
     align-items: center;
     justify-content: center;
-    height: 14px;
+    height: 15px;
   }
 `;

+ 76 - 164
dashboard/src/main/home/sidebar/ProjectSelectionModal.tsx

@@ -15,6 +15,7 @@ import _ from 'lodash';
 import { useMemo } from 'react';
 import api from "shared/api";
 import Button from "components/porter/Button";
+import Container from "components/porter/Container";
 
 type Props = RouteComponentProps & {
   closeModal: () => void;
@@ -34,19 +35,24 @@ const ProjectSelectionModal: React.FC<Props> = ({
   const [clusters, setClusters] = useState<DetailedClusterType[]>([]);
   const [loading, setLoading] = useState<boolean>(true);
   const [error, setError] = useState<string>("");
-  const [currentPage, setCurrentPage] = useState<number>(1); // add a currentPage state, starts at 1
-  const projectsPerPage = 15
   const filteredProjects = useMemo(() => {
     const filteredBySearch = projects.filter((project) => {
       return project.id === Number(searchValue) || project.name.toLowerCase().includes(searchValue.toLowerCase());
     });
 
-    // Get the projects for the current page
-    const startIndex = (currentPage - 1) * projectsPerPage;
-    const endIndex = startIndex + projectsPerPage;
+    // sort and return all the projects
+    const sortedProjects = _.sortBy(filteredBySearch, 'name');
+
+    // move the selected project to the top
+    const selectedProjectIndex = sortedProjects.findIndex(project => project.id === currentProject.id);
+    if (selectedProjectIndex !== -1) {
+      const selectedProject = sortedProjects.splice(selectedProjectIndex, 1)[0];
+      sortedProjects.unshift(selectedProject);
+    }
+
+    return sortedProjects;
+  }, [projects, searchValue, currentProject]);
 
-    return _.sortBy(filteredBySearch, 'name').slice(startIndex, endIndex);
-  }, [projects, searchValue, currentPage]);
   const updateClusterList = async (projectId: number) => {
     try {
       setLoading(true)
@@ -70,32 +76,11 @@ const ProjectSelectionModal: React.FC<Props> = ({
     }
   };
   const renderBlockList = () => {
-    const lastBlock = user && user.isPorterUser ? (
-      <Block
-        isLastBlock={true}
-        key="initialize"
-        onClick={() =>
-          pushFiltered(props, "/new-project", ["project_id"], {
-            new_project: true,
-          })
-        }
-      >
-        <BlockTitle>Create a project</BlockTitle>
-        {/* <ProjectIcon>
-          <ProjectImage src={gradient} />
-          <Letter>{"+"}</Letter>
-        </ProjectIcon> */}
-        <BlockDescription>
-          Initialize a new project
-        </BlockDescription>
-      </Block>
-    ) : null;
-
     return filteredProjects.map((project: ProjectType, i: number) => {
       return (
-        <Block
+        <IdContainer
           key={i}
-          selected={project.name === currentProject.name}
+          selected={project.id === currentProject.id}
           onClick={async () => {
             // if (project.id !== currentProject.id) {
             //   setCurrentCluster(null);
@@ -124,67 +109,46 @@ const ProjectSelectionModal: React.FC<Props> = ({
           <BlockDescription>
             Project Id: {project.id}
           </BlockDescription>
-        </Block>
+        </IdContainer>
       );
-    }).concat(lastBlock);
-  };
-
-  const renderPaginationButtons = () => {
-    const totalProjects = projects.length;
-    const totalPages = Math.ceil(totalProjects / projectsPerPage);
-
-    // Only render pagination buttons if there are multiple pages
-    if (totalPages > 1) {
-      return (
-        <PaginationButtonsContainer>
-          <Button
-            disabled={currentPage === 1}
-            onClick={() => setCurrentPage((page) => Math.max(page - 1, 1))}
-          >
-            Previous
-          </Button>
-
-          <span>{currentPage} / {totalPages}</span>
-
-          <Button
-            disabled={currentPage === totalPages}
-            onClick={() => setCurrentPage((page) => Math.min(page + 1, totalPages))}
-          >
-            Next
-          </Button>
-        </PaginationButtonsContainer>
-      );
-    }
-
-    // If there is only one page, don't render the buttons
-    return null;
+    });
   };
 
   return (
-    <Modal closeModal={closeModal} width={'900px'}>
+    <Modal closeModal={closeModal} width={'600px'}>
       <Text size={16} style={{ marginRight: '10px' }}>
         Switch Project
       </Text>
       <Spacer y={1} />
 
-      <SearchBar
-        value={searchValue}
-        setValue={(x) => {
-          setSearchValue(x);
-        }}
-        placeholder="Search projects..."
-        width="100%"
-      />
+      <Container row spaced>
+        <SearchBar
+          value={searchValue}
+          setValue={(x) => {
+            setSearchValue(x);
+          }}
+          placeholder="Search projects..."
+          width="100%"
+        />
+
+        <Spacer inline x={1} />
+
+        {user.isPorterUser && <Button onClick={() =>
+          pushFiltered(props, "/new-project", ["project_id"], {
+            new_project: true,
+          })} height="30px" width="130px">
+          <I className="material-icons">add</I> New Project
+        </Button>}
+      </Container>
 
       <Spacer y={1} />
 
-      <ScrollableContent>  {/* Wrap the block list and pagination buttons */}
-        <BlockList>
+      <ScrollableContent>  {/* Wrap the block list */}
+        {/* <BlockList>
           {renderBlockList()}
-        </BlockList>
+        </BlockList> */}
+        {renderBlockList()}
         <Spacer height="15px" />
-
-        {renderPaginationButtons()}
       </ScrollableContent>
     </Modal >
   )
@@ -192,68 +156,37 @@ const ProjectSelectionModal: React.FC<Props> = ({
 
 export default withRouter(ProjectSelectionModal);
 
-const Block = styled.div<{ selected?: boolean }>`
-  align-items: center;
-  user-select: none;
-  display: flex;
-  font-size: 13px;
-  overflow: hidden;
-  font-weight: 500;
-  padding: 3px 0px 12px;
-  flex-direction: column;
-  height: 170px;
-  cursor: pointer;
-  color: #ffffff;
-  position: relative;
-
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  align-items: center;
-  border-radius: 5px;
-  background: ${props => props.isLastBlock ? '#aaaabb' : props.theme.clickable.bg};
-
-  border: ${props => props.selected ? "2px solid #8590ff" : "1px solid #494b4f"};
-  :hover {
-    border: ${({ selected }) => (!selected && "1px solid #7a7b80")};
-  }
-
-  animation: fadeIn 0.3s 0s;
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
+const IdContainer = styled.div`
+    color: #ffffff;
+    border-radius: 5px;
+    padding: 5px;
+    display: block;
+    width: 100%;
+    border-radius: 5px;
+    border: 1px solid ${({ theme }) => theme.border};
+    margin-bottom: 10px;
+    margin-top: 5px;
+      border: ${props => props.selected ? "2px solid #8590ff" : "1px solid #494b4f"};
+      :hover {
+        border: ${({ selected }) => (!selected && "1px solid #7a7b80")};
+      }
+      cursor: pointer;
 
-const BlockList = styled.div`
-  overflow: visible;
-  margin-top: 6px;
-  display: grid;
-  grid-column-gap: 25px;
-  grid-row-gap: 25px;
-  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
-`;
+      animation: fadeIn 0.3s 0s;
+      @keyframes fadeIn {
+        from {
+          opacity: 0;
+        }
+        to {
+          opacity: 1;
+        }
+      }
+    `;
 
-const Letter = styled.div`
-  height: 100%;
-  width: 100%;
-  position: absolute;
-  padding-bottom: 2px;
-  font-weight: 10000;
-  font-size: 60px;
-  top: 0;
-  left: 0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
 const BlockDescription = styled.div`
   color: #ffffff66;
   margin-left: -10px;
+  margin-top: 4px;
   text-align: center;
   font-weight: default;
   font-size: 13px;
@@ -277,37 +210,16 @@ const BlockTitle = styled.div`
   overflow: hidden;
   text-overflow: ellipsis;
 `;
-
-const Plus = styled.div`
-  margin-right: 10px;
-  font-size: 15px;
-`;
-
-
-const ProjectImage = styled.img`
-width: 100%;
-height: 100%;
-`;
-
-const ProjectIcon = styled.div`
-width: 75px;
-min-width: 25px;
-height: 75px;
-border-radius: 3px;
-overflow: hidden;
-position: relative;
-margin-right: 10px;
-font-weight: 400;
-`;
-
-const PaginationButtonsContainer = styled.div`
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-top: 20px;
-`;
 const ScrollableContent = styled.div`
   overflow-y: auto; /* Enable vertical scrolling */
-  height: calc(100vh - 200px); /* Set the maximum height */
+  height: calc(100vh - 500px); /* Set the maximum height */
   padding-right: 15px; /* Add some right padding to account for scrollbar */
 `;
+const I = styled.i`
+  color: white;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  margin-right: 5px;
+  justify-content: center;
+`;