mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Show snapshots on events page (#3763)
* Add tabs to show snapshot or thumbnail as part of event details, even if event has a clip available. * Add ability for TextTab to render as disabled.
This commit is contained in:
		
							parent
							
								
									bdfe4a961a
								
							
						
					
					
						commit
						14faf0b2f6
					
				| @ -27,12 +27,14 @@ export function Tabs({ children, selectedIndex: selectedIndexProp, onChange, cla | |||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function TextTab({ selected, text, onClick }) { | export function TextTab({ selected, text, onClick, disabled }) { | ||||||
|   const selectedStyle = selected |   const selectedStyle = disabled | ||||||
|     ? 'text-white bg-blue-500 dark:text-black dark:bg-white' |     ? 'text-gray-400 dark:text-gray-600 bg-transparent' | ||||||
|     : 'text-black dark:text-white bg-transparent'; |     : selected | ||||||
|  |       ? 'text-white bg-blue-500 dark:text-black dark:bg-white' | ||||||
|  |       : 'text-black dark:text-white bg-transparent'; | ||||||
|   return ( |   return ( | ||||||
|     <button onClick={onClick} className={`rounded-full px-4 py-2 ${selectedStyle}`}> |     <button onClick={onClick} disabled={disabled} className={`rounded-full px-4 py-2 ${selectedStyle}`}> | ||||||
|       <span>{text}</span> |       <span>{text}</span> | ||||||
|     </button> |     </button> | ||||||
|   ); |   ); | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ import { h, Fragment } from 'preact'; | |||||||
| import { route } from 'preact-router'; | import { route } from 'preact-router'; | ||||||
| import ActivityIndicator from '../components/ActivityIndicator'; | import ActivityIndicator from '../components/ActivityIndicator'; | ||||||
| import Heading from '../components/Heading'; | import Heading from '../components/Heading'; | ||||||
|  | import { Tabs, TextTab } from '../components/Tabs'; | ||||||
| import { useApiHost } from '../api'; | import { useApiHost } from '../api'; | ||||||
| import useSWR from 'swr'; | import useSWR from 'swr'; | ||||||
| import useSWRInfinite from 'swr/infinite'; | import useSWRInfinite from 'swr/infinite'; | ||||||
| @ -54,6 +55,7 @@ export default function Events({ path, ...props }) { | |||||||
|   }); |   }); | ||||||
|   const [uploading, setUploading] = useState([]); |   const [uploading, setUploading] = useState([]); | ||||||
|   const [viewEvent, setViewEvent] = useState(); |   const [viewEvent, setViewEvent] = useState(); | ||||||
|  |   const [eventDetailType, setEventDetailType] = useState('clip'); | ||||||
|   const [downloadEvent, setDownloadEvent] = useState({ |   const [downloadEvent, setDownloadEvent] = useState({ | ||||||
|     id: null, |     id: null, | ||||||
|     has_clip: false, |     has_clip: false, | ||||||
| @ -235,6 +237,10 @@ export default function Events({ path, ...props }) { | |||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   const handleEventDetailTabChange = (index) => { | ||||||
|  |     setEventDetailType(index == 0 ? 'clip' : 'image'); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   if (!config) { |   if (!config) { | ||||||
|     return <ActivityIndicator />; |     return <ActivityIndicator />; | ||||||
|   } |   } | ||||||
| @ -495,9 +501,15 @@ export default function Events({ path, ...props }) { | |||||||
|                   {viewEvent !== event.id ? null : ( |                   {viewEvent !== event.id ? null : ( | ||||||
|                     <div className="space-y-4"> |                     <div className="space-y-4"> | ||||||
|                       <div className="mx-auto max-w-7xl"> |                       <div className="mx-auto max-w-7xl"> | ||||||
|                         {event.has_clip ? ( |                         <div className='flex justify-center w-full py-2'> | ||||||
|                           <> |                           <Tabs selectedIndex={event.has_clip && eventDetailType == 'clip' ? 0 : 1} onChange={handleEventDetailTabChange} className='justify'> | ||||||
|                             <Heading size="lg">Clip</Heading> |                             <TextTab text='Clip' disabled={!event.has_clip} /> | ||||||
|  |                             <TextTab text={event.has_snapshot ? 'Snapshot' : 'Thumbnail'} /> | ||||||
|  |                           </Tabs> | ||||||
|  |                         </div> | ||||||
|  | 
 | ||||||
|  |                         <div> | ||||||
|  |                           {((eventDetailType == 'clip') && event.has_clip) ? ( | ||||||
|                             <VideoPlayer |                             <VideoPlayer | ||||||
|                               options={{ |                               options={{ | ||||||
|                                 preload: 'auto', |                                 preload: 'auto', | ||||||
| @ -512,23 +524,22 @@ export default function Events({ path, ...props }) { | |||||||
|                               seekOptions={{ forward: 10, back: 5 }} |                               seekOptions={{ forward: 10, back: 5 }} | ||||||
|                               onReady={() => {}} |                               onReady={() => {}} | ||||||
|                             /> |                             /> | ||||||
|                           </> |                           ) : null } | ||||||
|                         ) : ( | 
 | ||||||
|                           <div className="flex justify-center"> |                           {((eventDetailType == 'image') || !event.has_clip) ? ( | ||||||
|                             <div> |                             <div className="flex justify-center"> | ||||||
|                               <Heading size="sm">{event.has_snapshot ? 'Best Image' : 'Thumbnail'}</Heading> |  | ||||||
|                               <img |                               <img | ||||||
|                                 className="flex-grow-0" |                                 className="flex-grow-0" | ||||||
|                                 src={ |                                 src={ | ||||||
|                                   event.has_snapshot |                                   event.has_snapshot | ||||||
|                                     ? `${apiHost}/api/events/${event.id}/snapshot.jpg` |                                     ? `${apiHost}/api/events/${event.id}/snapshot.jpg` | ||||||
|                                     : `data:image/jpeg;base64,${event.thumbnail}` |                                     : `${apiHost}/api/events/${event.id}/thumbnail.jpg` | ||||||
|                                 } |                                 } | ||||||
|                                 alt={`${event.label} at ${(event.top_score * 100).toFixed(0)}% confidence`} |                                 alt={`${event.label} at ${(event.top_score * 100).toFixed(0)}% confidence`} | ||||||
|                               /> |                               /> | ||||||
|                             </div> |                             </div> | ||||||
|                           </div> |                           ) : null } | ||||||
|                         )} |                         </div> | ||||||
|                       </div> |                       </div> | ||||||
|                     </div> |                     </div> | ||||||
|                   )} |                   )} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user