Add view artist discography

This commit is contained in:
jeffvli 2023-01-15 16:22:07 -08:00
parent 67523f1e7b
commit 5614ad54f2
7 changed files with 338 additions and 155 deletions

View File

@ -10,12 +10,12 @@ import {
import { AppRoute } from '/@/renderer/router/routes';
import { ListDisplayType, CardRow } from '/@/renderer/types';
import AutoSizer from 'react-virtualized-auto-sizer';
import { MutableRefObject, useCallback, useMemo } from 'react';
import { MutableRefObject, useCallback, useMemo, useState } from 'react';
import { ListOnScrollProps } from 'react-window';
import { api } from '/@/renderer/api';
import { controller } from '/@/renderer/api/controller';
import { queryKeys } from '/@/renderer/api/query-keys';
import { Album, AlbumListSort, LibraryItem } from '/@/renderer/api/types';
import { Album, AlbumListQuery, AlbumListSort, LibraryItem } from '/@/renderer/api/types';
import { useQueryClient } from '@tanstack/react-query';
import {
useCurrentServer,
@ -25,6 +25,7 @@ import {
useSetAlbumTable,
useSetAlbumTablePagination,
useAlbumListItemData,
AlbumListFilter,
} from '/@/renderer/store';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import {
@ -44,12 +45,18 @@ import { usePlayQueueAdd } from '/@/renderer/features/player';
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
interface AlbumListContentProps {
customFilters?: Partial<AlbumListFilter>;
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
itemCount?: number;
tableRef: MutableRefObject<AgGridReactType | null>;
}
export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListContentProps) => {
export const AlbumListContent = ({
customFilters,
itemCount,
gridRef,
tableRef,
}: AlbumListContentProps) => {
const queryClient = useQueryClient();
const navigate = useNavigate();
const server = useCurrentServer();
@ -58,6 +65,7 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
const handlePlayQueueAdd = usePlayQueueAdd();
const { itemData, setItemData } = useAlbumListItemData();
const [localItemData, setLocalItemData] = useState<any[]>([]);
const pagination = useAlbumTablePagination();
const setPagination = useSetAlbumTablePagination();
@ -77,21 +85,28 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
const limit = params.endRow - params.startRow;
const startIndex = params.startRow;
const queryKey = queryKeys.albums.list(server?.id || '', {
const query: AlbumListQuery = {
limit,
startIndex,
...page.filter,
});
...customFilters,
jfParams: {
...page.filter.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...page.filter.ndParams,
...customFilters?.ndParams,
},
};
const queryKey = queryKeys.albums.list(server?.id || '', query);
const albumsRes = await queryClient.fetchQuery(
queryKey,
async ({ signal }) =>
api.controller.getAlbumList({
query: {
limit,
startIndex,
...page.filter,
},
query,
server,
signal,
}),
@ -104,9 +119,12 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
rowCount: undefined,
};
params.api.setDatasource(dataSource);
params.api.ensureIndexVisible(page.table.scrollOffset || 0, 'top');
if (!customFilters) {
params.api.ensureIndexVisible(page.table.scrollOffset || 0, 'top');
}
},
[page.filter, page.table.scrollOffset, queryClient, server],
[customFilters, page.filter, page.table.scrollOffset, queryClient, server],
);
const onTablePaginationChanged = useCallback(
@ -153,25 +171,33 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
const debouncedTableColumnChange = debounce(handleTableColumnChange, 200);
const handleTableScroll = (e: BodyScrollEvent) => {
if (customFilters) return;
const scrollOffset = Number((e.top / page.table.rowHeight).toFixed(0));
setTable({ scrollOffset });
};
const fetch = useCallback(
async ({ skip, take }: { skip: number; take: number }) => {
const queryKey = queryKeys.albums.list(server?.id || '', {
const query: AlbumListQuery = {
limit: take,
startIndex: skip,
...page.filter,
});
...customFilters,
jfParams: {
...page.filter.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...page.filter.ndParams,
...customFilters?.ndParams,
},
};
const queryKey = queryKeys.albums.list(server?.id || '', query);
const albums = await queryClient.fetchQuery(queryKey, async ({ signal }) =>
controller.getAlbumList({
query: {
limit: take,
startIndex: skip,
...page.filter,
},
query,
server,
signal,
}),
@ -179,11 +205,12 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
return api.normalize.albumList(albums, server);
},
[page.filter, queryClient, server],
[customFilters, page.filter, queryClient, server],
);
const handleGridScroll = useCallback(
(e: ListOnScrollProps) => {
if (customFilters) return;
setPage({
list: {
...page,
@ -194,7 +221,7 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
},
});
},
[page, setPage],
[customFilters, page, setPage],
);
const cardRows = useMemo(() => {
@ -308,9 +335,9 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
handleFavorite={handleFavorite}
handlePlayQueueAdd={handlePlayQueueAdd}
height={height}
initialScrollOffset={page?.grid.scrollOffset || 0}
initialScrollOffset={customFilters ? 0 : page?.grid.scrollOffset || 0}
itemCount={itemCount || 0}
itemData={itemData}
itemData={customFilters ? localItemData : itemData}
itemGap={20}
itemSize={150 + page.grid?.size}
itemType={LibraryItem.ALBUM}
@ -320,7 +347,7 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
route: AppRoute.LIBRARY_ALBUMS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumId' }],
}}
setItemData={setItemData}
setItemData={customFilters ? setLocalItemData : setItemData}
width={width}
onScroll={handleGridScroll}
/>
@ -334,6 +361,7 @@ export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListCont
key={`table-${page.display}-${page.table.rowHeight}-${server?.id}`}
ref={tableRef}
alwaysShowHorizontalScroll
suppressRowDrag
autoFitColumns={page.table.autoFit}
blockLoadDebounceMillis={200}
columnDefs={columnDefs}

View File

@ -3,6 +3,7 @@ import { useCallback } from 'react';
import { IDatasource } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Flex, Group, Stack } from '@mantine/core';
import { openModal } from '@mantine/modals';
import { useQueryClient } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
import {
@ -17,7 +18,13 @@ import styled from 'styled-components';
import { api } from '/@/renderer/api';
import { controller } from '/@/renderer/api/controller';
import { queryKeys } from '/@/renderer/api/query-keys';
import { AlbumListSort, LibraryItem, ServerType, SortOrder } from '/@/renderer/api/types';
import {
AlbumListQuery,
AlbumListSort,
LibraryItem,
ServerType,
SortOrder,
} from '/@/renderer/api/types';
import {
ALBUM_TABLE_COLUMNS,
Badge,
@ -25,7 +32,6 @@ import {
DropdownMenu,
MultiSelect,
PageHeader,
Popover,
SearchInput,
Slider,
SpinnerIcon,
@ -92,12 +98,20 @@ const HeaderItems = styled.div`
`;
interface AlbumListHeaderProps {
customFilters?: Partial<AlbumListFilter>;
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
itemCount?: number;
tableRef: MutableRefObject<AgGridReactType | null>;
title?: string;
}
export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeaderProps) => {
export const AlbumListHeader = ({
itemCount,
gridRef,
tableRef,
title,
customFilters,
}: AlbumListHeaderProps) => {
const queryClient = useQueryClient();
const server = useCurrentServer();
const setPage = useSetAlbumStore();
@ -131,21 +145,28 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
const fetch = useCallback(
async (skip: number, take: number, filters: AlbumListFilter) => {
const queryKey = queryKeys.albums.list(server?.id || '', {
const query: AlbumListQuery = {
limit: take,
startIndex: skip,
...filters,
});
jfParams: {
...filters.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...filters.ndParams,
...customFilters?.ndParams,
},
...customFilters,
};
const queryKey = queryKeys.albums.list(server?.id || '', query);
const albums = await queryClient.fetchQuery(
queryKey,
async ({ signal }) =>
controller.getAlbumList({
query: {
limit: take,
startIndex: skip,
...filters,
},
query,
server,
signal,
}),
@ -154,7 +175,7 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
return api.normalize.albumList(albums, server);
},
[queryClient, server],
[customFilters, queryClient, server],
);
const handleFilterChange = useCallback(
@ -168,21 +189,28 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
const limit = params.endRow - params.startRow;
const startIndex = params.startRow;
const queryKey = queryKeys.albums.list(server?.id || '', {
const query: AlbumListQuery = {
limit,
startIndex,
...filters,
});
...customFilters,
jfParams: {
...filters.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...filters.ndParams,
...customFilters?.ndParams,
},
};
const queryKey = queryKeys.albums.list(server?.id || '', query);
const albumsRes = await queryClient.fetchQuery(
queryKey,
async ({ signal }) =>
api.controller.getAlbumList({
query: {
limit,
startIndex,
...filters,
},
query,
server,
signal,
}),
@ -214,9 +242,30 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
gridRef.current?.setItemData(data.items);
}
},
[page.display, tableRef, setPagination, server, queryClient, gridRef, fetch],
[page.display, tableRef, customFilters, server, queryClient, setPagination, gridRef, fetch],
);
const handleOpenFiltersModal = () => {
openModal({
children: (
<>
{server?.type === ServerType.NAVIDROME ? (
<NavidromeAlbumFilters
disableArtistFilter={!!customFilters}
handleFilterChange={handleFilterChange}
/>
) : (
<JellyfinAlbumFilters
disableArtistFilter={!!customFilters}
handleFilterChange={handleFilterChange}
/>
)}
</>
),
title: 'Album Filters',
});
};
const handleRefresh = useCallback(() => {
queryClient.invalidateQueries(queryKeys.albums.list(server?.id || ''));
handleFilterChange(filters);
@ -315,7 +364,19 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
const handlePlay = async (play: Play) => {
if (!itemCount || itemCount === 0) return;
const query = { startIndex: 0, ...filters };
const query = {
startIndex: 0,
...filters,
...customFilters,
jfParams: {
...filters.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...filters.ndParams,
...customFilters?.ndParams,
},
};
const queryKey = queryKeys.albums.list(server?.id || '', query);
const albumListRes = await queryClient.fetchQuery({
@ -355,9 +416,11 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
<Group noWrap>
<TextTitle
fw="bold"
maw="20vw"
order={3}
overflow="hidden"
>
Albums
{title || 'Albums'}
</TextTitle>
<Badge
radius="xl"
@ -509,24 +572,14 @@ export const AlbumListHeader = ({ itemCount, gridRef, tableRef }: AlbumListHeade
</DropdownMenu.Dropdown>
</DropdownMenu>
)}
<Popover position="bottom-start">
<Popover.Target>
<Button
compact
fw="600"
variant="subtle"
>
{cq.isMd ? 'Filters' : <RiFilter3Line size={15} />}
</Button>
</Popover.Target>
<Popover.Dropdown>
{server?.type === ServerType.NAVIDROME ? (
<NavidromeAlbumFilters handleFilterChange={handleFilterChange} />
) : (
<JellyfinAlbumFilters handleFilterChange={handleFilterChange} />
)}
</Popover.Dropdown>
</Popover>
<Button
compact
fw="600"
variant="subtle"
onClick={handleOpenFiltersModal}
>
{cq.isMd ? 'Filters' : <RiFilter3Line size={15} />}
</Button>
<DropdownMenu position="bottom-start">
<DropdownMenu.Target>
<Button

View File

@ -1,15 +1,22 @@
import { ChangeEvent, useMemo } from 'react';
import { ChangeEvent, useMemo, useState } from 'react';
import { Divider, Group, Stack } from '@mantine/core';
import { MultiSelect, NumberInput, Switch, Text } from '/@/renderer/components';
import { MultiSelect, NumberInput, SpinnerIcon, Switch, Text } from '/@/renderer/components';
import { AlbumListFilter, useAlbumListStore, useSetAlbumFilters } from '/@/renderer/store';
import debounce from 'lodash/debounce';
import { useGenreList } from '/@/renderer/features/genres';
import { useDebouncedValue } from '@mantine/hooks';
import { AlbumArtistListSort, SortOrder } from '/@/renderer/api/types';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
interface JellyfinAlbumFiltersProps {
disableArtistFilter?: boolean;
handleFilterChange: (filters: AlbumListFilter) => void;
}
export const JellyfinAlbumFilters = ({ handleFilterChange }: JellyfinAlbumFiltersProps) => {
export const JellyfinAlbumFilters = ({
disableArtistFilter,
handleFilterChange,
}: JellyfinAlbumFiltersProps) => {
const { filter } = useAlbumListStore();
const setFilters = useSetAlbumFilters();
@ -74,46 +81,33 @@ export const JellyfinAlbumFilters = ({ handleFilterChange }: JellyfinAlbumFilter
handleFilterChange(updatedFilters);
}, 250);
const [albumArtistSearchTerm, setAlbumArtistSearchTerm] = useState<string>('');
const [debouncedSearchTerm] = useDebouncedValue(albumArtistSearchTerm, 200);
const albumArtistListQuery = useAlbumArtistList(
{
limit: 300,
searchTerm: debouncedSearchTerm,
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
{
enabled: debouncedSearchTerm ? debouncedSearchTerm !== '' : false,
},
);
const selectableAlbumArtists = useMemo(() => {
if (!albumArtistListQuery?.data?.items) return [];
return albumArtistListQuery?.data?.items?.map((artist) => ({
label: artist.name,
value: artist.id,
}));
}, [albumArtistListQuery?.data?.items]);
return (
<Stack p="0.8rem">
<Group position="apart">
<Text>Year range</Text>
<Group>
<NumberInput
required
hideControls={false}
max={2300}
min={1700}
value={filter.jfParams?.minYear}
width={80}
onChange={handleMinYearFilter}
/>
<NumberInput
hideControls={false}
max={2300}
min={1700}
value={filter.jfParams?.maxYear}
width={80}
onChange={handleMaxYearFilter}
/>
</Group>
</Group>
<Divider my="0.5rem" />
<Group
position="apart"
spacing={20}
>
<Text>Genres</Text>
<MultiSelect
clearable
searchable
data={genreList}
defaultValue={selectedGenres}
width={250}
onChange={handleGenresFilter}
/>
</Group>
<Divider my="0.5rem" />
{toggleFilters.map((filter) => (
<Group
key={`nd-filter-${filter.label}`}
@ -127,14 +121,52 @@ export const JellyfinAlbumFilters = ({ handleFilterChange }: JellyfinAlbumFilter
/>
</Group>
))}
{/* <Divider my="0.5rem" />
<Stack>
<Text>Tags</Text>
<MultiSelect
disabled
data={[]}
<Divider my="0.5rem" />
<Group grow>
<NumberInput
hideControls={false}
label="From year"
max={2300}
min={1700}
required={!!filter.jfParams?.maxYear}
value={filter.jfParams?.minYear}
onChange={handleMinYearFilter}
/>
</Stack> */}
<NumberInput
hideControls={false}
label="To year"
max={2300}
min={1700}
required={!!filter.jfParams?.minYear}
value={filter.jfParams?.maxYear}
onChange={handleMaxYearFilter}
/>
</Group>
<Group grow>
<MultiSelect
clearable
searchable
data={genreList}
defaultValue={selectedGenres}
label="Genres"
onChange={handleGenresFilter}
/>
</Group>
<Group grow>
<MultiSelect
clearable
searchable
data={selectableAlbumArtists}
disabled={disableArtistFilter}
label="Artist"
limit={300}
placeholder="Type to search for an artist"
rightSection={albumArtistListQuery.isFetching ? <SpinnerIcon /> : undefined}
searchValue={albumArtistSearchTerm}
onSearchChange={setAlbumArtistSearchTerm}
/>
</Group>
</Stack>
);
};

View File

@ -1,15 +1,22 @@
import { ChangeEvent, useMemo } from 'react';
import { ChangeEvent, useMemo, useState } from 'react';
import { Divider, Group, Stack } from '@mantine/core';
import { NumberInput, Switch, Text, Select } from '/@/renderer/components';
import { NumberInput, Switch, Text, Select, SpinnerIcon } from '/@/renderer/components';
import { AlbumListFilter, useAlbumListStore, useSetAlbumFilters } from '/@/renderer/store';
import { useDebouncedValue } from '@mantine/hooks';
import debounce from 'lodash/debounce';
import { useGenreList } from '/@/renderer/features/genres';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
import { AlbumArtistListSort, SortOrder } from '/@/renderer/api/types';
interface NavidromeAlbumFiltersProps {
disableArtistFilter?: boolean;
handleFilterChange: (filters: AlbumListFilter) => void;
}
export const NavidromeAlbumFilters = ({ handleFilterChange }: NavidromeAlbumFiltersProps) => {
export const NavidromeAlbumFilters = ({
handleFilterChange,
disableArtistFilter,
}: NavidromeAlbumFiltersProps) => {
const { filter } = useAlbumListStore();
const setFilters = useSetAlbumFilters();
@ -89,35 +96,33 @@ export const NavidromeAlbumFilters = ({ handleFilterChange }: NavidromeAlbumFilt
handleFilterChange(updatedFilters);
}, 500);
const [albumArtistSearchTerm, setAlbumArtistSearchTerm] = useState<string>('');
const [debouncedSearchTerm] = useDebouncedValue(albumArtistSearchTerm, 200);
const albumArtistListQuery = useAlbumArtistList(
{
limit: 300,
searchTerm: debouncedSearchTerm,
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
{
enabled: debouncedSearchTerm ? debouncedSearchTerm !== '' : false,
},
);
const selectableAlbumArtists = useMemo(() => {
if (!albumArtistListQuery?.data?.items) return [];
return albumArtistListQuery?.data?.items?.map((artist) => ({
label: artist.name,
value: artist.id,
}));
}, [albumArtistListQuery?.data?.items]);
return (
<Stack p="0.8rem">
<Group position="apart">
<Text>Year</Text>
<NumberInput
hideControls={false}
max={5000}
min={0}
value={filter.ndParams?.year}
width={80}
onChange={handleYearFilter}
/>
</Group>
<Divider my="0.5rem" />
<Group
position="apart"
spacing={20}
>
<Text>Genre</Text>
<Select
clearable
searchable
data={genreList}
defaultValue={filter.ndParams?.genre_id}
width={150}
onChange={handleGenresFilter}
/>
</Group>
<Divider my="0.5rem" />
{toggleFilters.map((filter) => (
<Group
key={`nd-filter-${filter.label}`}
@ -130,6 +135,39 @@ export const NavidromeAlbumFilters = ({ handleFilterChange }: NavidromeAlbumFilt
/>
</Group>
))}
<Divider my="0.5rem" />
<Group grow>
<NumberInput
hideControls={false}
label="Year"
max={5000}
min={0}
value={filter.ndParams?.year}
onChange={handleYearFilter}
/>
<Select
clearable
searchable
data={genreList}
defaultValue={filter.ndParams?.genre_id}
label="Genre"
onChange={handleGenresFilter}
/>
</Group>
<Group grow>
<Select
clearable
searchable
data={selectableAlbumArtists}
disabled={disableArtistFilter}
label="Artist"
limit={300}
placeholder="Type to search for an artist"
rightSection={albumArtistListQuery.isFetching ? <SpinnerIcon /> : undefined}
searchValue={albumArtistSearchTerm}
onSearchChange={setAlbumArtistSearchTerm}
/>
</Group>
</Stack>
);
};

View File

@ -5,18 +5,49 @@ import { AlbumListContent } from '/@/renderer/features/albums/components/album-l
import { useRef } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query';
import { useAlbumListFilters } from '/@/renderer/store';
import { useAlbumListFilters, useCurrentServer } from '/@/renderer/store';
import { useSearchParams } from 'react-router-dom';
import { AlbumListQuery, ServerType } from '/@/renderer/api/types';
const AlbumListRoute = () => {
const gridRef = useRef<VirtualInfiniteGridRef | null>(null);
const tableRef = useRef<AgGridReactType | null>(null);
const filters = useAlbumListFilters();
const server = useCurrentServer();
const [searchParams] = useSearchParams();
const customFilters: Partial<AlbumListQuery> | undefined = searchParams.get('artistId')
? {
jfParams:
server?.type === ServerType.JELLYFIN
? {
artistIds: searchParams.get('artistId') as string,
}
: undefined,
ndParams:
server?.type === ServerType.NAVIDROME
? {
artist_id: searchParams.get('artistId') as string,
}
: undefined,
}
: undefined;
const itemCountCheck = useAlbumList(
{
limit: 1,
startIndex: 0,
...filters,
...customFilters,
jfParams: {
...filters.jfParams,
...customFilters?.jfParams,
},
ndParams: {
...filters.ndParams,
...customFilters?.ndParams,
},
},
{
cacheTime: 1000 * 60 * 60 * 2,
@ -33,11 +64,14 @@ const AlbumListRoute = () => {
<AnimatedPage>
<VirtualGridContainer>
<AlbumListHeader
customFilters={customFilters}
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}
title={searchParams.get('artistName') || undefined}
/>
<AlbumListContent
customFilters={customFilters}
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}

View File

@ -13,7 +13,7 @@ import { Box, Group, Stack } from '@mantine/core';
import { RiArrowDownSLine, RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri';
import { generatePath, useParams } from 'react-router';
import { useCurrentServer } from '/@/renderer/store';
import { Link } from 'react-router-dom';
import { createSearchParams, Link } from 'react-router-dom';
import styled from 'styled-components';
import { AppRoute } from '/@/renderer/router/routes';
import { useContainerQuery } from '/@/renderer/hooks';
@ -66,6 +66,13 @@ export const AlbumArtistDetailContent = () => {
const detailQuery = useAlbumArtistDetail({ id: albumArtistId });
const artistDiscographyLink = `${generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY, {
albumArtistId,
})}?${createSearchParams({
artistId: albumArtistId,
artistName: detailQuery?.data?.name || '',
})}`;
const recentAlbumsQuery = useAlbumList({
jfParams: server?.type === ServerType.JELLYFIN ? { artistIds: albumArtistId } : undefined,
limit: itemsPerPage,
@ -146,9 +153,7 @@ export const AlbumArtistDetailContent = () => {
compact
uppercase
component={Link}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY, {
albumArtistId,
})}
to={artistDiscographyLink}
variant="subtle"
>
View discography
@ -283,9 +288,7 @@ export const AlbumArtistDetailContent = () => {
compact
uppercase
component={Link}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY, {
albumArtistId,
})}
to={artistDiscographyLink}
variant="subtle"
>
View discography
@ -302,7 +305,6 @@ export const AlbumArtistDetailContent = () => {
</Group>
</Group>
</Box>
{showGenres && (
<Box component="section">
<Group>

View File

@ -58,10 +58,6 @@ const AlbumArtistDetailTopSongsListRoute = lazy(
() => import('../features/artists/routes/album-artist-detail-top-songs-list-route'),
);
const AlbumArtistDetailDiscographyRoute = lazy(
() => import('../features/artists/routes/album-artist-detail-discography-route'),
);
const AlbumDetailRoute = lazy(
() => import('/@/renderer/features/albums/routes/album-detail-route'),
);
@ -141,7 +137,7 @@ export const AppRouter = () => {
element={<AlbumArtistDetailRoute />}
/>
<Route
element={<AlbumArtistDetailDiscographyRoute />}
element={<AlbumListRoute />}
path={AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY}
/>
<Route