mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
resolve #1143
This commit is contained in:
parent
3712a8ab80
commit
85de881181
@ -34,7 +34,27 @@ function reducer(state, { type, payload, meta }) {
|
||||
draftState.queries[url] = { status: ok ? FetchStatus.LOADED : FetchStatus.ERROR, data, fetchId };
|
||||
});
|
||||
}
|
||||
case 'DELETE': {
|
||||
const { eventId } = payload;
|
||||
|
||||
return produce(state, (draftState) => {
|
||||
Object.keys(draftState.queries).map(function (url, index) {
|
||||
// If no url or data has no array length then just return state.
|
||||
if (!(url in draftState.queries) || !draftState.queries[url].data.length) return state;
|
||||
|
||||
//Find the index to remove
|
||||
const removeIndex = draftState.queries[url].data.map((event) => event.id).indexOf(eventId);
|
||||
if (removeIndex === -1) return;
|
||||
|
||||
// We need to keep track of deleted items, This will be used to calculate "ReachEnd" for auto load new events. Events.jsx
|
||||
const totDeleted = state.queries[url].deleted || 0;
|
||||
|
||||
// Splice the deleted index.
|
||||
draftState.queries[url].data.splice(removeIndex, 1);
|
||||
draftState.queries[url].deleted = totDeleted + 1;
|
||||
});
|
||||
});
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
@ -91,8 +111,23 @@ export function useFetch(url, fetchId) {
|
||||
|
||||
const data = state.queries[url].data || null;
|
||||
const status = state.queries[url].status;
|
||||
const deleted = state.queries[url].deleted || 0;
|
||||
|
||||
return { data, status };
|
||||
return { data, status, deleted };
|
||||
}
|
||||
|
||||
export function useDelete() {
|
||||
const { dispatch, state } = useContext(Api);
|
||||
|
||||
async function deleteEvent(eventId) {
|
||||
if (!eventId) return { success: false };
|
||||
|
||||
const response = await fetch(`${state.host}/api/events/${eventId}`, { method: 'DELETE' });
|
||||
await dispatch({ type: 'DELETE', payload: { eventId } });
|
||||
return await (response.status < 300 ? response.json() : { success: true });
|
||||
}
|
||||
|
||||
return deleteEvent;
|
||||
}
|
||||
|
||||
export function useApiHost() {
|
||||
|
@ -10,7 +10,7 @@ import Dialog from '../components/Dialog';
|
||||
import Heading from '../components/Heading';
|
||||
import Link from '../components/Link';
|
||||
import VideoPlayer from '../components/VideoPlayer';
|
||||
import { FetchStatus, useApiHost, useEvent } from '../api';
|
||||
import { FetchStatus, useApiHost, useEvent, useDelete } from '../api';
|
||||
import { Table, Thead, Tbody, Th, Tr, Td } from '../components/Table';
|
||||
|
||||
export default function Event({ eventId }) {
|
||||
@ -18,6 +18,7 @@ export default function Event({ eventId }) {
|
||||
const { data, status } = useEvent(eventId);
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
const [deleteStatus, setDeleteStatus] = useState(FetchStatus.NONE);
|
||||
const setDeleteEvent = useDelete();
|
||||
|
||||
const handleClickDelete = () => {
|
||||
setShowDialog(true);
|
||||
@ -30,8 +31,7 @@ export default function Event({ eventId }) {
|
||||
const handleClickDeleteDialog = useCallback(async () => {
|
||||
let success;
|
||||
try {
|
||||
const response = await fetch(`${apiHost}/api/events/${eventId}`, { method: 'DELETE' });
|
||||
success = await (response.status < 300 ? response.json() : { success: true });
|
||||
success = await setDeleteEvent(eventId);
|
||||
setDeleteStatus(success ? FetchStatus.LOADED : FetchStatus.ERROR);
|
||||
} catch (e) {
|
||||
setDeleteStatus(FetchStatus.ERROR);
|
||||
@ -42,7 +42,7 @@ export default function Event({ eventId }) {
|
||||
setShowDialog(false);
|
||||
route('/events', true);
|
||||
}
|
||||
}, [apiHost, eventId, setShowDialog]);
|
||||
}, [eventId, setShowDialog]);
|
||||
|
||||
if (status !== FetchStatus.LOADED) {
|
||||
return <ActivityIndicator />;
|
||||
@ -64,7 +64,11 @@ export default function Event({ eventId }) {
|
||||
<Dialog
|
||||
onDismiss={handleDismissDeleteDialog}
|
||||
title="Delete Event?"
|
||||
text="This event will be permanently deleted along with any related clips and snapshots"
|
||||
text={
|
||||
deleteStatus === FetchStatus.ERROR
|
||||
? 'Could not delete event, please try again.'
|
||||
: 'This event will be permanently deleted along with any related clips and snapshots'
|
||||
}
|
||||
actions={[
|
||||
deleteStatus !== FetchStatus.LOADING
|
||||
? { text: 'Delete', color: 'red', onClick: handleClickDeleteDialog }
|
||||
|
@ -20,6 +20,7 @@ const reducer = (state = initialState, action) => {
|
||||
meta: { searchString },
|
||||
payload,
|
||||
} = action;
|
||||
|
||||
return produce(state, (draftState) => {
|
||||
draftState.searchStrings[searchString] = true;
|
||||
draftState.events.push(...payload);
|
||||
@ -56,17 +57,17 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
||||
const [{ events, reachedEnd, searchStrings }, dispatch] = useReducer(reducer, initialState);
|
||||
const { searchParams: initialSearchParams } = new URL(window.location);
|
||||
const [searchString, setSearchString] = useState(`${defaultSearchString(limit)}&${initialSearchParams.toString()}`);
|
||||
const { data, status } = useEvents(searchString);
|
||||
const { data, status, deleted } = useEvents(searchString);
|
||||
|
||||
useEffect(() => {
|
||||
if (data && !(searchString in searchStrings)) {
|
||||
dispatch({ type: 'APPEND_EVENTS', payload: data, meta: { searchString } });
|
||||
}
|
||||
|
||||
if (data && Array.isArray(data) && data.length < limit) {
|
||||
if (data && Array.isArray(data) && data.length + deleted < limit) {
|
||||
dispatch({ type: 'REACHED_END', meta: { searchString } });
|
||||
}
|
||||
}, [data, limit, searchString, searchStrings]);
|
||||
}, [data, limit, searchString, searchStrings, deleted]);
|
||||
|
||||
const [entry, setIntersectNode] = useIntersectionObserver();
|
||||
|
||||
@ -100,7 +101,6 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
||||
);
|
||||
|
||||
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4 w-full">
|
||||
<Heading>Events</Heading>
|
||||
|
Loading…
Reference in New Issue
Block a user