diff --git a/src/renderer/components/card/poster-card.tsx b/src/renderer/components/card/poster-card.tsx
index 8a2036957..8704edb43 100644
--- a/src/renderer/components/card/poster-card.tsx
+++ b/src/renderer/components/card/poster-card.tsx
@@ -4,7 +4,6 @@ import { generatePath, Link } from 'react-router-dom';
import styles from './poster-card.module.css';
import { CardRows } from '/@/renderer/components/card/card-rows';
-import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/grid-card-controls';
import { Image } from '/@/shared/components/image/image';
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
import { Stack } from '/@/shared/components/stack/stack';
@@ -57,12 +56,12 @@ export const PosterCard = ({
>
-
+ /> */}
diff --git a/src/renderer/components/virtual-table/hooks/use-virtual-table.ts b/src/renderer/components/virtual-table/hooks/use-virtual-table.ts
index ec105303d..d39d4b580 100644
--- a/src/renderer/components/virtual-table/hooks/use-virtual-table.ts
+++ b/src/renderer/components/virtual-table/hooks/use-virtual-table.ts
@@ -30,7 +30,7 @@ import {
LibraryItem,
ServerListItem,
} from '/@/shared/types/domain-types';
-import { ListDisplayType, TablePagination } from '/@/shared/types/types';
+import { ListDisplayType, ListPagination } from '/@/shared/types/types';
export type AgGridFetchFn
= (
args: { filter: TFilter; limit: number; startIndex: number },
@@ -227,7 +227,7 @@ export const useVirtualTable = >({
);
const setParamsTablePagination = useCallback(
- (args: { data: Partial; key: ListKey }) => {
+ (args: { data: Partial; key: ListKey }) => {
const { data } = args;
setSearchParams(
diff --git a/src/renderer/components/virtual-table/index.tsx b/src/renderer/components/virtual-table/index.tsx
index 2e06b9f4b..23999304f 100644
--- a/src/renderer/components/virtual-table/index.tsx
+++ b/src/renderer/components/virtual-table/index.tsx
@@ -50,7 +50,7 @@ import {
import {
PlayerStatus,
TableColumn,
- TablePagination as TablePaginationType,
+ ListPagination as TablePaginationType,
} from '/@/shared/types/types';
export * from './hooks/use-click-outside-deselect';
diff --git a/src/renderer/components/virtual-table/table-config-dropdown.tsx b/src/renderer/components/virtual-table/table-config-dropdown.tsx
index bf6b56d1a..cce9a1a65 100644
--- a/src/renderer/components/virtual-table/table-config-dropdown.tsx
+++ b/src/renderer/components/virtual-table/table-config-dropdown.tsx
@@ -8,13 +8,17 @@ import { MultiSelect } from '/@/shared/components/multi-select/multi-select';
import { Option } from '/@/shared/components/option/option';
import { Slider } from '/@/shared/components/slider/slider';
import { Switch } from '/@/shared/components/switch/switch';
-import { TableColumn, TableType } from '/@/shared/types/types';
+import { ItemListKey, TableColumn } from '/@/shared/types/types';
export const SONG_TABLE_COLUMNS = [
{
label: i18n.t('table.config.label.rowIndex', { postProcess: 'titleCase' }),
value: TableColumn.ROW_INDEX,
},
+ {
+ label: i18n.t('table.config.label.image', { postProcess: 'titleCase' }),
+ value: TableColumn.IMAGE,
+ },
{
label: i18n.t('table.config.label.title', { postProcess: 'titleCase' }),
value: TableColumn.TITLE,
@@ -43,6 +47,10 @@ export const SONG_TABLE_COLUMNS = [
label: i18n.t('table.config.label.genre', { postProcess: 'titleCase' }),
value: TableColumn.GENRE,
},
+ {
+ label: i18n.t('table.config.label.genreBadge', { postProcess: 'titleCase' }),
+ value: TableColumn.GENRE_BADGE,
+ },
{
label: i18n.t('table.config.label.year', { postProcess: 'titleCase' }),
value: TableColumn.YEAR,
@@ -119,6 +127,10 @@ export const ALBUM_TABLE_COLUMNS = [
label: i18n.t('table.config.label.rowIndex', { postProcess: 'titleCase' }),
value: TableColumn.ROW_INDEX,
},
+ {
+ label: i18n.t('table.config.label.image', { postProcess: 'titleCase' }),
+ value: TableColumn.IMAGE,
+ },
{
label: i18n.t('table.config.label.title', { postProcess: 'titleCase' }),
value: TableColumn.TITLE,
@@ -147,6 +159,10 @@ export const ALBUM_TABLE_COLUMNS = [
label: i18n.t('table.config.label.genre', { postProcess: 'titleCase' }),
value: TableColumn.GENRE,
},
+ {
+ label: i18n.t('table.config.label.genreBadge', { postProcess: 'titleCase' }),
+ value: TableColumn.GENRE_BADGE,
+ },
{
label: i18n.t('table.config.label.year', { postProcess: 'titleCase' }),
value: TableColumn.YEAR,
@@ -241,6 +257,10 @@ export const PLAYLIST_TABLE_COLUMNS = [
label: i18n.t('table.config.label.rowIndex', { postProcess: 'titleCase' }),
value: TableColumn.ROW_INDEX,
},
+ {
+ label: i18n.t('table.config.label.image', { postProcess: 'titleCase' }),
+ value: TableColumn.IMAGE,
+ },
{
label: i18n.t('table.config.label.title', { postProcess: 'titleCase' }),
value: TableColumn.TITLE,
@@ -284,23 +304,23 @@ export const GENRE_TABLE_COLUMNS = [
interface TableConfigDropdownProps {
// tableRef?: MutableRefObject | null>;
- type: TableType;
+ type: ItemListKey;
}
export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const { t } = useTranslation();
const { setSettings } = useSettingsStoreActions();
- const tableConfig = useSettingsStore((state) => state.tables);
+ const tableConfig = useSettingsStore((state) => state.lists);
const handleAddOrRemoveColumns = (values: string[]) => {
const existingColumns = tableConfig[type].columns;
if (values.length === 0) {
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
columns: [],
},
},
@@ -312,10 +332,10 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
if (values.length > existingColumns.length) {
const newColumn = { column: values[values.length - 1] };
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
columns: [...existingColumns, newColumn],
},
},
@@ -328,10 +348,10 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const newColumns = existingColumns.filter((column) => !removed.includes(column));
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
columns: newColumns,
},
},
@@ -341,10 +361,10 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const handleUpdateRowHeight = (value: number) => {
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
rowHeight: value,
},
},
@@ -353,10 +373,10 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const handleUpdateAutoFit = (e: ChangeEvent) => {
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
autoFit: e.currentTarget.checked,
},
},
@@ -365,10 +385,10 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
const handleUpdateFollow = (e: ChangeEvent) => {
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
followCurrentSong: e.currentTarget.checked,
},
},
diff --git a/src/renderer/components/virtual-table/table-pagination.tsx b/src/renderer/components/virtual-table/table-pagination.tsx
index b59d22af7..14e62a852 100644
--- a/src/renderer/components/virtual-table/table-pagination.tsx
+++ b/src/renderer/components/virtual-table/table-pagination.tsx
@@ -14,7 +14,7 @@ import { NumberInput } from '/@/shared/components/number-input/number-input';
import { Pagination } from '/@/shared/components/pagination/pagination';
import { Popover } from '/@/shared/components/popover/popover';
import { Text } from '/@/shared/components/text/text';
-import { TablePagination as TablePaginationType } from '/@/shared/types/types';
+import { ListPagination as TablePaginationType } from '/@/shared/types/types';
interface TablePaginationProps {
pageKey: ListKey;
diff --git a/src/renderer/features/artists/components/album-artist-detail-top-songs-list-content.tsx b/src/renderer/features/artists/components/album-artist-detail-top-songs-list-content.tsx
deleted file mode 100644
index 04fdcdbbb..000000000
--- a/src/renderer/features/artists/components/album-artist-detail-top-songs-list-content.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import type { RowDoubleClickedEvent } from '@ag-grid-community/core';
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { MutableRefObject } from 'react';
-
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
-import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
-import { useListContext } from '/@/renderer/context/list-context';
-import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
-import { useCurrentServer } from '/@/renderer/store';
-import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
-import { LibraryItem, QueueSong, SongListQuery } from '/@/shared/types/domain-types';
-
-interface AlbumArtistSongListContentProps {
- data: QueueSong[];
- tableRef: MutableRefObject;
-}
-
-export const AlbumArtistDetailTopSongsListContent = ({
- data,
- tableRef,
-}: AlbumArtistSongListContentProps) => {
- const server = useCurrentServer();
- const { id, pageKey } = useListContext();
-
- const handlePlayQueueAdd = usePlayQueueAdd();
- const playButtonBehavior = usePlayButtonBehavior();
-
- const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
- if (!e.data) return;
-
- const rowData: QueueSong[] = [];
- e.api.forEachNode((node) => {
- if (!node.data) return;
- rowData.push(node.data);
- });
-
- handlePlayQueueAdd?.({
- byData: rowData,
- initialSongId: e.data.id,
- playType: playButtonBehavior,
- });
- };
-
- const customFilters: Partial = {
- ...(id && { artistIds: [id] }),
- };
-
- const { rowClassRules } = useCurrentSongRowStyles({ tableRef });
-
- const tableProps = useVirtualTable({
- contextMenu: SONG_CONTEXT_MENU_ITEMS,
- customFilters,
- itemType: LibraryItem.SONG,
- pageKey,
- server,
- tableRef,
- });
-
- return (
- <>
-
- data.data.uniqueId}
- onRowDoubleClicked={handleRowDoubleClick}
- rowClassRules={rowClassRules}
- rowData={data}
- rowModelType="clientSide"
- rowSelection="multiple"
- />
-
- >
- );
-};
diff --git a/src/renderer/features/artists/components/album-artist-list-grid-view.tsx b/src/renderer/features/artists/components/album-artist-list-grid-view.tsx
deleted file mode 100644
index ae9116cbe..000000000
--- a/src/renderer/features/artists/components/album-artist-list-grid-view.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import { QueryKey, useQueryClient } from '@tanstack/react-query';
-import { MutableRefObject, useCallback, useMemo } from 'react';
-import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
-import { ListOnScrollProps } from 'react-window';
-
-import { api } from '/@/renderer/api';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { ALBUMARTIST_CARD_ROWS } from '/@/renderer/components/card/card-rows';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import {
- VirtualInfiniteGrid,
- VirtualInfiniteGridRef,
-} from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
-import { useListContext } from '/@/renderer/context/list-context';
-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';
-import {
- AlbumArtist,
- AlbumArtistListQuery,
- AlbumArtistListResponse,
- AlbumArtistListSort,
- LibraryItem,
-} from '/@/shared/types/domain-types';
-import { CardRow, ListDisplayType } from '/@/shared/types/types';
-
-interface AlbumArtistListGridViewProps {
- gridRef: MutableRefObject;
- itemCount?: number;
-}
-
-export const AlbumArtistListGridView = ({ gridRef, itemCount }: AlbumArtistListGridViewProps) => {
- const queryClient = useQueryClient();
- const server = useCurrentServer();
- const handlePlayQueueAdd = usePlayQueueAdd();
-
- const { pageKey } = useListContext();
- const { display, filter, grid } = useListStoreByKey({ key: pageKey });
- const { setGrid } = useListStoreActions();
- const handleFavorite = useHandleFavorite({ gridRef });
-
- const fetchInitialData = useCallback(() => {
- const query: Omit = {
- ...filter,
- };
-
- const queriesFromCache: [QueryKey, AlbumArtistListResponse | undefined][] =
- queryClient.getQueriesData({
- exact: false,
- fetchStatus: 'idle',
- queryKey: queryKeys.albumArtists.list(server?.id || '', query),
- stale: false,
- });
-
- const itemData: AlbumArtist[] = [];
-
- for (const [, data] of queriesFromCache) {
- const { items, startIndex } = data || {};
-
- if (items && items.length !== 1 && startIndex !== undefined) {
- let itemIndex = 0;
- for (
- let rowIndex = startIndex;
- rowIndex < startIndex + items.length;
- rowIndex += 1
- ) {
- itemData[rowIndex] = items[itemIndex];
- itemIndex += 1;
- }
- }
- }
-
- return itemData;
- }, [filter, queryClient, server?.id]);
-
- const fetch = useCallback(
- async ({ skip: startIndex, take: limit }: { skip: number; take: number }) => {
- const query: AlbumArtistListQuery = {
- ...filter,
- limit,
- startIndex,
- };
-
- const queryKey = queryKeys.albumArtists.list(server?.id || '', query);
-
- const albumArtistsRes = await queryClient.fetchQuery({
- gcTime: 1000 * 60 * 1,
- queryFn: async ({ signal }) =>
- api.controller.getAlbumArtistList({
- apiClientProps: {
- serverId: server?.id || '',
- signal,
- },
- query,
- }),
- queryKey,
- });
-
- return albumArtistsRes;
- },
- [filter, queryClient, server],
- );
-
- const handleGridScroll = useCallback(
- (e: ListOnScrollProps) => {
- setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey });
- },
- [pageKey, setGrid],
- );
-
- const cardRows = useMemo(() => {
- const rows: CardRow[] = [ALBUMARTIST_CARD_ROWS.name];
-
- switch (filter.sortBy) {
- case AlbumArtistListSort.ALBUM_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.albumCount);
- break;
- case AlbumArtistListSort.DURATION:
- rows.push(ALBUMARTIST_CARD_ROWS.duration);
- break;
- case AlbumArtistListSort.FAVORITED:
- break;
- case AlbumArtistListSort.NAME:
- break;
- case AlbumArtistListSort.PLAY_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.playCount);
- break;
- case AlbumArtistListSort.RANDOM:
- break;
- case AlbumArtistListSort.RATING:
- rows.push(ALBUMARTIST_CARD_ROWS.rating);
- break;
- case AlbumArtistListSort.RECENTLY_ADDED:
- break;
- case AlbumArtistListSort.RELEASE_DATE:
- break;
- case AlbumArtistListSort.SONG_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.songCount);
- break;
- }
-
- return rows;
- }, [filter.sortBy]);
-
- return (
-
-
- {({ height, width }: Size) => (
-
- )}
-
-
- );
-};
diff --git a/src/renderer/features/artists/components/album-artist-list-table-view.tsx b/src/renderer/features/artists/components/album-artist-list-table-view.tsx
deleted file mode 100644
index d7f8e81cc..000000000
--- a/src/renderer/features/artists/components/album-artist-list-table-view.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { MutableRefObject } from 'react';
-
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
-import { useListContext } from '/@/renderer/context/list-context';
-import { ARTIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { useCurrentServer } from '/@/renderer/store';
-import { LibraryItem } from '/@/shared/types/domain-types';
-
-interface AlbumArtistListTableViewProps {
- itemCount?: number;
- tableRef: MutableRefObject;
-}
-
-export const AlbumArtistListTableView = ({
- itemCount,
- tableRef,
-}: AlbumArtistListTableViewProps) => {
- const server = useCurrentServer();
- const { pageKey } = useListContext();
-
- const tableProps = useVirtualTable({
- contextMenu: ARTIST_CONTEXT_MENU_ITEMS,
- itemCount,
- itemType: LibraryItem.ALBUM_ARTIST,
- pageKey,
- server,
- tableRef,
- });
-
- return (
-
-
-
- );
-};
diff --git a/src/renderer/features/artists/components/artist-list-grid-view.tsx b/src/renderer/features/artists/components/artist-list-grid-view.tsx
deleted file mode 100644
index 47900da28..000000000
--- a/src/renderer/features/artists/components/artist-list-grid-view.tsx
+++ /dev/null
@@ -1,178 +0,0 @@
-import { QueryKey, useQueryClient } from '@tanstack/react-query';
-import { MutableRefObject, useCallback, useMemo } from 'react';
-import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
-import { ListOnScrollProps } from 'react-window';
-
-import { api } from '/@/renderer/api';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { ALBUMARTIST_CARD_ROWS } from '/@/renderer/components/card/card-rows';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import {
- VirtualInfiniteGrid,
- VirtualInfiniteGridRef,
-} from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
-import { useListContext } from '/@/renderer/context/list-context';
-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 } from '/@/renderer/store';
-import { useListStoreByKey } from '/@/renderer/store/list.store';
-import {
- AlbumArtist,
- ArtistListQuery,
- ArtistListResponse,
- ArtistListSort,
- LibraryItem,
-} from '/@/shared/types/domain-types';
-import { CardRow, ListDisplayType } from '/@/shared/types/types';
-
-interface ArtistListGridViewProps {
- gridRef: MutableRefObject;
- itemCount?: number;
-}
-
-export const ArtistListGridView = ({ gridRef, itemCount }: ArtistListGridViewProps) => {
- const queryClient = useQueryClient();
- const server = useCurrentServer();
- const handlePlayQueueAdd = usePlayQueueAdd();
-
- const { pageKey } = useListContext();
- const { display, filter, grid } = useListStoreByKey({ key: pageKey });
- const { setGrid } = useListStoreActions();
- const handleFavorite = useHandleFavorite({ gridRef });
-
- const fetchInitialData = useCallback(() => {
- const query: Omit = {
- ...filter,
- };
-
- const queriesFromCache: [QueryKey, ArtistListResponse | undefined][] =
- queryClient.getQueriesData({
- exact: false,
- fetchStatus: 'idle',
- queryKey: queryKeys.artists.list(server?.id || '', query),
- stale: false,
- });
-
- const itemData: AlbumArtist[] = [];
-
- for (const [, data] of queriesFromCache) {
- const { items, startIndex } = data || {};
-
- if (items && items.length !== 1 && startIndex !== undefined) {
- let itemIndex = 0;
- for (
- let rowIndex = startIndex;
- rowIndex < startIndex + items.length;
- rowIndex += 1
- ) {
- itemData[rowIndex] = items[itemIndex];
- itemIndex += 1;
- }
- }
- }
-
- return itemData;
- }, [filter, queryClient, server?.id]);
-
- const fetch = useCallback(
- async ({ skip: startIndex, take: limit }: { skip: number; take: number }) => {
- const query: ArtistListQuery = {
- ...filter,
- limit,
- startIndex,
- };
-
- const queryKey = queryKeys.artists.list(server?.id || '', query);
-
- const artistsRes = await queryClient.fetchQuery({
- gcTime: 1000 * 60 * 1,
- queryFn: async ({ signal }) =>
- api.controller.getArtistList({
- apiClientProps: {
- serverId: server?.id || '',
- signal,
- },
- query,
- }),
- queryKey,
- });
-
- return artistsRes;
- },
- [filter, queryClient, server],
- );
-
- const handleGridScroll = useCallback(
- (e: ListOnScrollProps) => {
- setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey });
- },
- [pageKey, setGrid],
- );
-
- const cardRows = useMemo(() => {
- const rows: CardRow[] = [ALBUMARTIST_CARD_ROWS.name];
-
- switch (filter.sortBy) {
- case ArtistListSort.ALBUM_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.albumCount);
- break;
- case ArtistListSort.DURATION:
- rows.push(ALBUMARTIST_CARD_ROWS.duration);
- break;
- case ArtistListSort.FAVORITED:
- break;
- case ArtistListSort.NAME:
- break;
- case ArtistListSort.PLAY_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.playCount);
- break;
- case ArtistListSort.RANDOM:
- break;
- case ArtistListSort.RATING:
- rows.push(ALBUMARTIST_CARD_ROWS.rating);
- break;
- case ArtistListSort.RECENTLY_ADDED:
- break;
- case ArtistListSort.RELEASE_DATE:
- break;
- case ArtistListSort.SONG_COUNT:
- rows.push(ALBUMARTIST_CARD_ROWS.songCount);
- break;
- }
-
- return rows;
- }, [filter.sortBy]);
-
- return (
-
-
- {({ height, width }: Size) => (
-
- )}
-
-
- );
-};
diff --git a/src/renderer/features/artists/components/artist-list-table-view.tsx b/src/renderer/features/artists/components/artist-list-table-view.tsx
deleted file mode 100644
index d7c247cb2..000000000
--- a/src/renderer/features/artists/components/artist-list-table-view.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { MutableRefObject } from 'react';
-
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
-import { useListContext } from '/@/renderer/context/list-context';
-import { ARTIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { useCurrentServer } from '/@/renderer/store';
-import { LibraryItem } from '/@/shared/types/domain-types';
-
-interface ArtistListTableViewProps {
- itemCount?: number;
- tableRef: MutableRefObject;
-}
-
-export const ArtistListTableView = ({ itemCount, tableRef }: ArtistListTableViewProps) => {
- const server = useCurrentServer();
- const { pageKey } = useListContext();
-
- const tableProps = useVirtualTable({
- contextMenu: ARTIST_CONTEXT_MENU_ITEMS,
- itemCount,
- itemType: LibraryItem.ARTIST,
- pageKey,
- server,
- tableRef,
- });
-
- return (
-
-
-
- );
-};
diff --git a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx
index dea8693b5..7078da72f 100644
--- a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx
+++ b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router';
import { ListContext } from '/@/renderer/context/list-context';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
-import { AlbumArtistDetailTopSongsListContent } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-content';
import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header';
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
import { useCurrentServer } from '/@/renderer/store/auth.store';
@@ -54,10 +53,10 @@ const AlbumArtistDetailTopSongsListRoute = () => {
itemCount={itemCount}
title={detailQuery?.data?.name || 'Unknown'}
/>
-
+ /> */}
);
diff --git a/src/renderer/features/artists/routes/album-artist-list-route.tsx b/src/renderer/features/artists/routes/album-artist-list-route.tsx
index 2d1f4852c..235c598c3 100644
--- a/src/renderer/features/artists/routes/album-artist-list-route.tsx
+++ b/src/renderer/features/artists/routes/album-artist-list-route.tsx
@@ -3,10 +3,8 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useQuery } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
-import { AlbumArtistListContent } from '/@/renderer/features/artists/components/album-artist-list-content';
import { AlbumArtistListHeader } from '/@/renderer/features/artists/components/album-artist-list-header';
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
import { useCurrentServer } from '/@/renderer/store/auth.store';
@@ -14,7 +12,7 @@ import { useListFilterByKey } from '/@/renderer/store/list.store';
import { AlbumArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
const AlbumArtistListRoute = () => {
- const gridRef = useRef(null);
+ const gridRef = useRef(null);
const tableRef = useRef(null);
const pageKey = LibraryItem.ALBUM_ARTIST;
const server = useCurrentServer();
@@ -48,11 +46,11 @@ const AlbumArtistListRoute = () => {
itemCount={itemCount}
tableRef={tableRef}
/>
-
+ /> */}
);
diff --git a/src/renderer/features/artists/routes/artist-list-route.tsx b/src/renderer/features/artists/routes/artist-list-route.tsx
index 9ee535aa0..53dbe5a49 100644
--- a/src/renderer/features/artists/routes/artist-list-route.tsx
+++ b/src/renderer/features/artists/routes/artist-list-route.tsx
@@ -3,7 +3,6 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useQuery } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
import { ArtistListContent } from '/@/renderer/features/artists/components/artist-list-content';
@@ -14,7 +13,7 @@ import { useListFilterByKey } from '/@/renderer/store/list.store';
import { ArtistListQuery, LibraryItem } from '/@/shared/types/domain-types';
const ArtistListRoute = () => {
- const gridRef = useRef(null);
+ const gridRef = useRef(null);
const tableRef = useRef(null);
const pageKey = LibraryItem.ARTIST;
const server = useCurrentServer();
@@ -45,7 +44,7 @@ const ArtistListRoute = () => {
-
+ {/* */}
);
diff --git a/src/renderer/features/genres/components/genre-list-grid-view.tsx b/src/renderer/features/genres/components/genre-list-grid-view.tsx
deleted file mode 100644
index 6747c1ac4..000000000
--- a/src/renderer/features/genres/components/genre-list-grid-view.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import { QueryKey, useQueryClient } from '@tanstack/react-query';
-import { useCallback, useMemo } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
-import { ListOnScrollProps } from 'react-window';
-
-import { api } from '/@/renderer/api';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { ALBUM_CARD_ROWS } from '/@/renderer/components/card/card-rows';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualInfiniteGrid } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
-import { useListContext } from '/@/renderer/context/list-context';
-import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
-import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
-import { useCurrentServer, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
-import {
- Album,
- Genre,
- GenreListQuery,
- GenreListResponse,
- LibraryItem,
-} from '/@/shared/types/domain-types';
-import { CardRow, ListDisplayType } from '/@/shared/types/types';
-
-export const GenreListGridView = ({ gridRef, itemCount }: any) => {
- const queryClient = useQueryClient();
- const server = useCurrentServer();
- const handlePlayQueueAdd = usePlayQueueAdd();
- const { id, pageKey } = useListContext();
- const { display, filter, grid } = useListStoreByKey({ key: pageKey });
- const { setGrid } = useListStoreActions();
- const genrePath = useGenreRoute();
-
- const [searchParams, setSearchParams] = useSearchParams();
- const scrollOffset = searchParams.get('scrollOffset');
- const initialScrollOffset = Number(id ? scrollOffset : grid?.scrollOffset) || 0;
-
- const cardRows = useMemo(() => {
- const rows: CardRow[] = [ALBUM_CARD_ROWS.name];
- return rows;
- }, []);
-
- const handleGridScroll = useCallback(
- (e: ListOnScrollProps) => {
- if (id) {
- setSearchParams(
- (params) => {
- params.set('scrollOffset', String(e.scrollOffset));
- return params;
- },
- { replace: true },
- );
- } else {
- setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey });
- }
- },
- [id, pageKey, setGrid, setSearchParams],
- );
-
- const fetchInitialData = useCallback(() => {
- const query: Omit = {
- ...filter,
- };
-
- const queriesFromCache: [QueryKey, GenreListResponse | undefined][] =
- queryClient.getQueriesData({
- exact: false,
- fetchStatus: 'idle',
- queryKey: queryKeys.genres.list(server?.id || '', query),
- stale: false,
- });
-
- const itemData: Genre[] = [];
-
- for (const [, data] of queriesFromCache) {
- const { items, startIndex } = data || {};
-
- if (items && items.length !== 1 && startIndex !== undefined) {
- let itemIndex = 0;
- for (
- let rowIndex = startIndex;
- rowIndex < startIndex + items.length;
- rowIndex += 1
- ) {
- itemData[rowIndex] = items[itemIndex];
- itemIndex += 1;
- }
- }
- }
-
- return itemData;
- }, [filter, queryClient, server?.id]);
-
- const fetch = useCallback(
- async ({ skip, take }: { skip: number; take: number }) => {
- if (!server) {
- return [];
- }
-
- const query: GenreListQuery = {
- ...filter,
- limit: take,
- startIndex: skip,
- };
-
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albums = await queryClient.fetchQuery({
- queryFn: async ({ signal }) => {
- return api.controller.getGenreList({
- apiClientProps: {
- serverId: server?.id || '',
- signal,
- },
- query,
- });
- },
- queryKey,
- });
-
- return albums;
- },
- [filter, queryClient, server],
- );
-
- return (
-
-
- {({ height, width }: Size) => (
-
- )}
-
-
- );
-};
diff --git a/src/renderer/features/genres/components/genre-list-table-view.tsx b/src/renderer/features/genres/components/genre-list-table-view.tsx
deleted file mode 100644
index 1ab131061..000000000
--- a/src/renderer/features/genres/components/genre-list-table-view.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { RowDoubleClickedEvent } from '@ag-grid-community/core';
-import { MutableRefObject, useCallback } from 'react';
-import { generatePath, useNavigate } from 'react-router';
-
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
-import { useListContext } from '/@/renderer/context/list-context';
-import { GENRE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
-import { useCurrentServer } from '/@/renderer/store';
-import { LibraryItem } from '/@/shared/types/domain-types';
-
-interface GenreListTableViewProps {
- itemCount?: number;
- tableRef: MutableRefObject;
-}
-
-export const GenreListTableView = ({ itemCount, tableRef }: GenreListTableViewProps) => {
- const server = useCurrentServer();
- const { customFilters, pageKey } = useListContext();
- const navigate = useNavigate();
- const genrePath = useGenreRoute();
-
- const tableProps = useVirtualTable({
- contextMenu: GENRE_CONTEXT_MENU_ITEMS,
- customFilters,
- itemCount,
- itemType: LibraryItem.GENRE,
- pageKey,
- server,
- tableRef,
- });
-
- const onRowDoubleClicked = useCallback(
- (e: RowDoubleClickedEvent) => {
- const { data } = e;
- if (!data) return;
-
- navigate(generatePath(genrePath, { genreId: data.id }));
- },
- [genrePath, navigate],
- );
-
- return (
-
-
-
- );
-};
diff --git a/src/renderer/features/genres/routes/genre-list-route.tsx b/src/renderer/features/genres/routes/genre-list-route.tsx
index ccc5538f9..5c63b7942 100644
--- a/src/renderer/features/genres/routes/genre-list-route.tsx
+++ b/src/renderer/features/genres/routes/genre-list-route.tsx
@@ -3,10 +3,8 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useQuery } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
-import { GenreListContent } from '/@/renderer/features/genres/components/genre-list-content';
import { GenreListHeader } from '/@/renderer/features/genres/components/genre-list-header';
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
import { useCurrentServer } from '/@/renderer/store';
@@ -14,7 +12,7 @@ import { useListStoreByKey } from '/@/renderer/store/list.store';
import { GenreListQuery } from '/@/shared/types/domain-types';
const GenreListRoute = () => {
- const gridRef = useRef(null);
+ const gridRef = useRef(null);
const tableRef = useRef(null);
const server = useCurrentServer();
const pageKey = 'genre';
@@ -46,7 +44,7 @@ const GenreListRoute = () => {
-
+ {/* */}
);
diff --git a/src/renderer/features/now-playing/components/play-queue-list-controls.tsx b/src/renderer/features/now-playing/components/play-queue-list-controls.tsx
index f7bfdbaf0..4893a7810 100644
--- a/src/renderer/features/now-playing/components/play-queue-list-controls.tsx
+++ b/src/renderer/features/now-playing/components/play-queue-list-controls.tsx
@@ -12,7 +12,7 @@ import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Group } from '/@/shared/components/group/group';
import { Popover } from '/@/shared/components/popover/popover';
import { Song } from '/@/shared/types/domain-types';
-import { TableType } from '/@/shared/types/types';
+import { ItemListKey } from '/@/shared/types/types';
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
@@ -20,7 +20,7 @@ interface PlayQueueListOptionsProps {
handleSearch: (value: string) => void;
searchTerm?: string;
tableRef: MutableRefObject }>;
- type: TableType;
+ type: ItemListKey;
}
export const PlayQueueListControls = ({
diff --git a/src/renderer/features/now-playing/components/play-queue.tsx b/src/renderer/features/now-playing/components/play-queue.tsx
index 72a508c93..880100031 100644
--- a/src/renderer/features/now-playing/components/play-queue.tsx
+++ b/src/renderer/features/now-playing/components/play-queue.tsx
@@ -8,7 +8,6 @@ import debounce from 'lodash/debounce';
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-table';
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
import { QUEUE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
@@ -21,18 +20,16 @@ import {
usePlayerStatus,
} from '/@/renderer/store';
import {
- PersistedTableColumn,
useSettingsStore,
useSettingsStoreActions,
useTableSettings,
} from '/@/renderer/store/settings.store';
import { searchSongs } from '/@/renderer/utils/search-songs';
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
-import { TableType } from '/@/shared/types/types';
+import { ItemListKey } from '/@/shared/types/types';
type QueueProps = {
- searchTerm?: string;
- type: TableType;
+ type: ItemListKey;
};
export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref) => {
@@ -138,7 +135,7 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
const columnsOrder = columnApi?.getAllGridColumns();
if (!columnsOrder) return;
- const columnsInSettings = useSettingsStore.getState().tables[type].columns;
+ const columnsInSettings = useSettingsStore.getState().lists[type].columns;
const updatedColumns: PersistedTableColumn[] = [];
for (const column of columnsOrder) {
@@ -149,7 +146,7 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
if (columnInSettings) {
updatedColumns.push({
...columnInSettings,
- ...(!useSettingsStore.getState().tables[type].autoFit && {
+ ...(!useSettingsStore.getState().lists[type].autoFit && {
width: column.getActualWidth(),
}),
});
@@ -157,10 +154,10 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
}
setSettings({
- tables: {
- ...useSettingsStore.getState().tables,
+ lists: {
+ ...useSettingsStore.getState().lists,
[type]: {
- ...useSettingsStore.getState().tables[type],
+ ...useSettingsStore.getState().lists[type],
columns: updatedColumns,
},
},
diff --git a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
index 8202f1d19..ef7b03a24 100644
--- a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
+++ b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
@@ -2,12 +2,7 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useRef, useState } from 'react';
-import { PlayQueueListControls } from './play-queue-list-controls';
-
-import { VirtualGridContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
import { useWindowSettings } from '/@/renderer/store/settings.store';
-import { Box } from '/@/shared/components/box/box';
import { Song } from '/@/shared/types/domain-types';
import { Platform } from '/@/shared/types/types';
@@ -17,17 +12,6 @@ export const SidebarPlayQueue = () => {
const { windowBarStyle } = useWindowSettings();
const isWeb = windowBarStyle === Platform.WEB;
- return (
-
-
-
-
-
-
- );
+
+ return null;
};
diff --git a/src/renderer/features/now-playing/routes/now-playing-route.tsx b/src/renderer/features/now-playing/routes/now-playing-route.tsx
index cd6e21eb7..c68f9c3f0 100644
--- a/src/renderer/features/now-playing/routes/now-playing-route.tsx
+++ b/src/renderer/features/now-playing/routes/now-playing-route.tsx
@@ -3,10 +3,6 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { useRef, useState } from 'react';
-import { VirtualGridContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { NowPlayingHeader } from '/@/renderer/features/now-playing/components/now-playing-header';
-import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
-import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
const NowPlayingRoute = () => {
@@ -15,16 +11,11 @@ const NowPlayingRoute = () => {
return (
-
+ {/*
-
-
-
+
+
+ */}
);
};
diff --git a/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx b/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx
deleted file mode 100644
index c815a6f8a..000000000
--- a/src/renderer/features/playlists/components/playlist-detail-song-list-content.tsx
+++ /dev/null
@@ -1,312 +0,0 @@
-import type {
- BodyScrollEvent,
- ColDef,
- GridReadyEvent,
- PaginationChangedEvent,
- RowDoubleClickedEvent,
- RowDragEvent,
-} from '@ag-grid-community/core';
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { useQuery, useQueryClient } from '@tanstack/react-query';
-import debounce from 'lodash/debounce';
-import { AnimatePresence } from 'motion/react';
-import { MutableRefObject, useCallback, useMemo } from 'react';
-import { useParams } from 'react-router';
-
-import { api } from '/@/renderer/api';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { getColumnDefs, TablePagination, VirtualTable } from '/@/renderer/components/virtual-table';
-import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
-import {
- PLAYLIST_SONG_CONTEXT_MENU_ITEMS,
- SMART_PLAYLIST_SONG_CONTEXT_MENU_ITEMS,
-} from '/@/renderer/features/context-menu/context-menu-items';
-import { useHandleTableContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
-import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
-import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
-import { useAppFocus } from '/@/renderer/hooks';
-import {
- useCurrentServer,
- usePlayerSong,
- usePlayerStatus,
- usePlaylistDetailStore,
- usePlaylistDetailTablePagination,
- useSetPlaylistDetailTable,
- useSetPlaylistDetailTablePagination,
-} from '/@/renderer/store';
-import { PersistedTableColumn, usePlayButtonBehavior } from '/@/renderer/store/settings.store';
-import { toast } from '/@/shared/components/toast/toast';
-import {
- LibraryItem,
- PlaylistSongListQueryClientSide,
- QueueSong,
- ServerType,
- Song,
- SongListResponse,
- SongListSort,
- SortOrder,
-} from '/@/shared/types/domain-types';
-import { ListDisplayType } from '/@/shared/types/types';
-
-interface PlaylistDetailContentProps {
- songs?: Song[];
- tableRef: MutableRefObject;
-}
-
-export const PlaylistDetailSongListContent = ({ songs, tableRef }: PlaylistDetailContentProps) => {
- const { playlistId } = useParams() as { playlistId: string };
- const queryClient = useQueryClient();
- const status = usePlayerStatus();
- const isFocused = useAppFocus();
- const currentSong = usePlayerSong();
- const server = useCurrentServer();
- const page = usePlaylistDetailStore();
- const filters: PlaylistSongListQueryClientSide = useMemo(() => {
- return {
- sortBy: page?.table.id[playlistId]?.filter?.sortBy || SongListSort.ID,
- sortOrder: page?.table.id[playlistId]?.filter?.sortOrder || SortOrder.ASC,
- };
- }, [page?.table.id, playlistId]);
-
- const detailQuery = useQuery(
- playlistsQueries.detail({ query: { id: playlistId }, serverId: server?.id }),
- );
-
- const p = usePlaylistDetailTablePagination(playlistId);
- const pagination = {
- currentPage: p?.currentPage || 0,
- itemsPerPage: p?.itemsPerPage || 100,
- scrollOffset: p?.scrollOffset || 0,
- totalItems: p?.totalItems || 1,
- totalPages: p?.totalPages || 1,
- };
-
- const setPagination = useSetPlaylistDetailTablePagination();
- const setTable = useSetPlaylistDetailTable();
- const handlePlayQueueAdd = usePlayQueueAdd();
- const playButtonBehavior = usePlayButtonBehavior();
-
- const isPaginationEnabled = page.display === ListDisplayType.TABLE_PAGINATED;
-
- const columnDefs: ColDef[] = useMemo(
- () => getColumnDefs(page.table.columns, false, 'generic'),
- [page.table.columns],
- );
-
- const onGridReady = useCallback(
- (params: GridReadyEvent) => {
- params.api?.ensureIndexVisible(pagination.scrollOffset, 'top');
- },
- [pagination.scrollOffset],
- );
-
- const handleDragEnd = useCallback(
- async (e: RowDragEvent) => {
- if (!e.nodes.length) return;
-
- const trackId = e.node.data?.playlistItemId;
- if (trackId && e.node.rowIndex !== null && e.overIndex !== e.node.rowIndex) {
- try {
- await api.controller.movePlaylistItem({
- apiClientProps: {
- serverId: server?.id || '',
- },
- query: {
- endingIndex: e.overIndex,
- playlistId,
- startingIndex: e.node.rowIndex + 1,
- trackId,
- },
- });
-
- queryClient.setQueryData(
- queryKeys.playlists.songList(server?.id || '', playlistId),
- (previous) => {
- if (previous?.items) {
- const from = e.node.rowIndex!;
- const to = e.overIndex;
-
- const item = previous.items[from];
- const remaining = previous.items.toSpliced(from, 1);
- remaining.splice(to, 0, item);
-
- return {
- error: previous.error,
- items: remaining,
- startIndex: previous.startIndex,
- totalRecordCount: previous.totalRecordCount,
- };
- }
-
- return previous;
- },
- );
-
- // Nodes have to be redrawn, otherwise the row indexes will be wrong
- // Maybe it's possible to only redraw necessary rows to not be as expensive?
- tableRef.current?.api.redrawRows();
- } catch (error) {
- toast.error({
- message: (error as Error).message,
- title: `Failed to move song ${e.node.data?.name} to ${e.overIndex}`,
- });
- }
- }
- },
- [playlistId, queryClient, server, tableRef],
- );
-
- const handleGridSizeChange = () => {
- if (page.table.autoFit) {
- tableRef?.current?.api?.sizeColumnsToFit();
- }
- };
-
- const onPaginationChanged = useCallback(
- (event: PaginationChangedEvent) => {
- if (!isPaginationEnabled || !event.api) return;
-
- try {
- // Scroll to top of page on pagination change
- const currentPageStartIndex = pagination.currentPage * pagination.itemsPerPage;
- event.api?.ensureIndexVisible(currentPageStartIndex, 'top');
- } catch (err) {
- console.error(err);
- }
-
- setPagination(playlistId, {
- itemsPerPage: event.api.paginationGetPageSize(),
- totalItems: event.api.paginationGetRowCount(),
- totalPages: event.api.paginationGetTotalPages() + 1,
- });
- },
- [
- isPaginationEnabled,
- pagination.currentPage,
- pagination.itemsPerPage,
- playlistId,
- setPagination,
- ],
- );
-
- const handleColumnChange = useCallback(() => {
- const { columnApi } = tableRef?.current || {};
- const columnsOrder = columnApi?.getAllGridColumns();
-
- if (!columnsOrder) return;
-
- const columnsInSettings = page.table.columns;
- const updatedColumns: PersistedTableColumn[] = [];
- for (const column of columnsOrder) {
- const columnInSettings = columnsInSettings.find(
- (c) => c.column === column.getColDef().colId,
- );
-
- if (columnInSettings) {
- updatedColumns.push({
- ...columnInSettings,
- ...(!page.table.autoFit && {
- width: column.getActualWidth(),
- }),
- });
- }
- }
-
- setTable({ columns: updatedColumns });
- }, [page.table.autoFit, page.table.columns, setTable, tableRef]);
-
- const debouncedColumnChange = debounce(handleColumnChange, 200);
-
- const handleScroll = (e: BodyScrollEvent) => {
- const scrollOffset = Number((e.top / page.table.rowHeight).toFixed(0));
- setPagination(playlistId, { scrollOffset });
- };
-
- const contextMenuItems = useMemo(() => {
- if (detailQuery?.data?.rules) {
- return SMART_PLAYLIST_SONG_CONTEXT_MENU_ITEMS;
- }
-
- return PLAYLIST_SONG_CONTEXT_MENU_ITEMS;
- }, [detailQuery?.data?.rules]);
-
- const handleContextMenu = useHandleTableContextMenu(LibraryItem.SONG, contextMenuItems, {
- playlistId,
- tableRef,
- });
-
- const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
- if (!e.data) return;
- handlePlayQueueAdd?.({
- byItemType: {
- id: [playlistId],
- type: LibraryItem.PLAYLIST,
- },
- initialSongId: e.data.id,
- playType: playButtonBehavior,
- });
- };
-
- const { rowClassRules } = useCurrentSongRowStyles({ tableRef });
-
- const canDrag =
- filters.sortBy === SongListSort.ID &&
- !detailQuery?.data?.rules &&
- server?.type !== ServerType.SUBSONIC;
-
- return (
- <>
-
- data.data.uniqueId}
- // https://github.com/ag-grid/ag-grid/issues/5284
- // Key is used to force remount of table when display, rowHeight, or server changes
- key={`table-${page.display}-${page.table.rowHeight}-${server?.id}`}
- onBodyScrollEnd={handleScroll}
- onCellContextMenu={handleContextMenu}
- onColumnMoved={handleColumnChange}
- onColumnResized={debouncedColumnChange}
- onGridReady={onGridReady}
- onGridSizeChanged={handleGridSizeChange}
- onPaginationChanged={onPaginationChanged}
- onRowDoubleClicked={handleRowDoubleClick}
- onRowDragEnd={handleDragEnd}
- pagination={isPaginationEnabled}
- paginationAutoPageSize={isPaginationEnabled}
- paginationPageSize={pagination.itemsPerPage || 100}
- ref={tableRef}
- rowClassRules={rowClassRules}
- rowData={songs}
- rowDragEntireRow={canDrag}
- rowHeight={page.table.rowHeight || 40}
- rowModelType="clientSide"
- shouldUpdateSong
- />
-
- {isPaginationEnabled && (
-
- {page.display === ListDisplayType.TABLE_PAGINATED && (
-
- )}
-
- )}
- >
- );
-};
diff --git a/src/renderer/features/playlists/components/playlist-list-grid-view.tsx b/src/renderer/features/playlists/components/playlist-list-grid-view.tsx
deleted file mode 100644
index 1952be18b..000000000
--- a/src/renderer/features/playlists/components/playlist-list-grid-view.tsx
+++ /dev/null
@@ -1,174 +0,0 @@
-import { QueryKey, useQueryClient } from '@tanstack/react-query';
-import { MutableRefObject, useCallback, useMemo } from 'react';
-import AutoSizer, { Size } from 'react-virtualized-auto-sizer';
-import { ListOnScrollProps } from 'react-window';
-
-import { controller } from '/@/renderer/api/controller';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { PLAYLIST_CARD_ROWS } from '/@/renderer/components/card/card-rows';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import {
- VirtualInfiniteGrid,
- VirtualInfiniteGridRef,
-} from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
-import { useListContext } from '/@/renderer/context/list-context';
-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, useListStoreByKey } from '/@/renderer/store';
-import { useListStoreActions } from '/@/renderer/store/list.store';
-import {
- LibraryItem,
- Playlist,
- PlaylistListQuery,
- PlaylistListResponse,
- PlaylistListSort,
-} from '/@/shared/types/domain-types';
-import { CardRow, ListDisplayType } from '/@/shared/types/types';
-
-interface PlaylistListGridViewProps {
- gridRef: MutableRefObject;
- itemCount?: number;
-}
-
-export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridViewProps) => {
- const { pageKey } = useListContext();
- const queryClient = useQueryClient();
- const server = useCurrentServer();
- const handlePlayQueueAdd = usePlayQueueAdd();
- const { display, filter, grid } = useListStoreByKey({ key: pageKey });
- const { setGrid } = useListStoreActions();
- const handleFavorite = useHandleFavorite({ gridRef });
-
- const cardRows = useMemo(() => {
- const rows: CardRow[] = [PLAYLIST_CARD_ROWS.nameFull];
-
- switch (filter.sortBy) {
- case PlaylistListSort.DURATION:
- rows.push(PLAYLIST_CARD_ROWS.duration);
- break;
- case PlaylistListSort.NAME:
- rows.push(PLAYLIST_CARD_ROWS.songCount);
- break;
- case PlaylistListSort.OWNER:
- rows.push(PLAYLIST_CARD_ROWS.owner);
- break;
- case PlaylistListSort.PUBLIC:
- rows.push(PLAYLIST_CARD_ROWS.public);
- break;
- case PlaylistListSort.SONG_COUNT:
- rows.push(PLAYLIST_CARD_ROWS.songCount);
- break;
- case PlaylistListSort.UPDATED_AT:
- break;
- }
-
- return rows;
- }, [filter.sortBy]);
-
- const handleGridScroll = useCallback(
- (e: ListOnScrollProps) => {
- setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey });
- },
- [pageKey, setGrid],
- );
-
- const fetchInitialData = useCallback(() => {
- const query: Omit = {
- ...filter,
- };
-
- const queriesFromCache: [QueryKey, PlaylistListResponse | undefined][] =
- queryClient.getQueriesData({
- exact: false,
- fetchStatus: 'idle',
- queryKey: queryKeys.playlists.list(server?.id || '', query),
- stale: false,
- });
-
- const itemData: Playlist[] = [];
-
- for (const [, data] of queriesFromCache) {
- const { items, startIndex } = data || {};
-
- if (items && items.length !== 1 && startIndex !== undefined) {
- let itemIndex = 0;
- for (
- let rowIndex = startIndex;
- rowIndex < startIndex + items.length;
- rowIndex += 1
- ) {
- itemData[rowIndex] = items[itemIndex];
- itemIndex += 1;
- }
- }
- }
-
- return itemData;
- }, [filter, queryClient, server?.id]);
-
- const fetch = useCallback(
- async ({ skip, take }: { skip: number; take: number }) => {
- if (!server) {
- return [];
- }
-
- const query: PlaylistListQuery = {
- limit: take,
- ...filter,
- _custom: {},
- startIndex: skip,
- };
-
- const queryKey = queryKeys.playlists.list(server?.id || '', query);
-
- const playlists = await queryClient.fetchQuery({
- queryFn: async ({ signal }) =>
- controller.getPlaylistList({
- apiClientProps: {
- serverId: server?.id || '',
- signal,
- },
- query,
- }),
- queryKey,
- });
-
- return playlists;
- },
- [filter, queryClient, server],
- );
-
- return (
-
-
- {({ height, width }: Size) => (
-
- )}
-
-
- );
-};
diff --git a/src/renderer/features/playlists/components/playlist-list-table-view.tsx b/src/renderer/features/playlists/components/playlist-list-table-view.tsx
deleted file mode 100644
index 82468e49d..000000000
--- a/src/renderer/features/playlists/components/playlist-list-table-view.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
-import { RowDoubleClickedEvent } from '@ag-grid-community/core';
-import { MutableRefObject } from 'react';
-import { generatePath, useNavigate } from 'react-router';
-
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
-import { PLAYLIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { AppRoute } from '/@/renderer/router/routes';
-import { useCurrentServer } from '/@/renderer/store';
-import { LibraryItem } from '/@/shared/types/domain-types';
-
-interface PlaylistListTableViewProps {
- itemCount?: number;
- tableRef: MutableRefObject;
-}
-
-export const PlaylistListTableView = ({ itemCount, tableRef }: PlaylistListTableViewProps) => {
- const navigate = useNavigate();
- const server = useCurrentServer();
- const pageKey = 'playlist';
-
- const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
- if (!e.data) return;
- navigate(generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: e.data.id }));
- };
-
- const tableProps = useVirtualTable({
- contextMenu: PLAYLIST_CONTEXT_MENU_ITEMS,
- itemCount,
- itemType: LibraryItem.PLAYLIST,
- pageKey,
- server,
- tableRef,
- });
-
- return (
-
-
-
- );
-};
diff --git a/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx b/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx
index 625add5d6..b2f3b25f1 100644
--- a/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx
+++ b/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx
@@ -9,7 +9,6 @@ import { generatePath, useNavigate, useParams } from 'react-router';
import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add';
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
-import { PlaylistDetailSongListContent } from '/@/renderer/features/playlists/components/playlist-detail-song-list-content';
import { PlaylistDetailSongListHeader } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header';
import { PlaylistQueryBuilder } from '/@/renderer/features/playlists/components/playlist-query-builder';
import { SaveAsPlaylistForm } from '/@/renderer/features/playlists/components/save-as-playlist-form';
@@ -228,7 +227,7 @@ const PlaylistDetailSongListRoute = () => {
)}
-
+ {/* */}
);
};
diff --git a/src/renderer/features/playlists/routes/playlist-list-route.tsx b/src/renderer/features/playlists/routes/playlist-list-route.tsx
index 312310f5d..7a02b414f 100644
--- a/src/renderer/features/playlists/routes/playlist-list-route.tsx
+++ b/src/renderer/features/playlists/routes/playlist-list-route.tsx
@@ -4,7 +4,6 @@ import { useQuery } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
import { useParams } from 'react-router';
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
import { PlaylistListContent } from '/@/renderer/features/playlists/components/playlist-list-content';
@@ -14,7 +13,7 @@ import { useCurrentServer, useListStoreByKey } from '/@/renderer/store';
import { PlaylistListSort, PlaylistSongListQuery, SortOrder } from '/@/shared/types/domain-types';
const PlaylistListRoute = () => {
- const gridRef = useRef(null);
+ const gridRef = useRef(null);
const tableRef = useRef(null);
const server = useCurrentServer();
const { playlistId } = useParams();
@@ -53,7 +52,7 @@ const PlaylistListRoute = () => {
-
+ {/* */}
);
diff --git a/src/renderer/features/search/components/search-content.tsx b/src/renderer/features/search/components/search-content.tsx
index bcf731280..c26b1cb86 100644
--- a/src/renderer/features/search/components/search-content.tsx
+++ b/src/renderer/features/search/components/search-content.tsx
@@ -5,8 +5,6 @@ import { MutableRefObject } from 'react';
import { generatePath, useNavigate } from 'react-router';
import { useParams, useSearchParams } from 'react-router-dom';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
import {
@@ -91,22 +89,5 @@ export const SearchContent = ({ tableRef }: SearchContentProps) => {
tableRef,
});
- return (
-
- data.data.id}
- infiniteInitialRowCount={25}
- key={`table-${itemType}-${tableProps.rowHeight}-${server?.id}`}
- onRowDoubleClicked={handleRowDoubleClick}
- ref={tableRef}
- rowClassRules={rowClassRules}
- shouldUpdateSong={itemType === LibraryItem.SONG}
- />
-
- );
+ return null;
};
diff --git a/src/renderer/features/similar-songs/components/similar-songs-list.tsx b/src/renderer/features/similar-songs/components/similar-songs-list.tsx
index 596241271..cc49e1476 100644
--- a/src/renderer/features/similar-songs/components/similar-songs-list.tsx
+++ b/src/renderer/features/similar-songs/components/similar-songs-list.tsx
@@ -4,7 +4,6 @@ import { useQuery } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
-import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid/virtual-grid-wrapper';
import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-table';
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
@@ -59,27 +58,25 @@ export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListPr
) : (
-
- data.data.uniqueId}
- onCellContextMenu={onCellContextMenu}
- onCellDoubleClicked={handleRowDoubleClick}
- ref={tableRef}
- rowBuffer={50}
- rowData={songQuery.data ?? []}
- rowHeight={tableConfig.rowHeight || 40}
- shouldUpdateSong
- />
-
+ data.data.uniqueId}
+ onCellContextMenu={onCellContextMenu}
+ onCellDoubleClicked={handleRowDoubleClick}
+ ref={tableRef}
+ rowBuffer={50}
+ rowData={songQuery.data ?? []}
+ rowHeight={tableConfig.rowHeight || 40}
+ shouldUpdateSong
+ />
);
};
diff --git a/src/renderer/store/album-artist.store.ts b/src/renderer/store/album-artist.store.ts
index 6627988ab..5d4dbe64c 100644
--- a/src/renderer/store/album-artist.store.ts
+++ b/src/renderer/store/album-artist.store.ts
@@ -5,7 +5,7 @@ import { createWithEqualityFn } from 'zustand/traditional';
import { DataTableProps } from '/@/renderer/store/settings.store';
import { mergeOverridingColumns } from '/@/renderer/store/utils';
import { AlbumArtistListArgs, AlbumArtistListSort, SortOrder } from '/@/shared/types/domain-types';
-import { ListDisplayType, TableColumn, TablePagination } from '/@/shared/types/types';
+import { ListDisplayType, ListPagination, TableColumn } from '/@/shared/types/types';
export type AlbumArtistListFilter = Omit;
@@ -33,7 +33,7 @@ type ListProps = {
};
type TableProps = DataTableProps & {
- pagination: TablePagination;
+ pagination: ListPagination;
scrollOffset: number;
};
diff --git a/src/renderer/store/list.store.ts b/src/renderer/store/list.store.ts
index a6c75aa9d..298bfecfc 100644
--- a/src/renderer/store/list.store.ts
+++ b/src/renderer/store/list.store.ts
@@ -3,7 +3,9 @@ import { immer } from 'zustand/middleware/immer';
import { shallow } from 'zustand/shallow';
import { createWithEqualityFn } from 'zustand/traditional';
-import { DataTableProps, PersistedTableColumn } from '/@/renderer/store/settings.store';
+import { ItemTableListColumnConfig } from '/@/renderer/components/item-list/types';
+import { ListDeterministicArgs } from '/@/renderer/store';
+import { DataTableProps } from '/@/renderer/store/settings.store';
import { mergeOverridingColumns } from '/@/renderer/store/utils';
import {
AlbumArtistListArgs,
@@ -20,7 +22,7 @@ import {
SongListSort,
SortOrder,
} from '/@/shared/types/domain-types';
-import { ListDisplayType, TableColumn, TablePagination } from '/@/shared/types/types';
+import { ListDisplayType, ListPagination, TableColumn } from '/@/shared/types/types';
export const generatePageKey = (page: string, id?: string) => {
return id ? `${page}_${id}` : page;
@@ -35,13 +37,14 @@ export type ListGridProps = {
itemGap?: number;
itemSize?: number;
itemsPerRow?: number;
- scrollOffset?: number;
};
export type ListItemProps = {
display: ListDisplayType;
filter: TFilter;
- grid?: ListGridProps;
+ grid: ListGridProps;
+ itemsPerPage: number;
+ pagination: ListPagination;
table: ListTableProps;
};
@@ -67,9 +70,11 @@ export interface ListSlice extends ListState {
setGrid: (args: ListDeterministicArgs & { data: Partial }) => void;
setStore: (data: Partial) => void;
setTable: (args: ListDeterministicArgs & { data: Partial }) => void;
- setTableColumns: (args: ListDeterministicArgs & { data: PersistedTableColumn[] }) => void;
+ setTableColumns: (
+ args: ListDeterministicArgs & { data: ItemTableListColumnConfig[] },
+ ) => void;
setTablePagination: (
- args: ListDeterministicArgs & { data: Partial },
+ args: ListDeterministicArgs & { data: Partial },
) => void;
};
}
@@ -90,10 +95,7 @@ export interface ListState {
};
}
-export type ListTableProps = DataTableProps & {
- pagination: TablePagination;
- scrollOffset: number;
-};
+export type ListTableProps = DataTableProps;
export type PlaylistListFilter = Omit;
diff --git a/src/renderer/store/playlist.store.ts b/src/renderer/store/playlist.store.ts
index a5396152f..59001bf1f 100644
--- a/src/renderer/store/playlist.store.ts
+++ b/src/renderer/store/playlist.store.ts
@@ -6,7 +6,7 @@ import { PlaylistListFilter, SongListFilter } from '/@/renderer/store/list.store
import { DataTableProps } from '/@/renderer/store/settings.store';
import { mergeOverridingColumns } from '/@/renderer/store/utils';
import { PlaylistListSort, SortOrder } from '/@/shared/types/domain-types';
-import { ListDisplayType, TableColumn, TablePagination } from '/@/shared/types/types';
+import { ListDisplayType, TableColumn, ListPagination } from '/@/shared/types/types';
export interface PlaylistSlice extends PlaylistState {
actions: {
@@ -17,11 +17,11 @@ export interface PlaylistSlice extends PlaylistState {
setGrid: (args: { data: Partial }) => void;
setStore: (data: Partial) => void;
setTable: (data: Partial) => void;
- setTablePagination: (args: { data: Partial }) => void;
+ setTablePagination: (args: { data: Partial }) => void;
};
}
-type DetailPaginationProps = TablePagination & {
+type DetailPaginationProps = ListPagination & {
scrollOffset: number;
};
@@ -54,7 +54,7 @@ interface PlaylistState {
}
type TableProps = DataTableProps & {
- pagination: TablePagination;
+ pagination: ListPagination;
scrollOffset: number;
};