mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-02 09:15:22 +03:00
re-arrange
This commit is contained in:
parent
3527c1f14a
commit
e2bee3ab94
@ -1,5 +1,5 @@
|
|||||||
import { h, Fragment } from 'preact';
|
import { h, Fragment } from 'preact';
|
||||||
import { useCallback, useState, useEffect } from 'preact/hooks';
|
import { useCallback, useState, useEffect, useRef } from 'preact/hooks';
|
||||||
import ActivityIndicator from '../components/ActivityIndicator';
|
import ActivityIndicator from '../components/ActivityIndicator';
|
||||||
import Button from '../components/Button';
|
import Button from '../components/Button';
|
||||||
import Clip from '../icons/Clip';
|
import Clip from '../icons/Clip';
|
||||||
@ -18,6 +18,7 @@ export default function Event({ eventId, close, scrollRef }) {
|
|||||||
const [shouldScroll, setShouldScroll] = useState(true);
|
const [shouldScroll, setShouldScroll] = useState(true);
|
||||||
const [deleteStatus, setDeleteStatus] = useState(FetchStatus.NONE);
|
const [deleteStatus, setDeleteStatus] = useState(FetchStatus.NONE);
|
||||||
const setDeleteEvent = useDelete();
|
const setDeleteEvent = useDelete();
|
||||||
|
const eventRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Scroll event into view when component has been mounted.
|
// Scroll event into view when component has been mounted.
|
||||||
@ -27,6 +28,21 @@ export default function Event({ eventId, close, scrollRef }) {
|
|||||||
}
|
}
|
||||||
}, [data, scrollRef, eventId, shouldScroll]);
|
}, [data, scrollRef, eventId, shouldScroll]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// const checkIfClickedOutside = (e) => {
|
||||||
|
// // If the event is open and the clicked target is not within the event window or delete modal,
|
||||||
|
// // then close the menu
|
||||||
|
// if (!showDialog && eventRef.current && !eventRef.current.contains(e.target)) {
|
||||||
|
// close(null);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// document.addEventListener('mousedown', checkIfClickedOutside);
|
||||||
|
// return () => {
|
||||||
|
// // Cleanup the
|
||||||
|
// document.removeEventListener('mousedown', checkIfClickedOutside);
|
||||||
|
// };
|
||||||
|
// }, [close, showDialog]);
|
||||||
|
|
||||||
const handleClickDelete = () => {
|
const handleClickDelete = () => {
|
||||||
setShowDialog(true);
|
setShowDialog(true);
|
||||||
};
|
};
|
||||||
@ -55,7 +71,7 @@ export default function Event({ eventId, close, scrollRef }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4" ref={eventRef}>
|
||||||
<div className="grid grid-cols-6 gap-4">
|
<div className="grid grid-cols-6 gap-4">
|
||||||
<div class="col-start-1 col-end-8 md:space-x-4">
|
<div class="col-start-1 col-end-8 md:space-x-4">
|
||||||
<Button color="blue" href={`${apiHost}/api/events/${eventId}/clip.mp4?download=true`} download>
|
<Button color="blue" href={`${apiHost}/api/events/${eventId}/clip.mp4?download=true`} download>
|
||||||
|
|||||||
@ -1,39 +1,30 @@
|
|||||||
import { h, Fragment } from 'preact';
|
import { h, Fragment } from 'preact';
|
||||||
import { useCallback, useEffect, useState, useRef } from 'preact/hooks';
|
import { memo } from 'preact/compat';
|
||||||
|
import { useCallback, useState } from 'preact/hooks';
|
||||||
import { Tr, Td } from '../../../components/Table';
|
import { Tr, Td } from '../../../components/Table';
|
||||||
import Filterable from './filterable';
|
import Filterable from './filterable';
|
||||||
import Event from '../../Event';
|
import Event from '../../Event';
|
||||||
|
|
||||||
import { memo } from 'preact/compat';
|
|
||||||
import { useSearchString } from '../hooks/useSearchString';
|
|
||||||
|
|
||||||
const EventsRow = memo(
|
const EventsRow = memo(
|
||||||
(
|
({
|
||||||
{
|
|
||||||
id,
|
id,
|
||||||
apiHost,
|
apiHost,
|
||||||
start_time: startTime,
|
start_time: startTime,
|
||||||
end_time: endTime,
|
end_time: endTime,
|
||||||
handleFilter,
|
|
||||||
reachedEnd,
|
reachedEnd,
|
||||||
scrollToRef,
|
scrollToRef,
|
||||||
|
searchString,
|
||||||
|
lastRowRef,
|
||||||
|
handleFilter,
|
||||||
pathname,
|
pathname,
|
||||||
searchParams,
|
searchParams,
|
||||||
camera,
|
camera,
|
||||||
label,
|
label,
|
||||||
score,
|
top_score: score,
|
||||||
zones,
|
zones,
|
||||||
numberOfEvents,
|
|
||||||
idx,
|
|
||||||
searchString,
|
|
||||||
lastCellRef,
|
|
||||||
removeDefaultSearchKeys,
|
removeDefaultSearchKeys,
|
||||||
},
|
}) => {
|
||||||
i
|
|
||||||
) => {
|
|
||||||
const [viewEvent, setViewEvent] = useState(null);
|
const [viewEvent, setViewEvent] = useState(null);
|
||||||
// const [searchString, setSearchString, removeDefaultSearchKeys] = useSearchString(limit);
|
|
||||||
// const ref = useRef();
|
|
||||||
|
|
||||||
const viewEventHandler = useCallback(
|
const viewEventHandler = useCallback(
|
||||||
(id) => {
|
(id) => {
|
||||||
@ -46,32 +37,19 @@ const EventsRow = memo(
|
|||||||
[viewEvent]
|
[viewEvent]
|
||||||
);
|
);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// const checkIfClickedOutside = (e) => {
|
|
||||||
// // If the menu is open and the clicked target is not within the menu,
|
|
||||||
// // then close the menu
|
|
||||||
// if (viewEvent && ref.current && !ref.current.contains(e.target)) {
|
|
||||||
// setViewEvent(null);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// document.addEventListener('mousedown', checkIfClickedOutside);
|
|
||||||
// return () => {
|
|
||||||
// // Cleanup the event listener
|
|
||||||
// document.removeEventListener('mousedown', checkIfClickedOutside);
|
|
||||||
// };
|
|
||||||
// }, [setViewEvent, viewEvent]);
|
|
||||||
|
|
||||||
const start = new Date(parseInt(startTime * 1000, 10));
|
const start = new Date(parseInt(startTime * 1000, 10));
|
||||||
const end = new Date(parseInt(endTime * 1000, 10));
|
const end = new Date(parseInt(endTime * 1000, 10));
|
||||||
const ref = idx === numberOfEvents - 1 ? lastCellRef : undefined;
|
console.log('tablerow has been rendered');
|
||||||
|
|
||||||
console.log('table row renders');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={id}>
|
<Fragment key={id}>
|
||||||
<Tr data-testid={`event-${id}`} className={`${viewEvent === id ? 'border-none' : ''}`}>
|
<Tr data-testid={`event-${id}`} className={`${viewEvent === id ? 'border-none' : ''}`}>
|
||||||
<Td className="w-40">
|
<Td className="w-40">
|
||||||
<a onClick={() => viewEventHandler(id)} ref={ref} data-start-time={startTime} data-reached-end={reachedEnd}>
|
<a
|
||||||
|
onClick={() => viewEventHandler(id)}
|
||||||
|
ref={lastRowRef}
|
||||||
|
data-start-time={startTime}
|
||||||
|
data-reached-end={reachedEnd}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
ref={(el) => (scrollToRef[id] = el)}
|
ref={(el) => (scrollToRef[id] = el)}
|
||||||
width="150"
|
width="150"
|
||||||
@ -131,36 +109,6 @@ const EventsRow = memo(
|
|||||||
</Tr>
|
</Tr>
|
||||||
) : null}
|
) : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
// <Fragment>
|
|
||||||
// <Tr>
|
|
||||||
// <Td className="w-40">
|
|
||||||
// <a
|
|
||||||
// onClick={() => viewEventHandler(id)}
|
|
||||||
// ref={lastCellRef}
|
|
||||||
// data-start-time={startTime}
|
|
||||||
// data-reached-end={reachedEnd}
|
|
||||||
// >
|
|
||||||
// <img
|
|
||||||
// ref={(el) => (scrollToRef[id] = el)}
|
|
||||||
// width="150"
|
|
||||||
// height="150"
|
|
||||||
// className="cursor-pointer"
|
|
||||||
// style="min-height: 48px; min-width: 48px;"
|
|
||||||
// src={`${apiHost}/api/events/${id}/thumbnail.jpg`}
|
|
||||||
// />
|
|
||||||
// </a>
|
|
||||||
// </Td>
|
|
||||||
// {viewEvent === id ? (
|
|
||||||
// <span ref={ref}>
|
|
||||||
// <Tr className="border-b-1">
|
|
||||||
// <Td colSpan="8">
|
|
||||||
// <Event eventId={id} close={() => setViewEvent(null)} scrollRef={scrollToRef} />
|
|
||||||
// </Td>
|
|
||||||
// </Tr>
|
|
||||||
// </span>
|
|
||||||
// ) : null}
|
|
||||||
// </Tr>
|
|
||||||
// </Fragment>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import { h } from 'preact';
|
|
||||||
import { useState, useCallback } from 'preact/hooks';
|
import { useState, useCallback } from 'preact/hooks';
|
||||||
|
|
||||||
const defaultSearchString = (limit) => `include_thumbnails=0&limit=${limit}`;
|
const defaultSearchString = (limit) => `include_thumbnails=0&limit=${limit}`;
|
||||||
|
|
||||||
export const useSearchString = (limit, searchParams) => {
|
export const useSearchString = (limit, searchParams) => {
|
||||||
const { searchParams: initialSearchParams } = new URL(window.location);
|
const { searchParams: initialSearchParams } = new URL(window.location);
|
||||||
const _searchParams = searchParams ? searchParams : initialSearchParams.toString();
|
const _searchParams = searchParams || initialSearchParams.toString();
|
||||||
|
|
||||||
const [searchString, setSearchString] = useState(`${defaultSearchString(limit)}&${_searchParams}`);
|
const [searchString, setSearchString] = useState(`${defaultSearchString(limit)}&${_searchParams}`);
|
||||||
|
|
||||||
@ -13,17 +12,14 @@ export const useSearchString = (limit, searchParams) => {
|
|||||||
(limit, searchString) => {
|
(limit, searchString) => {
|
||||||
setSearchString(`${defaultSearchString(limit)}&${searchString}`);
|
setSearchString(`${defaultSearchString(limit)}&${searchString}`);
|
||||||
},
|
},
|
||||||
[setSearchString, defaultSearchString]
|
[setSearchString]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeDefaultSearchKeys = useCallback(
|
const removeDefaultSearchKeys = useCallback((searchParams) => {
|
||||||
(searchParams) => {
|
|
||||||
searchParams.delete('limit');
|
searchParams.delete('limit');
|
||||||
searchParams.delete('include_thumbnails');
|
searchParams.delete('include_thumbnails');
|
||||||
searchParams.delete('before');
|
searchParams.delete('before');
|
||||||
},
|
}, []);
|
||||||
[searchParams]
|
|
||||||
);
|
|
||||||
|
|
||||||
return [searchString, changeSearchString, removeDefaultSearchKeys];
|
return [searchString, changeSearchString, removeDefaultSearchKeys];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { h, Fragment } from 'preact';
|
import { h } from 'preact';
|
||||||
import ActivityIndicator from '../../components/ActivityIndicator';
|
import ActivityIndicator from '../../components/ActivityIndicator';
|
||||||
import Heading from '../../components/Heading';
|
import Heading from '../../components/Heading';
|
||||||
import { TableHead, Filters } from './components';
|
import { TableHead, Filters } from './components';
|
||||||
@ -22,7 +22,7 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
|||||||
const { data, status, deletedId } = useEvents(searchString);
|
const { data, status, deletedId } = useEvents(searchString);
|
||||||
const [counter, setCounter] = useState(0);
|
const [counter, setCounter] = useState(0);
|
||||||
|
|
||||||
let scrollToRef = useMemo(() => Object, []);
|
const scrollToRef = useMemo(() => Object, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && !(searchString in searchStrings)) {
|
if (data && !(searchString in searchStrings)) {
|
||||||
@ -38,23 +38,17 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
|||||||
}
|
}
|
||||||
}, [data, limit, searchString, searchStrings, deleted, deletedId]);
|
}, [data, limit, searchString, searchStrings, deleted, deletedId]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setInterval(() => {
|
|
||||||
setCounter((prev) => prev + 1);
|
|
||||||
}, 1000);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleFilter = useCallback(
|
|
||||||
(searchParams) => {
|
|
||||||
dispatch({ type: 'RESET' });
|
|
||||||
removeDefaultSearchKeys(searchParams);
|
|
||||||
setSearchString(limit, searchParams.toString());
|
|
||||||
route(`${pathname}?${searchParams.toString()}`);
|
|
||||||
},
|
|
||||||
[limit, pathname, setSearchString, removeDefaultSearchKeys]
|
|
||||||
);
|
|
||||||
const [entry, setIntersectNode] = useIntersectionObserver();
|
const [entry, setIntersectNode] = useIntersectionObserver();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (entry && entry.isIntersecting) {
|
||||||
|
const { startTime } = entry.target.dataset;
|
||||||
|
const { searchParams } = new URL(window.location);
|
||||||
|
searchParams.set('before', parseFloat(startTime) - 0.0001);
|
||||||
|
setSearchString(limit, searchParams.toString());
|
||||||
|
}
|
||||||
|
}, [entry, limit, setSearchString]);
|
||||||
|
|
||||||
const lastCellRef = useCallback(
|
const lastCellRef = useCallback(
|
||||||
(node) => {
|
(node) => {
|
||||||
if (node !== null && !reachedEnd) {
|
if (node !== null && !reachedEnd) {
|
||||||
@ -64,17 +58,54 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
|||||||
[setIntersectNode, reachedEnd]
|
[setIntersectNode, reachedEnd]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const handleFilter = useCallback(
|
||||||
if (entry && entry.isIntersecting) {
|
(searchParams) => {
|
||||||
const { startTime } = entry.target.dataset;
|
dispatch({ type: 'RESET' });
|
||||||
const { searchParams } = new URL(window.location);
|
removeDefaultSearchKeys(searchParams);
|
||||||
searchParams.set('before', parseFloat(startTime) - 0.0001);
|
|
||||||
setSearchString(limit, searchParams.toString());
|
setSearchString(limit, searchParams.toString());
|
||||||
}
|
route(`${pathname}?${searchParams.toString()}`);
|
||||||
}, [entry, limit]);
|
},
|
||||||
|
[limit, pathname, setSearchString, removeDefaultSearchKeys]
|
||||||
|
);
|
||||||
|
|
||||||
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
||||||
|
|
||||||
console.log('counter ' + counter);
|
const RenderTableRow = useCallback(
|
||||||
|
(props) => (
|
||||||
|
<TableRow
|
||||||
|
key={props.id}
|
||||||
|
apiHost={apiHost}
|
||||||
|
scrollToRef={scrollToRef}
|
||||||
|
reachedEnd={reachedEnd}
|
||||||
|
setSearchString={setSearchString}
|
||||||
|
pathname={pathname}
|
||||||
|
searchParams={searchParams}
|
||||||
|
limit={API_LIMIT}
|
||||||
|
searchString={searchString}
|
||||||
|
handleFilter={handleFilter}
|
||||||
|
removeDefaultSearchKeys={removeDefaultSearchKeys}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
reachedEnd,
|
||||||
|
apiHost,
|
||||||
|
setSearchString,
|
||||||
|
handleFilter,
|
||||||
|
pathname,
|
||||||
|
removeDefaultSearchKeys,
|
||||||
|
scrollToRef,
|
||||||
|
// searchParams,
|
||||||
|
// searchString,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
setInterval(() => {
|
||||||
|
setCounter((prev) => prev + 1);
|
||||||
|
}, 1000);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.log('main render', counter);
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 w-full">
|
<div className="space-y-4 w-full">
|
||||||
<Heading>Events</Heading>
|
<Heading>Events</Heading>
|
||||||
@ -85,24 +116,9 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
|||||||
<Table className="min-w-full table-fixed">
|
<Table className="min-w-full table-fixed">
|
||||||
<TableHead />
|
<TableHead />
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{events.map(({ id, ...rest }, idx) => {
|
{events.map((props, idx) => {
|
||||||
return (
|
const lastRowRef = idx === events.length - 1 ? lastCellRef : undefined;
|
||||||
<TableRow
|
return <RenderTableRow {...props} lastRowRef={lastRowRef} idx={idx} />;
|
||||||
key={id}
|
|
||||||
idx={idx}
|
|
||||||
numberOfEvents={events.length}
|
|
||||||
id={id}
|
|
||||||
apiHost={apiHost}
|
|
||||||
scrollToRef={scrollToRef}
|
|
||||||
pathname={pathname}
|
|
||||||
searchParams={searchParams}
|
|
||||||
limit={API_LIMIT}
|
|
||||||
handleFilter={handleFilter}
|
|
||||||
lastCellRef={lastCellRef}
|
|
||||||
removeDefaultSearchKeys={removeDefaultSearchKeys}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
<Tfoot>
|
<Tfoot>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user