mirror of
				https://github.com/snowball-tools/snowballtools-base.git
				synced 2025-10-31 20:04:06 +00:00 
			
		
		
		
	Filter deployments with status options (#15)
This commit is contained in:
		
							parent
							
								
									cfb299c79e
								
							
						
					
					
						commit
						318ebdfd26
					
				| @ -1,16 +1,10 @@ | ||||
| import React, { ChangeEventHandler, forwardRef } from 'react'; | ||||
| import React, { forwardRef } from 'react'; | ||||
| 
 | ||||
| import { Input } from '@material-tailwind/react'; | ||||
| 
 | ||||
| interface SearchBarProps { | ||||
|   onChange?: ChangeEventHandler<HTMLInputElement>; | ||||
|   value?: string; | ||||
|   placeholder?: string; | ||||
| } | ||||
| import { Input, InputProps } from '@material-tailwind/react'; | ||||
| 
 | ||||
| const SearchBar: React.ForwardRefRenderFunction< | ||||
|   HTMLInputElement, | ||||
|   SearchBarProps | ||||
|   InputProps | ||||
| > = ({ value, onChange, placeholder = 'Search', ...props }, ref) => { | ||||
|   return ( | ||||
|     <div className="relative flex w-full gap-2"> | ||||
| @ -28,8 +22,8 @@ const SearchBar: React.ForwardRefRenderFunction< | ||||
|         }} | ||||
|         // TODO: Debug issue: https://github.com/creativetimofficial/material-tailwind/issues/427
 | ||||
|         crossOrigin={undefined} | ||||
|         ref={ref} | ||||
|         {...props} | ||||
|         ref={ref} | ||||
|       /> | ||||
|       <div className="!absolute left-3 top-[13px]"> | ||||
|         <i>^</i> | ||||
|  | ||||
| @ -1,60 +1,47 @@ | ||||
| import React, { useCallback, useMemo, useState } from 'react'; | ||||
| 
 | ||||
| import { Button } from '@material-tailwind/react'; | ||||
| import { Button, Typography } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import deploymentData from '../../../assets/deployments.json'; | ||||
| import DeployDetailsCard from './DeploymentDetailsCard'; | ||||
| import Dropdown from '../../Dropdown'; | ||||
| import SearchBar from '../../SearchBar'; | ||||
| import DeployDetailsCard from './deployments/DeploymentDetailsCard'; | ||||
| import FilterForm, { StatusOptions } from './deployments/FilterForm'; | ||||
| 
 | ||||
| const STATUS_OPTIONS = [ | ||||
|   { value: 'building', label: 'Building' }, | ||||
|   { value: 'ready', label: 'Ready' }, | ||||
|   { value: 'error', label: 'Error' }, | ||||
| ]; | ||||
| const DEFAULT_FILTER_VALUE = { | ||||
|   searchedBranch: '', | ||||
|   status: 'All status', | ||||
| }; | ||||
| 
 | ||||
| const DeploymentsTabPanel = () => { | ||||
|   const [searchedBranch, setSearchedBranch] = useState(''); | ||||
|   const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE); | ||||
| 
 | ||||
|   const filteredDeployments = useMemo(() => { | ||||
|     if (searchedBranch) { | ||||
|       return deploymentData.filter((deployment) => | ||||
|         deployment.branch.toLowerCase().includes(searchedBranch.toLowerCase()), | ||||
|       ); | ||||
|     } | ||||
|     return deploymentData.filter((deployment) => { | ||||
|       // Searched branch filter
 | ||||
|       const branchMatch = | ||||
|         !filterValue.searchedBranch || | ||||
|         deployment.branch | ||||
|           .toLowerCase() | ||||
|           .includes(filterValue.searchedBranch.toLowerCase()); | ||||
| 
 | ||||
|     return deploymentData; | ||||
|   }, [searchedBranch]); | ||||
|       // Status filter
 | ||||
|       const statusMatch = | ||||
|         filterValue.status === StatusOptions.ALL_STATUS || | ||||
|         deployment.status === filterValue.status; | ||||
| 
 | ||||
|       return branchMatch && statusMatch; | ||||
|     }); | ||||
|   }, [filterValue]); | ||||
| 
 | ||||
|   const handleResetFilters = useCallback(() => { | ||||
|     setSearchedBranch(''); | ||||
|     setFilterValue(DEFAULT_FILTER_VALUE); | ||||
|   }, []); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="p-4"> | ||||
|       <div className="grid grid-cols-4 gap-2 text-sm text-gray-600"> | ||||
|         <div className="col-span-2"> | ||||
|           <SearchBar | ||||
|             placeholder="Search branches" | ||||
|             value={searchedBranch} | ||||
|             onChange={(event) => setSearchedBranch(event.target.value)} | ||||
|           /> | ||||
|         </div> | ||||
|         <div className="col-span-1"> | ||||
|           <input | ||||
|             type="text" | ||||
|             className="border border-gray-300 rounded p-2 w-full focus:border-blue-300 focus:outline-none focus:shadow-outline-blue" | ||||
|             placeholder="All time" | ||||
|           /> | ||||
|         </div> | ||||
|         <div className="col-span-1"> | ||||
|           <Dropdown | ||||
|             placeholder="All status" | ||||
|             options={STATUS_OPTIONS} | ||||
|             onChange={() => {}} | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <FilterForm | ||||
|         value={filterValue} | ||||
|         onChange={(value) => setFilterValue(value)} | ||||
|       /> | ||||
|       <div className="mt-2"> | ||||
|         {Boolean(filteredDeployments.length) ? ( | ||||
|           filteredDeployments.map((deployment, key) => { | ||||
| @ -63,8 +50,10 @@ const DeploymentsTabPanel = () => { | ||||
|         ) : ( | ||||
|           <div className="h-[50vh] bg-gray-100 flex rounded items-center justify-center"> | ||||
|             <div className="text-center"> | ||||
|               <h5 className="text-lg font-bold">No deployments found</h5> | ||||
|               <p>Please change your search query or filters</p> | ||||
|               <Typography variant="h5">No deployments found</Typography> | ||||
|               <Typography> | ||||
|                 Please change your search query or filters | ||||
|               </Typography> | ||||
|               <Button | ||||
|                 className="rounded-full mt-5" | ||||
|                 color="white" | ||||
|  | ||||
| @ -7,7 +7,7 @@ import { | ||||
|   MenuItem, | ||||
| } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import { relativeTime } from '../../../utils/time'; | ||||
| import { relativeTime } from '../../../../utils/time'; | ||||
| 
 | ||||
| interface DeploymentDetails { | ||||
|   title: string; | ||||
| @ -0,0 +1,77 @@ | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| 
 | ||||
| import { Option, Select } from '@material-tailwind/react'; | ||||
| 
 | ||||
| import SearchBar from '../../../SearchBar'; | ||||
| 
 | ||||
| export enum StatusOptions { | ||||
|   ALL_STATUS = 'All status', | ||||
|   BUILDING = 'Building', | ||||
|   READY = 'Ready', | ||||
|   ERROR = 'Error', | ||||
| } | ||||
| 
 | ||||
| interface FilterValue { | ||||
|   searchedBranch: string; | ||||
|   status: string; | ||||
| } | ||||
| 
 | ||||
| interface FilterFormProps { | ||||
|   value: FilterValue; | ||||
|   onChange: (value: FilterValue) => void; | ||||
| } | ||||
| 
 | ||||
| const FilterForm = ({ value, onChange }: FilterFormProps) => { | ||||
|   const [searchedBranch, setSearchedBranch] = useState(value.searchedBranch); | ||||
|   const [selectedStatus, setSelectedStatus] = useState(value.status); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     onChange({ | ||||
|       searchedBranch, | ||||
|       status: selectedStatus, | ||||
|     }); | ||||
|   }, [searchedBranch, selectedStatus]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setSearchedBranch(value.searchedBranch); | ||||
|     setSelectedStatus(value.status); | ||||
|   }, [value]); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="grid grid-cols-4 gap-2 text-sm text-gray-600"> | ||||
|       <div className="col-span-2"> | ||||
|         <SearchBar | ||||
|           placeholder="Search branches" | ||||
|           value={searchedBranch} | ||||
|           onChange={(event) => setSearchedBranch(event.target.value)} | ||||
|         /> | ||||
|       </div> | ||||
|       <div className="col-span-1"> | ||||
|         <input | ||||
|           type="text" | ||||
|           className="border border-gray-300 rounded p-2 w-full focus:border-blue-300 focus:outline-none focus:shadow-outline-blue" | ||||
|           placeholder="All time" | ||||
|         /> | ||||
|       </div> | ||||
|       <div className="col-span-1"> | ||||
|         <Select | ||||
|           value={selectedStatus} | ||||
|           onChange={(value) => setSelectedStatus(value!)} | ||||
|           label="Select Version" | ||||
|         > | ||||
|           {Object.values(StatusOptions).map((status) => ( | ||||
|             <Option | ||||
|               className={status === selectedStatus ? 'hidden' : ''} | ||||
|               key={status} | ||||
|               value={status} | ||||
|             > | ||||
|               ^ {status} | ||||
|             </Option> | ||||
|           ))} | ||||
|         </Select> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default FilterForm; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user