forked from cerc-io/snowballtools-base
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>
This commit is contained in:
parent
3133fb989f
commit
0a1a53e0bc
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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(() => {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -3,6 +3,7 @@ export interface ProjectDetails {
|
||||
name: string;
|
||||
title: string;
|
||||
organization: string;
|
||||
url: string;
|
||||
domain: string;
|
||||
id: number;
|
||||
createdAt: string;
|
||||
|
Loading…
Reference in New Issue
Block a user