mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Add download chips to search item details video and snapshot panes (#14525)
This commit is contained in:
		
							parent
							
								
									e4048be088
								
							
						
					
					
						commit
						fc59c83e16
					
				| @ -4,17 +4,20 @@ import { toast } from "sonner"; | ||||
| import ActivityIndicator from "../indicators/activity-indicator"; | ||||
| import { FaDownload } from "react-icons/fa"; | ||||
| import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; | ||||
| import { cn } from "@/lib/utils"; | ||||
| 
 | ||||
| type DownloadVideoButtonProps = { | ||||
|   source: string; | ||||
|   camera: string; | ||||
|   startTime: number; | ||||
|   className?: string; | ||||
| }; | ||||
| 
 | ||||
| export function DownloadVideoButton({ | ||||
|   source, | ||||
|   camera, | ||||
|   startTime, | ||||
|   className, | ||||
| }: DownloadVideoButtonProps) { | ||||
|   const [isDownloading, setIsDownloading] = useState(false); | ||||
| 
 | ||||
| @ -32,13 +35,6 @@ export function DownloadVideoButton({ | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDownloadEnd = () => { | ||||
|     setIsDownloading(false); | ||||
|     toast.success("Download completed successfully.", { | ||||
|       position: "top-center", | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex justify-center"> | ||||
|       <Button | ||||
| @ -48,16 +44,13 @@ export function DownloadVideoButton({ | ||||
|         size="sm" | ||||
|         aria-label="Download Video" | ||||
|       > | ||||
|         <a | ||||
|           href={source} | ||||
|           download={filename} | ||||
|           onClick={handleDownloadStart} | ||||
|           onBlur={handleDownloadEnd} | ||||
|         > | ||||
|         <a href={source} download={filename} onClick={handleDownloadStart}> | ||||
|           {isDownloading ? ( | ||||
|             <ActivityIndicator className="size-4" /> | ||||
|           ) : ( | ||||
|             <FaDownload className="size-4 text-secondary-foreground" /> | ||||
|             <FaDownload | ||||
|               className={cn("size-4 text-secondary-foreground", className)} | ||||
|             /> | ||||
|           )} | ||||
|         </a> | ||||
|       </Button> | ||||
|  | ||||
| @ -27,6 +27,7 @@ import ActivityIndicator from "@/components/indicators/activity-indicator"; | ||||
| import { | ||||
|   FaCheckCircle, | ||||
|   FaChevronDown, | ||||
|   FaDownload, | ||||
|   FaHistory, | ||||
|   FaImage, | ||||
|   FaRegListAlt, | ||||
| @ -68,6 +69,7 @@ import { | ||||
|   PopoverTrigger, | ||||
| } from "@/components/ui/popover"; | ||||
| import { LuInfo } from "react-icons/lu"; | ||||
| import { TooltipPortal } from "@radix-ui/react-tooltip"; | ||||
| 
 | ||||
| const SEARCH_TABS = [ | ||||
|   "details", | ||||
| @ -577,16 +579,39 @@ function ObjectSnapshotTab({ | ||||
|               }} | ||||
|             > | ||||
|               {search?.id && ( | ||||
|                 <img | ||||
|                   ref={imgRef} | ||||
|                   className={`mx-auto max-h-[60dvh] bg-black object-contain`} | ||||
|                   src={`${baseUrl}api/events/${search?.id}/snapshot.jpg`} | ||||
|                   alt={`${search?.label}`} | ||||
|                   loading={isSafari ? "eager" : "lazy"} | ||||
|                   onLoad={() => { | ||||
|                     onImgLoad(); | ||||
|                   }} | ||||
|                 /> | ||||
|                 <div className="relative mx-auto"> | ||||
|                   <img | ||||
|                     ref={imgRef} | ||||
|                     className={`mx-auto max-h-[60dvh] bg-black object-contain`} | ||||
|                     src={`${baseUrl}api/events/${search?.id}/snapshot.jpg`} | ||||
|                     alt={`${search?.label}`} | ||||
|                     loading={isSafari ? "eager" : "lazy"} | ||||
|                     onLoad={() => { | ||||
|                       onImgLoad(); | ||||
|                     }} | ||||
|                   /> | ||||
|                   <div | ||||
|                     className={cn( | ||||
|                       "absolute right-1 top-1 flex items-center gap-2", | ||||
|                     )} | ||||
|                   > | ||||
|                     <Tooltip> | ||||
|                       <TooltipTrigger asChild> | ||||
|                         <a | ||||
|                           download | ||||
|                           href={`${baseUrl}api/events/${search?.id}/snapshot.jpg`} | ||||
|                         > | ||||
|                           <Chip className="cursor-pointer rounded-md bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500"> | ||||
|                             <FaDownload className="size-4 text-white" /> | ||||
|                           </Chip> | ||||
|                         </a> | ||||
|                       </TooltipTrigger> | ||||
|                       <TooltipPortal> | ||||
|                         <TooltipContent>Download</TooltipContent> | ||||
|                       </TooltipPortal> | ||||
|                     </Tooltip> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               )} | ||||
|             </TransformComponent> | ||||
|             {search.plus_id !== "not_enabled" && search.end_time && ( | ||||
| @ -669,7 +694,7 @@ export function VideoTab({ search }: VideoTabProps) { | ||||
|       {reviewItem && ( | ||||
|         <div | ||||
|           className={cn( | ||||
|             "absolute top-2 z-10 flex items-center", | ||||
|             "absolute top-2 z-10 flex items-center gap-2", | ||||
|             isIOS ? "right-8" : "right-2", | ||||
|           )} | ||||
|         > | ||||
| @ -689,7 +714,24 @@ export function VideoTab({ search }: VideoTabProps) { | ||||
|                 <FaHistory className="size-4 text-white" /> | ||||
|               </Chip> | ||||
|             </TooltipTrigger> | ||||
|             <TooltipContent side="left">View in History</TooltipContent> | ||||
|             <TooltipPortal> | ||||
|               <TooltipContent>View in History</TooltipContent> | ||||
|             </TooltipPortal> | ||||
|           </Tooltip> | ||||
|           <Tooltip> | ||||
|             <TooltipTrigger asChild> | ||||
|               <a | ||||
|                 download | ||||
|                 href={`${baseUrl}api/${search.camera}/start/${search.start_time}/end/${endTime}/clip.mp4`} | ||||
|               > | ||||
|                 <Chip className="cursor-pointer rounded-md bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500"> | ||||
|                   <FaDownload className="size-4 text-white" /> | ||||
|                 </Chip> | ||||
|               </a> | ||||
|             </TooltipTrigger> | ||||
|             <TooltipPortal> | ||||
|               <TooltipContent>Download</TooltipContent> | ||||
|             </TooltipPortal> | ||||
|           </Tooltip> | ||||
|         </div> | ||||
|       )} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user