mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-17 06:00:20 +02:00
upgrade and refactor for react-query v5
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { queryOptions } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
import { SimilarSongsQuery, SongListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
export const songsQueries = {
|
||||
list: (args: QueryHookArgs<SongListQuery>, imageSize?: number) => {
|
||||
return queryOptions({
|
||||
queryFn: ({ signal }) => {
|
||||
const server = getServerById(args.serverId);
|
||||
if (!server) throw new Error('Server not found');
|
||||
return controller.getSongList({
|
||||
apiClientProps: { server, signal },
|
||||
query: { ...args.query, imageSize },
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.songs.list(args.serverId || '', { ...args.query, imageSize }),
|
||||
...args.options,
|
||||
});
|
||||
},
|
||||
listCount: (args: QueryHookArgs<SongListQuery>) => {
|
||||
return queryOptions({
|
||||
queryFn: ({ signal }) => {
|
||||
const server = getServerById(args.serverId);
|
||||
if (!server) throw new Error('Server not found');
|
||||
return api.controller.getSongListCount({
|
||||
apiClientProps: { server, signal },
|
||||
query: args.query,
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.songs.count(
|
||||
args.serverId || '',
|
||||
Object.keys(args.query).length === 0 ? undefined : args.query,
|
||||
),
|
||||
...args.options,
|
||||
});
|
||||
},
|
||||
similar: (args: QueryHookArgs<SimilarSongsQuery>) => {
|
||||
return queryOptions({
|
||||
queryFn: ({ signal }) => {
|
||||
const server = getServerById(args.serverId);
|
||||
if (!server) throw new Error('Server not found');
|
||||
return api.controller.getSimilarSongs({
|
||||
apiClientProps: { server, signal },
|
||||
query: {
|
||||
albumArtistIds: args.query.albumArtistIds,
|
||||
count: args.query.count ?? 50,
|
||||
songId: args.query.songId,
|
||||
},
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.songs.similar(args.serverId || '', args.query),
|
||||
...args.options,
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { MultiSelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
||||
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
|
||||
import { SongListFilter, useListFilterByKey, useListStoreActions } from '/@/renderer/store';
|
||||
import { Divider } from '/@/shared/components/divider/divider';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
@@ -18,7 +19,7 @@ interface JellyfinSongFiltersProps {
|
||||
customFilters?: Partial<SongListFilter>;
|
||||
onFilterChange: (filters: SongListFilter) => void;
|
||||
pageKey: string;
|
||||
serverId?: string;
|
||||
serverId: string;
|
||||
}
|
||||
|
||||
export const JellyfinSongFilters = ({
|
||||
@@ -35,15 +36,17 @@ export const JellyfinSongFilters = ({
|
||||
|
||||
// Despite the fact that getTags returns genres, it only returns genre names.
|
||||
// We prefer using IDs, hence the double query
|
||||
const genreListQuery = useGenreList({
|
||||
query: {
|
||||
musicFolderId: filter?.musicFolderId,
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
const genreListQuery = useQuery(
|
||||
genresQueries.list({
|
||||
query: {
|
||||
musicFolderId: filter?.musicFolderId,
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
}),
|
||||
);
|
||||
|
||||
const genreList = useMemo(() => {
|
||||
if (!genreListQuery?.data) return [];
|
||||
@@ -53,13 +56,15 @@ export const JellyfinSongFilters = ({
|
||||
}));
|
||||
}, [genreListQuery.data]);
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
query: {
|
||||
folder: filter?.musicFolderId,
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
const tagsQuery = useQuery(
|
||||
sharedQueries.tags({
|
||||
query: {
|
||||
folder: filter?.musicFolderId,
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
}),
|
||||
);
|
||||
|
||||
const selectedGenres = useMemo(() => {
|
||||
return filter?._custom?.jellyfin?.GenreIds?.split(',');
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -6,8 +7,8 @@ import {
|
||||
MultiSelectWithInvalidData,
|
||||
SelectWithInvalidData,
|
||||
} from '/@/renderer/components/select-with-invalid-data';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
||||
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
|
||||
import {
|
||||
getServerById,
|
||||
SongListFilter,
|
||||
@@ -29,7 +30,7 @@ interface NavidromeSongFiltersProps {
|
||||
customFilters?: Partial<SongListFilter>;
|
||||
onFilterChange: (filters: SongListFilter) => void;
|
||||
pageKey: string;
|
||||
serverId?: string;
|
||||
serverId: string;
|
||||
}
|
||||
|
||||
export const NavidromeSongFilters = ({
|
||||
@@ -45,21 +46,25 @@ export const NavidromeSongFilters = ({
|
||||
|
||||
const isGenrePage = customFilters?.genreIds !== undefined;
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
const genreListQuery = useQuery(
|
||||
genresQueries.list({
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
}),
|
||||
);
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
query: {
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
const tagsQuery = useQuery(
|
||||
sharedQueries.tags({
|
||||
query: {
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
}),
|
||||
);
|
||||
|
||||
const genreList = useMemo(() => {
|
||||
if (!genreListQuery?.data) return [];
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
VirtualInfiniteGridRef,
|
||||
} from '/@/renderer/components/virtual-grid';
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
|
||||
import { useHandleFavorite } from '/@/renderer/features/shared/hooks/use-handle-favorite';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
SongListSort,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { CardRow, ListDisplayType } from '/@/shared/types/types';
|
||||
|
||||
interface SongListGridViewProps {
|
||||
gridRef: MutableRefObject<null | VirtualInfiniteGridRef>;
|
||||
itemCount?: number;
|
||||
@@ -185,15 +184,17 @@ export const SongListGridView = ({ gridRef, itemCount }: SongListGridViewProps)
|
||||
|
||||
const queryKey = queryKeys.songs.list(server?.id || '', query, id);
|
||||
|
||||
const songs = await queryClient.fetchQuery(queryKey, async ({ signal }) =>
|
||||
controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query,
|
||||
}),
|
||||
);
|
||||
const songs = await queryClient.fetchQuery({
|
||||
queryFn: async ({ signal }) =>
|
||||
controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query,
|
||||
}),
|
||||
queryKey,
|
||||
});
|
||||
|
||||
return songs;
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||
|
||||
import { openModal } from '@mantine/modals';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { MouseEvent, MutableRefObject, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,7 +11,8 @@ import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
|
||||
import { SONG_TABLE_COLUMNS } from '/@/renderer/components/virtual-table';
|
||||
import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { OrderToggleButton, useMusicFolders } from '/@/renderer/features/shared';
|
||||
import { OrderToggleButton } from '/@/renderer/features/shared';
|
||||
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
|
||||
import { FilterButton } from '/@/renderer/features/shared/components/filter-button';
|
||||
import { FolderButton } from '/@/renderer/features/shared/components/folder-button';
|
||||
import { ListConfigMenu } from '/@/renderer/features/shared/components/list-config-menu';
|
||||
@@ -223,7 +225,9 @@ export const SongListHeaderFilters = ({
|
||||
|
||||
const cq = useContainerQuery();
|
||||
|
||||
const musicFoldersQuery = useMusicFolders({ query: null, serverId: server?.id });
|
||||
const musicFoldersQuery = useQuery(
|
||||
sharedQueries.musicFolders({ query: null, serverId: server?.id }),
|
||||
);
|
||||
|
||||
const sortByLabel =
|
||||
(server?.type &&
|
||||
@@ -407,7 +411,7 @@ export const SongListHeaderFilters = ({
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
queryClient.invalidateQueries(queryKeys.songs.list(server?.id || ''));
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.songs.list(server?.id || '') });
|
||||
if (isGrid) {
|
||||
handleRefreshGrid(gridRef, filter);
|
||||
} else {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { ChangeEvent, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
||||
import { SongListFilter, useListFilterByKey, useListStoreActions } from '/@/renderer/store';
|
||||
import { Divider } from '/@/shared/components/divider/divider';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
@@ -16,7 +17,7 @@ interface SubsonicSongFiltersProps {
|
||||
customFilters?: Partial<SongListFilter>;
|
||||
onFilterChange: (filters: SongListFilter) => void;
|
||||
pageKey: string;
|
||||
serverId?: string;
|
||||
serverId: string;
|
||||
}
|
||||
|
||||
export const SubsonicSongFilters = ({
|
||||
@@ -31,14 +32,16 @@ export const SubsonicSongFilters = ({
|
||||
|
||||
const isGenrePage = customFilters?.genreIds !== undefined;
|
||||
|
||||
const genreListQuery = useGenreList({
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
const genreListQuery = useQuery(
|
||||
genresQueries.list({
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId,
|
||||
}),
|
||||
);
|
||||
|
||||
const genreList = useMemo(() => {
|
||||
if (!genreListQuery?.data) return [];
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { SongListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useSongListCount = (args: QueryHookArgs<SongListQuery>) => {
|
||||
const { options, query, serverId } = args;
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!serverId,
|
||||
queryFn: ({ signal }) => {
|
||||
if (!server) throw new Error('Server not found');
|
||||
return api.controller.getSongListCount({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query,
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.songs.count(
|
||||
serverId || '',
|
||||
Object.keys(query).length === 0 ? undefined : query,
|
||||
),
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
|
||||
import type { SongListQuery } from '/@/shared/types/domain-types';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { getServerById } from '/@/renderer/store';
|
||||
|
||||
export const useSongList = (args: QueryHookArgs<SongListQuery>, imageSize?: number) => {
|
||||
const { options, query, serverId } = args || {};
|
||||
const server = getServerById(serverId);
|
||||
|
||||
return useQuery({
|
||||
enabled: !!server?.id,
|
||||
queryFn: ({ signal }) => {
|
||||
if (!server) throw new Error('Server not found');
|
||||
return controller.getSongList({
|
||||
apiClientProps: { server, signal },
|
||||
query: { ...query, imageSize },
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.songs.list(server?.id || '', { ...query, imageSize }),
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
|
||||
import { ListContext } from '/@/renderer/context/list-context';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared';
|
||||
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
||||
import { SongListContent } from '/@/renderer/features/songs/components/song-list-content';
|
||||
import { SongListHeader } from '/@/renderer/features/songs/components/song-list-header';
|
||||
import { useSongListCount } from '/@/renderer/features/songs/queries/song-list-count-query';
|
||||
import { useCurrentServer, useListFilterByKey } from '/@/renderer/store';
|
||||
import { GenreListSort, LibraryItem, SongListQuery, SortOrder } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
@@ -46,18 +47,20 @@ const TrackListRoute = () => {
|
||||
key: pageKey,
|
||||
});
|
||||
|
||||
const genreList = useGenreList({
|
||||
options: {
|
||||
cacheTime: 1000 * 60 * 60,
|
||||
enabled: !!genreId,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
const genreList = useQuery(
|
||||
genresQueries.list({
|
||||
options: {
|
||||
enabled: !!genreId,
|
||||
gcTime: 1000 * 60 * 60,
|
||||
},
|
||||
query: {
|
||||
sortBy: GenreListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
},
|
||||
serverId: server?.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const genreTitle = useMemo(() => {
|
||||
if (!genreList.data) return '';
|
||||
@@ -68,14 +71,15 @@ const TrackListRoute = () => {
|
||||
return genre?.name;
|
||||
}, [genreId, genreList.data]);
|
||||
|
||||
const itemCountCheck = useSongListCount({
|
||||
options: {
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
query: songListFilter,
|
||||
serverId: server?.id,
|
||||
});
|
||||
const itemCountCheck = useQuery(
|
||||
songsQueries.listCount({
|
||||
options: {
|
||||
gcTime: 1000 * 60,
|
||||
},
|
||||
query: songListFilter,
|
||||
serverId: server?.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const itemCount = itemCountCheck.data === null ? undefined : itemCountCheck.data;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user