From 0a1a53e0bcf132a86c5b5014f850e7bae04a3a09 Mon Sep 17 00:00:00 2001 From: Nabarun Gogoi <nabarun@deepstacksoft.com> Date: Thu, 21 Dec 2023 16:42:06 +0530 Subject: [PATCH] Add chips to display different kinds of information (#20) * Add chip for showing deployment status * Add chip to display projects count * Display label if project search is not matching * Add chip to display domain is not connected * Fix text size in chips for deployment domain * Add chip to display if repository is private --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com> --- packages/frontend/src/assets/deployments.json | 6 +- packages/frontend/src/assets/projects.json | 18 +++-- .../frontend/src/assets/repositories.json | 20 +++--- .../src/components/projects/ProjectCard.tsx | 2 +- .../src/components/projects/ProjectSearch.tsx | 65 +++++++++++-------- .../projects/create/ProjectRepoCard.tsx | 21 ++++-- .../projects/project/ActivityCard.tsx | 9 ++- .../projects/project/DeploymentsTabPanel.tsx | 8 ++- .../projects/project/OverviewTabPanel.tsx | 36 +++++++--- .../deployments/DeploymentDetailsCard.tsx | 31 +++++++-- packages/frontend/src/pages/Projects.tsx | 14 ++-- packages/frontend/src/types/project.ts | 1 + 12 files changed, 153 insertions(+), 78 deletions(-) diff --git a/packages/frontend/src/assets/deployments.json b/packages/frontend/src/assets/deployments.json index 6034e7e2..c2805124 100644 --- a/packages/frontend/src/assets/deployments.json +++ b/packages/frontend/src/assets/deployments.json @@ -1,6 +1,6 @@ [ { - "title": "nextjs-bolerplate-9t44zbky4dg-bygideon-projects", + "title": "nextjs-boilerplate-9t44zbky4dg-bygideon-projects", "status": "Building", "environment": "Production", "branch": "prod", @@ -12,7 +12,7 @@ "updatedAt": "2023-12-11T04:20:00" }, { - "title": "nextjs-bolerplate-9232dwky4dg-bygideon-projects", + "title": "nextjs-boilerplate-9232dwky4dg-bygideon-projects", "status": "Ready", "environment": "Preview", "branch": "prod", @@ -24,7 +24,7 @@ "updatedAt": "2023-12-11T04:20:00" }, { - "title": "nextjs-bolerplate-9saa22y4dg-bygideon-projects", + "title": "nextjs-boilerplate-9saa22y4dg-bygideon-projects", "status": "Error", "environment": "Production", "branch": "main", diff --git a/packages/frontend/src/assets/projects.json b/packages/frontend/src/assets/projects.json index 584aeb9e..c9f9e419 100644 --- a/packages/frontend/src/assets/projects.json +++ b/packages/frontend/src/assets/projects.json @@ -4,8 +4,9 @@ "icon": "^", "name": "iglotools", "title": "Iglotools", + "domain": "", "organization": "Airfoil", - "domain": "iglotools.co", + "url": "iglotools.co", "createdAt": "2023-12-07T04:20:00", "createdBy": "Alice", "deployment": "iglotools.snowballtools.co", @@ -21,8 +22,9 @@ "icon": "^", "name": "snowball-starter-kit", "title": "Snowball Starter Kit", + "domain": "", "organization": "Snowball", - "domain": "starterkit.snowballtools.com", + "url": "starterkit.snowballtools.com", "createdAt": "2023-12-04T04:20:00", "createdBy": "Bob", "deployment": "deploy.snowballtools.com", @@ -38,8 +40,9 @@ "icon": "^", "name": "web3-android", "title": "Web3 Android", + "domain": "", "organization": "Personal", - "domain": "web3fordroids.com", + "url": "web3fordroids.com", "createdAt": "2023-12-01T04:20:00", "createdBy": "Charlie", "deployment": "deploy.web3fordroids.com", @@ -55,8 +58,9 @@ "icon": "^", "name": "passkeys-demo", "title": "Passkeys Demo", + "domain": "", "organization": "Airfoil", - "domain": "passkeys.iglootools.xyz", + "url": "passkeys.iglootools.xyz", "createdAt": "2023-12-01T04:20:00", "createdBy": "David", "deployment": "demo.passkeys.xyz", @@ -72,8 +76,9 @@ "icon": "^", "name": "iglootools", "title": "Iglootools", + "domain": "", "organization": "Airfoil", - "domain": "iglotools.xyz", + "url": "iglotools.xyz", "createdAt": "2023-12-11T04:20:00", "createdBy": "Erin", "deployment": "staging.snowballtools.com", @@ -89,8 +94,9 @@ "icon": "^", "name": "iglootools", "title": "Iglootools", + "domain": "", "organization": "Airfoil", - "domain": "iglotools.xyz", + "url": "iglotools.xyz", "createdAt": "2023-12-11T04:20:00", "createdBy": "Frank", "deployment": "iglotools.snowballtools.com", diff --git a/packages/frontend/src/assets/repositories.json b/packages/frontend/src/assets/repositories.json index f9364789..04a1cff1 100644 --- a/packages/frontend/src/assets/repositories.json +++ b/packages/frontend/src/assets/repositories.json @@ -2,31 +2,31 @@ { "title": "project-101", "updatedAt": "2023-12-21T08:30:00", - "user": "bob" + "user": "bob", + "private": false }, { "title": "project-102", "updatedAt": "2023-12-21T08:30:00", - "user": "alice" + "user": "alice", + "private": true }, { "title": "project-103", "updatedAt": "2023-12-21T04:20:00", - "user": "charlie" + "user": "charlie", + "private": false }, { "title": "project-104", "updatedAt": "2023-12-21T04:27:00", - "user": "alice" + "user": "alice", + "private": false }, { "title": "project-105", "updatedAt": "2023-12-21T04:41:00", - "user": "ivan" - }, - { - "title": "project-106", - "updatedAt": "2023-12-21T04:32:00", - "user": "david" + "user": "ivan", + "private": false } ] diff --git a/packages/frontend/src/components/projects/ProjectCard.tsx b/packages/frontend/src/components/projects/ProjectCard.tsx index 25125700..afa24369 100644 --- a/packages/frontend/src/components/projects/ProjectCard.tsx +++ b/packages/frontend/src/components/projects/ProjectCard.tsx @@ -25,7 +25,7 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => { <Link to={`projects/${project.id}`}> <Typography>{project.name}</Typography> <Typography color="gray" variant="small"> - {project.domain} + {project.url} </Typography> </Link> </div> diff --git a/packages/frontend/src/components/projects/ProjectSearch.tsx b/packages/frontend/src/components/projects/ProjectSearch.tsx index baf37937..e5037431 100644 --- a/packages/frontend/src/components/projects/ProjectSearch.tsx +++ b/packages/frontend/src/components/projects/ProjectSearch.tsx @@ -27,6 +27,7 @@ const ProjectSearch = ({ onChange }: ProjectsSearchProps) => { getInputProps, getItemProps, highlightedIndex, + inputValue, } = useCombobox({ onInputValueChange({ inputValue }) { setItems( @@ -57,39 +58,47 @@ const ProjectSearch = ({ onChange }: ProjectsSearchProps) => { <div className="relative"> <SearchBar {...getInputProps()} /> <Card - className={`absolute w-1/2 max-h-100 -mt-1 overflow-y-scroll ${ - !(isOpen && items.length) && 'hidden' + className={`absolute w-1/2 max-h-52 -mt-1 overflow-y-auto ${ + (!inputValue || !isOpen) && 'hidden' }`} > <List {...getMenuProps()}> - <div className="p-3"> - <Typography variant="small" color="gray"> - Suggestions - </Typography> - </div> - {items.map((item, index) => ( - <ListItem - selected={highlightedIndex === index || selectedItem === item} - key={item.id} - {...getItemProps({ item, index })} - > - <ListItemPrefix> - <i>^</i> - </ListItemPrefix> - <div> - <Typography variant="h6" color="blue-gray"> - {item.title} - </Typography> - <Typography - variant="small" - color="gray" - className="font-normal" - > - {item.organization} + {items.length ? ( + <> + <div className="p-3"> + <Typography variant="small" color="gray"> + Suggestions </Typography> </div> - </ListItem> - ))} + {items.map((item, index) => ( + <ListItem + selected={highlightedIndex === index || selectedItem === item} + key={item.id} + {...getItemProps({ item, index })} + > + <ListItemPrefix> + <i>^</i> + </ListItemPrefix> + <div> + <Typography variant="h6" color="blue-gray"> + {item.title} + </Typography> + <Typography + variant="small" + color="gray" + className="font-normal" + > + {item.organization} + </Typography> + </div> + </ListItem> + ))} + </> + ) : ( + <div className="p-3"> + <Typography>^ No projects matching this name</Typography> + </div> + )} </List> </Card> </div> diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx b/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx index 67703f86..158de6bc 100644 --- a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx +++ b/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { IconButton } from '@material-tailwind/react'; +import { Chip, IconButton } from '@material-tailwind/react'; import { relativeTime } from '../../../utils/time'; @@ -8,6 +8,7 @@ interface RepositoryDetails { title: string; updatedAt: string; user: string; + private: boolean; } interface ProjectRepoCardProps { @@ -19,9 +20,21 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => { <div className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 p-2 cursor-pointer"> <div>^</div> <div className="grow"> - <p className="text-black"> - {repository.user}/{repository.title} - </p> + <div> + <span className="text-black"> + {repository.user}/{repository.title} + </span> + {repository.private ? ( + <Chip + className="normal-case inline ml-6 bg-[#FED7AA] text-[#EA580C] font-normal" + size="sm" + value="Private" + icon={'^'} + /> + ) : ( + '' + )} + </div> <p>{relativeTime(repository.updatedAt)}</p> </div> <div className="hidden group-hover:block"> diff --git a/packages/frontend/src/components/projects/project/ActivityCard.tsx b/packages/frontend/src/components/projects/project/ActivityCard.tsx index 4d2b8497..9a8f473a 100644 --- a/packages/frontend/src/components/projects/project/ActivityCard.tsx +++ b/packages/frontend/src/components/projects/project/ActivityCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Typography } from '@material-tailwind/react'; +import { Typography, IconButton } from '@material-tailwind/react'; import { relativeTime } from '../../../utils/time'; @@ -18,7 +18,7 @@ interface ActivityCardProps { const ActivityCard = ({ activity }: ActivityCardProps) => { return ( - <div className="flex hover:bg-gray-200 rounded mt-1"> + <div className="group flex hover:bg-gray-200 rounded mt-1"> <div className="w-4">{activity.authorAvatar}</div> <div className="grow"> @@ -30,6 +30,11 @@ const ActivityCard = ({ activity }: ActivityCardProps) => { {activity.message} </Typography> </div> + <div className="mr-2 self-center hidden group-hover:block"> + <IconButton size="sm" className="rounded-full bg-gray-600"> + {'>'} + </IconButton> + </div> </div> ); }; diff --git a/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx b/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx index 64d1715b..ae21894b 100644 --- a/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx +++ b/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx @@ -3,7 +3,9 @@ import React, { useCallback, useMemo, useState } from 'react'; import { Button, Typography } from '@material-tailwind/react'; import deploymentData from '../../../assets/deployments.json'; -import DeployDetailsCard from './deployments/DeploymentDetailsCard'; +import DeployDetailsCard, { + DeploymentDetails, +} from './deployments/DeploymentDetailsCard'; import FilterForm, { FilterValue, StatusOptions, @@ -17,7 +19,7 @@ const DEFAULT_FILTER_VALUE: FilterValue = { const DeploymentsTabPanel = () => { const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE); - const filteredDeployments = useMemo(() => { + const filteredDeployments = useMemo<DeploymentDetails[]>(() => { return deploymentData.filter((deployment) => { // Searched branch filter const branchMatch = @@ -37,7 +39,7 @@ const DeploymentsTabPanel = () => { new Date(deployment.updatedAt) <= filterValue.updateAtRange!.to!); return branchMatch && statusMatch && dateMatch; - }); + }) as DeploymentDetails[]; }, [filterValue]); const handleResetFilters = useCallback(() => { diff --git a/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx b/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx index 65a133c5..1d49843d 100644 --- a/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx +++ b/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Typography } from '@material-tailwind/react'; +import { Typography, Button, Chip } from '@material-tailwind/react'; import ActivityCard from './ActivityCard'; import activityDetails from '../../../assets/activities.json'; @@ -19,24 +19,40 @@ const OverviewTabPanel = ({ project }: OverviewProps) => ( <div className="grow"> <Typography>{project.name}</Typography> <Typography variant="small" color="gray"> - {project.domain} + {project.url} </Typography> </div> </div> - <div className="flex justify-between p-2 text-sm"> - <p>Domain</p> - {project.domain ? <p>{project.domain}</p> : <button>Set up</button>} + <div className="flex justify-between p-2 text-sm items-center"> + <div> + ^ Domain + {!project.domain && ( + <Chip + className="normal-case ml-6 bg-[#FED7AA] text-[#EA580C] inline font-normal" + size="sm" + value="Not connected" + icon="^" + /> + )} + </div> + {project.domain ? ( + <p>{project.domain}</p> + ) : ( + <Button className="normal-case rounded-full" color="blue" size="sm"> + Setup + </Button> + )} </div> <div className="flex justify-between p-2 text-sm"> - <p>Source</p> - <p>^ {project.source}</p> + <p>^ Source</p> + <p>{project.source}</p> </div> <div className="flex justify-between p-2 text-sm"> - <p>deployment</p> - <p>{project.deployment} ^</p> + <p>^ Deployment</p> + <p className="text-blue-600">{project.deployment}</p> </div> <div className="flex justify-between p-2 text-sm"> - <p>Created</p> + <p>^ Created</p> <p> {relativeTime(project.createdAt)} by ^ {project.createdBy} </p> diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx index cd87c0d2..0a1bab92 100644 --- a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx +++ b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx @@ -6,13 +6,21 @@ import { MenuList, MenuItem, Typography, + Chip, + ChipProps, } from '@material-tailwind/react'; import { relativeTime } from '../../../../utils/time'; -interface DeploymentDetails { +export enum Status { + BUILDING = 'Building', + READY = 'Ready', + ERROR = 'Error', +} + +export interface DeploymentDetails { title: string; - status: string; + status: Status; environment: string; branch: string; commit: { @@ -27,15 +35,24 @@ interface DeployDetailsCardProps { deployment: DeploymentDetails; } +const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = { + [Status.BUILDING]: 'blue', + [Status.READY]: 'green', + [Status.ERROR]: 'red', +}; + const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => { return ( - <div className="grid grid-cols-4 gap-2 border-b border-gray-300"> + <div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2"> <div className="col-span-2"> <div className="flex"> - <Typography className=" basis-2/3">{deployment.title}</Typography> - <Typography color="gray" className="basis-1/3"> - {deployment.status} - </Typography> + <Typography className=" basis-3/4">{deployment.title}</Typography> + <Chip + value={deployment.status} + color={STATUS_COLORS[deployment.status] ?? 'gray'} + variant="ghost" + icon={<i>^</i>} + /> </div> <Typography color="gray">{deployment.environment}</Typography> </div> diff --git a/packages/frontend/src/pages/Projects.tsx b/packages/frontend/src/pages/Projects.tsx index f7c4fa08..daafcd5e 100644 --- a/packages/frontend/src/pages/Projects.tsx +++ b/packages/frontend/src/pages/Projects.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { Button, IconButton, Typography } from '@material-tailwind/react'; +import { Button, IconButton, Typography, Chip } from '@material-tailwind/react'; import ProjectCard from '../components/projects/ProjectCard'; import HorizontalLine from '../components/HorizontalLine'; @@ -26,12 +26,18 @@ const Projects = () => { </div> </div> <HorizontalLine /> - <div className="flex p-4"> + <div className="flex p-5"> <div className="grow"> - <Typography variant="h4">Projects</Typography> + <div className="flex gap-2 items-center"> + <Typography variant="h4">Projects</Typography> + <Chip + className="bg-gray-300 rounded-full static" + value={projectsDetail.length} + size="sm" + /> + </div> </div> <div> - {/* TODO: Create button component */} <Link to="/projects/create"> <Button className="rounded-full" color="blue"> Create project diff --git a/packages/frontend/src/types/project.ts b/packages/frontend/src/types/project.ts index 602a53e6..1e8c6a7f 100644 --- a/packages/frontend/src/types/project.ts +++ b/packages/frontend/src/types/project.ts @@ -3,6 +3,7 @@ export interface ProjectDetails { name: string; title: string; organization: string; + url: string; domain: string; id: number; createdAt: string;