mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +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-gray-400 dark:text-gray-600 bg-transparent'
|
||||||
|
: selected
|
||||||
? 'text-white bg-blue-500 dark:text-black dark:bg-white'
|
? 'text-white bg-blue-500 dark:text-black dark:bg-white'
|
||||||
: 'text-black dark:text-white bg-transparent';
|
: '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 }
|
||||||
) : (
|
|
||||||
|
{((eventDetailType == 'image') || !event.has_clip) ? (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div>
|
|
||||||
<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>
|
||||||
|
) : null }
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
Loading…
Reference in New Issue
Block a user