UI fixes in Snowball frontend app (#93)
* Fix alignment of deployment status chip * Use template name from env * Use env for git template link * Add loading spinner for create project * Display user name * Format the displayed user name --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
		
							parent
							
								
									e816c596ca
								
							
						
					
					
						commit
						6b17dce2ae
					
				
							
								
								
									
										6
									
								
								packages/backend/test/fixtures/users.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								packages/backend/test/fixtures/users.json
									
									
									
									
										vendored
									
									
								
							| @ -1,19 +1,19 @@ | ||||
| [ | ||||
|   { | ||||
|     "id": "59f4355d-9549-4aac-9b54-eeefceeabef0", | ||||
|     "name": "Snowball", | ||||
|     "name": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", | ||||
|     "email": "snowball@snowballtools.xyz", | ||||
|     "isVerified": true | ||||
|   }, | ||||
|   { | ||||
|     "id": "e505b212-8da6-48b2-9614-098225dab34b", | ||||
|     "name": "Alice Anderson", | ||||
|     "name": "0xbe0eb53f46cd790cd13851d5eff43d12404d33e8", | ||||
|     "email": "alice@snowballtools.xyz", | ||||
|     "isVerified": true | ||||
|   }, | ||||
|   { | ||||
|     "id": "cd892fad-9138-4aa2-a62c-414a32776ea7", | ||||
|     "name": "Bob Banner", | ||||
|     "name": "0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a", | ||||
|     "email": "bob@snowballtools.xyz", | ||||
|     "isVerified": true | ||||
|   } | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import React, { useCallback } from 'react'; | ||||
| import toast from 'react-hot-toast'; | ||||
| import { useNavigate, useParams } from 'react-router-dom'; | ||||
| 
 | ||||
| import { Chip, IconButton } from '@material-tailwind/react'; | ||||
| import { Chip, IconButton, Spinner } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import { relativeTimeISO } from '../../../utils/time'; | ||||
| import { GitRepositoryDetails } from '../../../types'; | ||||
| @ -14,6 +15,7 @@ interface ProjectRepoCardProps { | ||||
| const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => { | ||||
|   const client = useGQLClient(); | ||||
|   const navigate = useNavigate(); | ||||
|   const [isLoading, setIsLoading] = React.useState(false); | ||||
| 
 | ||||
|   const { orgSlug } = useParams(); | ||||
| 
 | ||||
| @ -22,6 +24,7 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     setIsLoading(true); | ||||
|     const { addProject } = await client.addProject(orgSlug!, { | ||||
|       name: `${repository.owner!.login}-${repository.name}`, | ||||
|       prodBranch: repository.default_branch!, | ||||
| @ -30,7 +33,13 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => { | ||||
|       template: 'webapp', | ||||
|     }); | ||||
| 
 | ||||
|     navigate(`import?projectId=${addProject.id}`); | ||||
|     if (Boolean(addProject)) { | ||||
|       setIsLoading(false); | ||||
|       navigate(`import?projectId=${addProject.id}`); | ||||
|     } else { | ||||
|       setIsLoading(false); | ||||
|       toast.error('Failed to create project'); | ||||
|     } | ||||
|   }, [client, repository]); | ||||
| 
 | ||||
|   return ( | ||||
| @ -53,9 +62,13 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => { | ||||
|         </div> | ||||
|         <p>{repository.updated_at && relativeTimeISO(repository.updated_at)}</p> | ||||
|       </div> | ||||
|       <div className="hidden group-hover:block"> | ||||
|         <IconButton size="sm">{'>'}</IconButton> | ||||
|       </div> | ||||
|       {isLoading ? ( | ||||
|         <Spinner className="h-4 w-4" /> | ||||
|       ) : ( | ||||
|         <div className="hidden group-hover:block"> | ||||
|           <IconButton size="sm">{'>'}</IconButton> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| @ -87,18 +87,12 @@ const DeploymentDetailsCard = ({ | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2"> | ||||
|       <div className="col-span-2"> | ||||
|     <div className="grid grid-cols-8 gap-2 border-b border-gray-300 p-3 my-2"> | ||||
|       <div className="col-span-3"> | ||||
|         <div className="flex"> | ||||
|           {deployment.url && ( | ||||
|             <Typography className=" basis-3/4">{deployment.url}</Typography> | ||||
|           )} | ||||
|           <Chip | ||||
|             value={deployment.status} | ||||
|             color={STATUS_COLORS[deployment.status] ?? 'gray'} | ||||
|             variant="ghost" | ||||
|             icon={<i>^</i>} | ||||
|           /> | ||||
|         </div> | ||||
|         <Typography color="gray"> | ||||
|           {deployment.environment === Environment.Production | ||||
| @ -107,13 +101,21 @@ const DeploymentDetailsCard = ({ | ||||
|         </Typography> | ||||
|       </div> | ||||
|       <div className="col-span-1"> | ||||
|         <Chip | ||||
|           value={deployment.status} | ||||
|           color={STATUS_COLORS[deployment.status] ?? 'gray'} | ||||
|           variant="ghost" | ||||
|           icon={<i>^</i>} | ||||
|         /> | ||||
|       </div> | ||||
|       <div className="col-span-2"> | ||||
|         <Typography color="gray">^ {deployment.branch}</Typography> | ||||
|         <Typography color="gray"> | ||||
|           ^ {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '} | ||||
|           {deployment.commitMessage} | ||||
|         </Typography> | ||||
|       </div> | ||||
|       <div className="col-span-1 flex items-center"> | ||||
|       <div className="col-span-2 flex items-center"> | ||||
|         <Typography color="gray" className="grow"> | ||||
|           ^ {relativeTimeMs(deployment.createdAt)} ^ {deployment.createdBy.name} | ||||
|         </Typography> | ||||
|  | ||||
| @ -44,18 +44,18 @@ const FilterForm = ({ value, onChange }: FilterFormProps) => { | ||||
|   }, [value]); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="grid grid-cols-4 gap-2 text-sm text-gray-600"> | ||||
|       <div className="col-span-2"> | ||||
|     <div className="grid grid-cols-8 gap-2 text-sm text-gray-600"> | ||||
|       <div className="col-span-4"> | ||||
|         <SearchBar | ||||
|           placeholder="Search branches" | ||||
|           value={searchedBranch} | ||||
|           onChange={(event) => setSearchedBranch(event.target.value)} | ||||
|         /> | ||||
|       </div> | ||||
|       <div className="col-span-1"> | ||||
|       <div className="col-span-2"> | ||||
|         <DatePicker mode="range" selected={dateRange} onSelect={setDateRange} /> | ||||
|       </div> | ||||
|       <div className="col-span-1 relative"> | ||||
|       <div className="col-span-2 relative"> | ||||
|         <Select | ||||
|           value={selectedStatus} | ||||
|           onChange={(value) => setSelectedStatus(value as StatusOptions)} | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| export const GIT_TEMPLATE_LINK = | ||||
|   'https://git.vdb.to/cerc-io/test-progressive-web-app'; | ||||
| export const GIT_TEMPLATE_LINK = `https://github.com/${process.env.REACT_APP_GITHUB_TEMPLATE_REPO}`; | ||||
| 
 | ||||
| export const SHORT_COMMIT_HASH_LENGTH = 8; | ||||
|  | ||||
| @ -1,13 +1,40 @@ | ||||
| import React from 'react'; | ||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||
| import { Outlet, useNavigate } from 'react-router-dom'; | ||||
| import { User } from 'gql-client'; | ||||
| 
 | ||||
| import { IconButton, Typography } from '@material-tailwind/react'; | ||||
| import { IconButton, Tooltip, Typography } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import HorizontalLine from '../components/HorizontalLine'; | ||||
| import ProjectSearchBar from '../components/projects/ProjectSearchBar'; | ||||
| import { useGQLClient } from '../context/GQLClientContext'; | ||||
| 
 | ||||
| const ProjectSearch = () => { | ||||
|   const navigate = useNavigate(); | ||||
|   const client = useGQLClient(); | ||||
|   const [user, setUser] = useState<User>(); | ||||
| 
 | ||||
|   const fetchUser = useCallback(async () => { | ||||
|     const { user } = await client.getUser(); | ||||
|     setUser(user); | ||||
|   }, []); | ||||
| 
 | ||||
|   const formattedAddress = useMemo(() => { | ||||
|     const address = user?.name || ''; | ||||
| 
 | ||||
|     if (address.length <= 8) { | ||||
|       return address; | ||||
|     } | ||||
| 
 | ||||
|     if (address.startsWith('0x')) { | ||||
|       return address.slice(0, 4) + '..' + address.slice(-4); | ||||
|     } | ||||
| 
 | ||||
|     return address; | ||||
|   }, [user?.name]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     fetchUser(); | ||||
|   }, []); | ||||
| 
 | ||||
|   return ( | ||||
|     <div> | ||||
| @ -28,8 +55,10 @@ const ProjectSearch = () => { | ||||
|           <div className="mr-2 flex items-center"> | ||||
|             <Typography>^</Typography> | ||||
|           </div> | ||||
|           <div className="px-2 py-1 bg-blue-gray-50 rounded-lg"> | ||||
|             <Typography variant="lead">SY</Typography> | ||||
|           <div className="px-2 py-1 bg-blue-gray-50 rounded-lg flex items-center"> | ||||
|             {user?.name && ( | ||||
|               <Tooltip content={user.name}>{formattedAddress}</Tooltip> | ||||
|             )} | ||||
|           </div> | ||||
|         </div> | ||||
|         <HorizontalLine /> | ||||
|  | ||||
| @ -50,7 +50,7 @@ const CreateWithTemplate = () => { | ||||
|         <div className="grow px-2">{template?.name}</div> | ||||
|         <div> | ||||
|           <a href={GIT_TEMPLATE_LINK} target="_blank" rel="noreferrer"> | ||||
|             ^ cerc-io/test-progressive-web-app | ||||
|             ^ {process.env.REACT_APP_GITHUB_TEMPLATE_REPO} | ||||
|           </a> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
| @ -4,7 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom'; | ||||
| import toast from 'react-hot-toast'; | ||||
| import assert from 'assert'; | ||||
| 
 | ||||
| import { Option, Typography } from '@material-tailwind/react'; | ||||
| import { Button, Option, Typography } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import { useOctokit } from '../../../../../context/OctokitContext'; | ||||
| import { useGQLClient } from '../../../../../context/GQLClientContext'; | ||||
| @ -27,10 +27,12 @@ const CreateRepo = () => { | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const [gitAccounts, setGitAccounts] = useState<string[]>([]); | ||||
|   const [isLoading, setIsLoading] = useState(false); | ||||
| 
 | ||||
|   const submitRepoHandler: SubmitHandler<SubmitRepoValues> = useCallback( | ||||
|     async (data) => { | ||||
|       assert(data.account); | ||||
|       setIsLoading(true); | ||||
| 
 | ||||
|       try { | ||||
|         assert( | ||||
| @ -62,11 +64,17 @@ const CreateRepo = () => { | ||||
|           template: 'webapp', | ||||
|         }); | ||||
| 
 | ||||
|         navigate( | ||||
|           `/${orgSlug}/projects/create/template/deploy?projectId=${addProject.id}`, | ||||
|         ); | ||||
|         if (Boolean(addProject)) { | ||||
|           setIsLoading(true); | ||||
|           navigate( | ||||
|             `/${orgSlug}/projects/create/template/deploy?projectId=${addProject.id}`, | ||||
|           ); | ||||
|         } else { | ||||
|           setIsLoading(false); | ||||
|         } | ||||
|       } catch (err) { | ||||
|         console.error(err); | ||||
|         setIsLoading(false); | ||||
|         toast.error('Error deploying project'); | ||||
|       } | ||||
|     }, | ||||
| @ -174,9 +182,14 @@ const CreateRepo = () => { | ||||
|         </label> | ||||
|       </div> | ||||
|       <div className="mb-2"> | ||||
|         <button className="bg-blue-500 rounded-xl p-2" type="submit"> | ||||
|         <Button | ||||
|           className="bg-blue-500 rounded-xl p-2" | ||||
|           type="submit" | ||||
|           disabled={isLoading} | ||||
|           loading={isLoading} | ||||
|         > | ||||
|           Deploy ^ | ||||
|         </button> | ||||
|         </Button> | ||||
|       </div> | ||||
|     </form> | ||||
|   ); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user