mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Refactor ItemsContainer invalidate Queries
This commit is contained in:
parent
42b4d08e55
commit
e3b618f2fb
1 changed files with 43 additions and 144 deletions
|
@ -1,13 +1,11 @@
|
||||||
import type {
|
import type {
|
||||||
LibraryUpdateInfo,
|
LibraryUpdateInfo
|
||||||
SeriesTimerInfoDto,
|
|
||||||
TimerInfoDto,
|
|
||||||
UserItemDataDto
|
|
||||||
} from '@jellyfin/sdk/lib/generated-client';
|
} from '@jellyfin/sdk/lib/generated-client';
|
||||||
import React, { FC, useCallback, useEffect, useRef } from 'react';
|
import React, { FC, useCallback, useEffect, useRef } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Box } from '@mui/material';
|
import Box from '@mui/material/Box';
|
||||||
import Sortable from 'sortablejs';
|
import Sortable from 'sortablejs';
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { usePlaylistsMoveItemMutation } from 'hooks/useFetchItems';
|
import { usePlaylistsMoveItemMutation } from 'hooks/useFetchItems';
|
||||||
import Events, { Event } from 'utils/events';
|
import Events, { Event } from 'utils/events';
|
||||||
import serverNotifications from 'scripts/serverNotifications';
|
import serverNotifications from 'scripts/serverNotifications';
|
||||||
|
@ -40,11 +38,11 @@ interface ItemsContainerProps {
|
||||||
isContextMenuEnabled?: boolean;
|
isContextMenuEnabled?: boolean;
|
||||||
isMultiSelectEnabled?: boolean;
|
isMultiSelectEnabled?: boolean;
|
||||||
isDragreOrderEnabled?: boolean;
|
isDragreOrderEnabled?: boolean;
|
||||||
dataMonitor?: string;
|
eventsToMonitor?: string[];
|
||||||
parentId?: ParentId;
|
parentId?: ParentId;
|
||||||
reloadItems?: () => void;
|
reloadItems?: () => void;
|
||||||
getItemsHtml?: () => string;
|
getItemsHtml?: () => string;
|
||||||
children?: React.ReactNode;
|
queryKey?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemsContainer: FC<ItemsContainerProps> = ({
|
const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
|
@ -52,12 +50,14 @@ const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
isContextMenuEnabled,
|
isContextMenuEnabled,
|
||||||
isMultiSelectEnabled,
|
isMultiSelectEnabled,
|
||||||
isDragreOrderEnabled,
|
isDragreOrderEnabled,
|
||||||
dataMonitor,
|
eventsToMonitor = [],
|
||||||
parentId,
|
parentId,
|
||||||
|
queryKey,
|
||||||
reloadItems,
|
reloadItems,
|
||||||
getItemsHtml,
|
getItemsHtml,
|
||||||
children
|
children
|
||||||
}) => {
|
}) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { mutateAsync: playlistsMoveItemMutation } = usePlaylistsMoveItemMutation();
|
const { mutateAsync: playlistsMoveItemMutation } = usePlaylistsMoveItemMutation();
|
||||||
const itemsContainerRef = useRef<HTMLDivElement>(null);
|
const itemsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const multiSelectref = useRef<MultiSelect | null>(null);
|
const multiSelectref = useRef<MultiSelect | null>(null);
|
||||||
|
@ -172,6 +172,14 @@ const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const invalidateQueries = useCallback(async () => {
|
||||||
|
await queryClient.invalidateQueries({
|
||||||
|
queryKey: queryKey,
|
||||||
|
type: 'all',
|
||||||
|
refetchType: 'active'
|
||||||
|
});
|
||||||
|
}, [queryClient, queryKey]);
|
||||||
|
|
||||||
const notifyRefreshNeeded = useCallback(
|
const notifyRefreshNeeded = useCallback(
|
||||||
(isInForeground: boolean) => {
|
(isInForeground: boolean) => {
|
||||||
if (!reloadItems) return;
|
if (!reloadItems) return;
|
||||||
|
@ -184,144 +192,37 @@ const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
[reloadItems]
|
[reloadItems]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getEventsToMonitor = useCallback(() => {
|
const onUserDataChanged = useCallback(async () => {
|
||||||
const monitor = dataMonitor;
|
await invalidateQueries();
|
||||||
if (monitor) {
|
|
||||||
return monitor.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}, [dataMonitor]);
|
|
||||||
|
|
||||||
const onUserDataChanged = useCallback(
|
|
||||||
(_e: Event, userData: UserItemDataDto) => {
|
|
||||||
const itemsContainer = itemsContainerRef.current as HTMLDivElement;
|
|
||||||
|
|
||||||
import('../../components/cardbuilder/cardBuilder')
|
|
||||||
.then((cardBuilder) => {
|
|
||||||
cardBuilder.onUserDataChanged(userData, itemsContainer);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(
|
|
||||||
'[onUserDataChanged] failed to load onUserData Changed',
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
|
||||||
if (
|
|
||||||
eventsToMonitor.indexOf('markfavorite') !== -1
|
|
||||||
|| eventsToMonitor.indexOf('markplayed') !== -1
|
|
||||||
) {
|
|
||||||
notifyRefreshNeeded(false);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded]
|
[invalidateQueries]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onTimerCreated = useCallback(
|
const onTimerCreated = useCallback(async () => {
|
||||||
(_e: Event, data: TimerInfoDto) => {
|
await invalidateQueries();
|
||||||
const itemsContainer = itemsContainerRef.current as HTMLDivElement;
|
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
|
||||||
if (eventsToMonitor.indexOf('timers') !== -1) {
|
|
||||||
notifyRefreshNeeded(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const programId = data.ProgramId;
|
|
||||||
// This could be null, not supported by all tv providers
|
|
||||||
const newTimerId = data.Id;
|
|
||||||
if (programId && newTimerId) {
|
|
||||||
import('../../components/cardbuilder/cardBuilder')
|
|
||||||
.then((cardBuilder) => {
|
|
||||||
cardBuilder.onTimerCreated(
|
|
||||||
programId,
|
|
||||||
newTimerId,
|
|
||||||
itemsContainer
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(
|
|
||||||
'[onTimerCreated] failed to load onTimer Created',
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded]
|
[invalidateQueries]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSeriesTimerCreated = useCallback(() => {
|
const onSeriesTimerCreated = useCallback(async () => {
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
await invalidateQueries();
|
||||||
if (eventsToMonitor.indexOf('seriestimers') !== -1) {
|
}, [invalidateQueries]);
|
||||||
notifyRefreshNeeded(false);
|
|
||||||
}
|
|
||||||
}, [getEventsToMonitor, notifyRefreshNeeded]);
|
|
||||||
|
|
||||||
const onTimerCancelled = useCallback(
|
const onTimerCancelled = useCallback(async () => {
|
||||||
(_e: Event, data: TimerInfoDto) => {
|
await invalidateQueries();
|
||||||
const itemsContainer = itemsContainerRef.current as HTMLDivElement;
|
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
|
||||||
if (eventsToMonitor.indexOf('timers') !== -1) {
|
|
||||||
notifyRefreshNeeded(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timerId = data.Id;
|
|
||||||
|
|
||||||
if (timerId) {
|
|
||||||
import('../../components/cardbuilder/cardBuilder')
|
|
||||||
.then((cardBuilder) => {
|
|
||||||
cardBuilder.onTimerCancelled(timerId, itemsContainer);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(
|
|
||||||
'[onTimerCancelled] failed to load onTimer Cancelled',
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded]
|
[invalidateQueries]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSeriesTimerCancelled = useCallback(
|
const onSeriesTimerCancelled = useCallback(async () => {
|
||||||
(_e: Event, data: SeriesTimerInfoDto) => {
|
await invalidateQueries();
|
||||||
const itemsContainer = itemsContainerRef.current as HTMLDivElement;
|
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
|
||||||
if (eventsToMonitor.indexOf('seriestimers') !== -1) {
|
|
||||||
notifyRefreshNeeded(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancelledTimerId = data.Id;
|
|
||||||
|
|
||||||
if (cancelledTimerId) {
|
|
||||||
import('../../components/cardbuilder/cardBuilder')
|
|
||||||
.then((cardBuilder) => {
|
|
||||||
cardBuilder.onSeriesTimerCancelled(
|
|
||||||
cancelledTimerId,
|
|
||||||
itemsContainer
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(
|
|
||||||
'[onSeriesTimerCancelled] failed to load onSeriesTimer Cancelled',
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded]
|
[invalidateQueries]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onLibraryChanged = useCallback(
|
const onLibraryChanged = useCallback(
|
||||||
(_e: Event, data: LibraryUpdateInfo) => {
|
(_e: Event, apiClient, data: LibraryUpdateInfo) => {
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
if (eventsToMonitor.includes('seriestimers') || eventsToMonitor.includes('timers')) {
|
||||||
if (
|
|
||||||
eventsToMonitor.indexOf('seriestimers') !== -1
|
|
||||||
|| eventsToMonitor.indexOf('timers') !== -1
|
|
||||||
) {
|
|
||||||
// yes this is an assumption
|
// yes this is an assumption
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -348,32 +249,31 @@ const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
|
|
||||||
notifyRefreshNeeded(false);
|
notifyRefreshNeeded(false);
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded, parentId]
|
[eventsToMonitor, notifyRefreshNeeded, parentId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPlaybackStopped = useCallback(
|
const onPlaybackStopped = useCallback(
|
||||||
(_e: Event, stopInfo) => {
|
(_e: Event, apiClient, stopInfo) => {
|
||||||
const state = stopInfo.state;
|
const state = stopInfo.state;
|
||||||
|
|
||||||
const eventsToMonitor = getEventsToMonitor();
|
|
||||||
if (
|
if (
|
||||||
state.NowPlayingItem
|
state.NowPlayingItem
|
||||||
&& state.NowPlayingItem.MediaType === 'Video'
|
&& state.NowPlayingItem.MediaType === 'Video'
|
||||||
) {
|
) {
|
||||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
if (eventsToMonitor.includes('videoplayback')) {
|
||||||
notifyRefreshNeeded(true);
|
notifyRefreshNeeded(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
state.NowPlayingItem
|
state.NowPlayingItem
|
||||||
&& state.NowPlayingItem.MediaType === 'Audio'
|
&& state.NowPlayingItem.MediaType === 'Audio'
|
||||||
&& eventsToMonitor.indexOf('audioplayback') !== -1
|
&& eventsToMonitor.includes('videoplayback')
|
||||||
) {
|
) {
|
||||||
notifyRefreshNeeded(true);
|
notifyRefreshNeeded(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[getEventsToMonitor, notifyRefreshNeeded]
|
[eventsToMonitor, notifyRefreshNeeded]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFocus = useCallback(
|
const setFocus = useCallback(
|
||||||
|
@ -418,9 +318,8 @@ const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||||
|
|
||||||
if (getItemsHtml) {
|
if (getItemsHtml) {
|
||||||
itemsContainer.innerHTML = getItemsHtml();
|
itemsContainer.innerHTML = getItemsHtml();
|
||||||
}
|
|
||||||
|
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
if (hasActiveElement) {
|
if (hasActiveElement) {
|
||||||
setFocus(itemsContainer, focusId);
|
setFocus(itemsContainer, focusId);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue