From 0de8035ca94c8ad294841b9f0f16d5a8b7d03e5e Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 15 Nov 2025 20:07:42 -0800 Subject: [PATCH] remove ag-grid --- package.json | 5 - pnpm-lock.yaml | 53 ------ src/renderer/app.tsx | 6 - .../albums/components/album-detail-header.tsx | 43 +---- .../albums/routes/album-detail-route.tsx | 5 +- .../album-artist-detail-content.tsx | 7 - ...bum-artist-detail-top-songs-list-route.tsx | 5 +- .../components/drawer-play-queue.tsx | 11 +- .../playlist-detail-song-list-header.tsx | 6 +- .../playlist-detail-song-list-route.tsx | 6 +- .../components/similar-songs-list.tsx | 15 +- src/renderer/hooks/use-display-refresh.ts | 74 -------- src/renderer/hooks/use-list-filter-refresh.ts | 177 ------------------ src/renderer/hooks/use-song-change.ts | 73 -------- src/shared/styles/global.css | 94 ---------- 15 files changed, 19 insertions(+), 561 deletions(-) delete mode 100644 src/renderer/hooks/use-display-refresh.ts delete mode 100644 src/renderer/hooks/use-list-filter-refresh.ts delete mode 100644 src/renderer/hooks/use-song-change.ts diff --git a/package.json b/package.json index 04dee183d..afc69c00d 100644 --- a/package.json +++ b/package.json @@ -60,11 +60,6 @@ "postversion": "node ./scripts/update-app-stream.mjs" }, "dependencies": { - "@ag-grid-community/client-side-row-model": "^28.2.1", - "@ag-grid-community/core": "^28.2.1", - "@ag-grid-community/infinite-row-model": "^28.2.1", - "@ag-grid-community/react": "^28.2.1", - "@ag-grid-community/styles": "^28.2.1", "@atlaskit/pragmatic-drag-and-drop": "1.7.7", "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.2", "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca27fbe6d..d12593fa1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,21 +8,6 @@ importers: .: dependencies: - '@ag-grid-community/client-side-row-model': - specifier: ^28.2.1 - version: 28.2.1 - '@ag-grid-community/core': - specifier: ^28.2.1 - version: 28.2.1 - '@ag-grid-community/infinite-row-model': - specifier: ^28.2.1 - version: 28.2.1 - '@ag-grid-community/react': - specifier: ^28.2.1 - version: 28.2.1(@ag-grid-community/core@28.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@ag-grid-community/styles': - specifier: ^28.2.1 - version: 28.2.1 '@atlaskit/pragmatic-drag-and-drop': specifier: 1.7.7 version: 1.7.7 @@ -369,25 +354,6 @@ packages: 7zip-bin@5.2.0: resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} - '@ag-grid-community/client-side-row-model@28.2.1': - resolution: {integrity: sha512-JLLNVNAtSbVjg/h0+JqNxbRGzHR9xl3YHO4kVt8Bu0UO1XQLfGLT8wkzqQTcEOiq0pEfFTee7/BGT3oHOQfUQg==} - - '@ag-grid-community/core@28.2.1': - resolution: {integrity: sha512-qGhqZhY8KbPlr3cJBVkNjGKu+cOyFc8IGvPcvlm0pjNC9cdxO/ct9Sa1Dg+k3ACCEroMEt1apBvnoOgurpvewQ==} - - '@ag-grid-community/infinite-row-model@28.2.1': - resolution: {integrity: sha512-jvEvVNQ/USlQjGW0LbryR4/I1ZSgOBPn4tg45KWm3+R0jmDSfetI20D5t3UaSQHY6ZQMDVYxR3xSkorPFI3Vng==} - - '@ag-grid-community/react@28.2.1': - resolution: {integrity: sha512-VWtiBMhvDKp//lIa2Ovzv+/gcQj6wnZDhngyPW5e97Sl+sIs6/UngHSTbbmhIb+wWUCIKmSRL1+R05PNnKjFTA==} - peerDependencies: - '@ag-grid-community/core': ~28.2.1 - react: ^16.3.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.3.0 || ^17.0.0 || ^18.0.0 - - '@ag-grid-community/styles@28.2.1': - resolution: {integrity: sha512-dy3Z46zTnzrwJOnH+tFvIvY9g/8qIi+b7XmbQlmATBr9zcNMk0wqWH1/9sNHs1fFW6m3Csvu4ctyzdr9mSw1YA==} - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -6088,25 +6054,6 @@ snapshots: 7zip-bin@5.2.0: {} - '@ag-grid-community/client-side-row-model@28.2.1': - dependencies: - '@ag-grid-community/core': 28.2.1 - - '@ag-grid-community/core@28.2.1': {} - - '@ag-grid-community/infinite-row-model@28.2.1': - dependencies: - '@ag-grid-community/core': 28.2.1 - - '@ag-grid-community/react@28.2.1(@ag-grid-community/core@28.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@ag-grid-community/core': 28.2.1 - prop-types: 15.8.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@ag-grid-community/styles@28.2.1': {} - '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.12 diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index 28536a154..02d723ab2 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -1,6 +1,3 @@ -import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model'; -import { ModuleRegistry } from '@ag-grid-community/core'; -import { InfiniteRowModelModule } from '@ag-grid-community/infinite-row-model'; import { MantineProvider } from '@mantine/core'; import '@mantine/core/styles.css'; import '@mantine/dates/styles.css'; @@ -11,7 +8,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import '/@/shared/styles/global.css'; -import '@ag-grid-community/styles/ag-grid.css'; import 'overlayscrollbars/overlayscrollbars.css'; import i18n from '/@/i18n/i18n'; @@ -27,8 +23,6 @@ import { sanitizeCss } from '/@/renderer/utils/sanitize'; import { WebAudio } from '/@/shared/types/types'; import '/styles/overlayscrollbars.css'; -ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]); - const ipc = isElectron() ? window.api.ipc : null; export const App = () => { diff --git a/src/renderer/features/albums/components/album-detail-header.tsx b/src/renderer/features/albums/components/album-detail-header.tsx index 5fd479a3a..7641e8d44 100644 --- a/src/renderer/features/albums/components/album-detail-header.tsx +++ b/src/renderer/features/albums/components/album-detail-header.tsx @@ -1,16 +1,12 @@ import { useQuery } from '@tanstack/react-query'; -import { forwardRef, Ref, useCallback, useMemo } from 'react'; +import { forwardRef, Ref, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { generatePath, useParams } from 'react-router'; -import { Link } from 'react-router'; +import { generatePath, Link, useParams } from 'react-router'; -import { queryKeys } from '/@/renderer/api/query-keys'; import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import { LibraryHeader } from '/@/renderer/features/shared/components/library-header'; import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation'; import { useContainerQuery } from '/@/renderer/hooks'; -import { useSongChange } from '/@/renderer/hooks/use-song-change'; -import { queryClient } from '/@/renderer/lib/react-query'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils'; @@ -20,7 +16,7 @@ import { Pill } from '/@/shared/components/pill/pill'; import { Rating } from '/@/shared/components/rating/rating'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; -import { AlbumDetailResponse, LibraryItem, ServerType } from '/@/shared/types/domain-types'; +import { LibraryItem, ServerType } from '/@/shared/types/domain-types'; interface AlbumDetailHeaderProps { background: { @@ -52,36 +48,6 @@ export const AlbumDetailHeader = forwardRef( ? t('page.albumDetail.released', { postProcess: 'sentenceCase' }) : '♫'; - const songIds = useMemo(() => { - return new Set(detailQuery.data?.songs?.map((song) => song.id)); - }, [detailQuery.data?.songs]); - - const handleSongChange = useCallback( - (id: string) => { - if (songIds.has(id)) { - const queryKey = queryKeys.albums.detail(server?.id, { id: albumId }); - queryClient.setQueryData( - queryKey, - (previous) => { - if (!previous) return undefined; - - return { - ...previous, - playCount: previous.playCount ? previous.playCount + 1 : 1, - }; - }, - ); - } - }, - [albumId, server?.id, songIds], - ); - - useSongChange((ids, event) => { - if (event.event === 'play') { - handleSongChange(ids[0]); - } - }, detailQuery.data !== undefined); - const releaseTypes = useMemo( () => normalizeReleaseTypes(detailQuery.data?.releaseTypes ?? [], t).map((type) => ({ @@ -139,8 +105,9 @@ export const AlbumDetailHeader = forwardRef( updateRatingMutation.mutate({ apiClientProps: { serverId: detailQuery.data._serverId }, query: { - item: [detailQuery.data], + id: [detailQuery.data.id], rating, + type: LibraryItem.ALBUM, }, }); }; diff --git a/src/renderer/features/albums/routes/album-detail-route.tsx b/src/renderer/features/albums/routes/album-detail-route.tsx index 39f0befda..f8a8acd8b 100644 --- a/src/renderer/features/albums/routes/album-detail-route.tsx +++ b/src/renderer/features/albums/routes/album-detail-route.tsx @@ -1,5 +1,3 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - import { useQuery } from '@tanstack/react-query'; import { useRef } from 'react'; import { useParams } from 'react-router'; @@ -17,7 +15,6 @@ import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { LibraryItem } from '/@/shared/types/domain-types'; const AlbumDetailRoute = () => { - const tableRef = useRef(null); const scrollAreaRef = useRef(null); const headerRef = useRef(null); const { albumBackground, albumBackgroundBlur } = useGeneralSettings(); @@ -74,7 +71,7 @@ const AlbumDetailRoute = () => { }} ref={headerRef} /> - + ); diff --git a/src/renderer/features/artists/components/album-artist-detail-content.tsx b/src/renderer/features/artists/components/album-artist-detail-content.tsx index 17a0e3606..9f59b43b8 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -1,4 +1,3 @@ -import { RowDoubleClickedEvent } from '@ag-grid-community/core'; import { useQuery } from '@tanstack/react-query'; import { Suspense, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -32,7 +31,6 @@ import { AlbumArtist, AlbumListSort, LibraryItem, - QueueSong, ServerType, SortOrder, } from '/@/shared/types/domain-types'; @@ -194,10 +192,6 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten }); }; - const handleRowDoubleClick = (e: RowDoubleClickedEvent) => { - if (!e.data || !topSongsQuery?.data) return; - }; - const createFavoriteMutation = useCreateFavorite({}); const deleteFavoriteMutation = useDeleteFavorite({}); @@ -268,7 +262,6 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten icon="ellipsisHorizontal" onClick={(e) => { if (!detailQuery?.data) return; - // handleGeneralContextMenu(e, [detailQuery.data!]); }} size="lg" variant="transparent" 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 7078da72f..20b2d7b2f 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 @@ -1,9 +1,8 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - import { useQuery } from '@tanstack/react-query'; import { useMemo, useRef } from 'react'; import { useParams } from 'react-router'; +import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { ListContext } from '/@/renderer/context/list-context'; import { artistsQueries } from '/@/renderer/features/artists/api/artists-api'; import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header'; @@ -12,7 +11,7 @@ import { useCurrentServer } from '/@/renderer/store/auth.store'; import { LibraryItem } from '/@/shared/types/domain-types'; const AlbumArtistDetailTopSongsListRoute = () => { - const tableRef = useRef(null); + const tableRef = useRef(null); const { albumArtistId, artistId } = useParams() as { albumArtistId?: string; artistId?: string; diff --git a/src/renderer/features/now-playing/components/drawer-play-queue.tsx b/src/renderer/features/now-playing/components/drawer-play-queue.tsx index 84a54f6d3..b2ab37852 100644 --- a/src/renderer/features/now-playing/components/drawer-play-queue.tsx +++ b/src/renderer/features/now-playing/components/drawer-play-queue.tsx @@ -1,14 +1,13 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - import { useRef, useState } from 'react'; +import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue'; import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls'; import { Flex } from '/@/shared/components/flex/flex'; -import { Song } from '/@/shared/types/domain-types'; +import { ItemListKey } from '/@/shared/types/types'; export const DrawerPlayQueue = () => { - const queueRef = useRef }>(null); + const queueRef = useRef(null); const [search, setSearch] = useState(undefined); return ( @@ -23,11 +22,11 @@ export const DrawerPlayQueue = () => { handleSearch={setSearch} searchTerm={search} tableRef={queueRef} - type="sideQueue" + type={ItemListKey.SIDE_QUEUE} /> - + ); diff --git a/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx b/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx index cd3b8ffdd..834b8ddff 100644 --- a/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx +++ b/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx @@ -1,10 +1,9 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - import { useQuery } from '@tanstack/react-query'; import { MutableRefObject } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; +import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { PageHeader } from '/@/renderer/components/page-header/page-header'; import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api'; import { PlaylistDetailSongListHeaderFilters } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header-filters'; @@ -20,10 +19,9 @@ import { Play } from '/@/shared/types/types'; interface PlaylistDetailHeaderProps { handlePlay: (playType: Play) => void; - handleToggleShowQueryBuilder: () => void; itemCount?: number; - tableRef: MutableRefObject; + tableRef: MutableRefObject; } export const PlaylistDetailSongListHeader = ({ 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 b05afa55c..3e7ff990a 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 @@ -1,5 +1,3 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - import { closeAllModals, openModal } from '@mantine/modals'; import { useQuery } from '@tanstack/react-query'; import { motion } from 'motion/react'; @@ -7,6 +5,7 @@ import { useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath, useNavigate, useParams } from 'react-router'; +import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api'; import { PlaylistDetailSongListHeader } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header'; import { PlaylistQueryBuilder } from '/@/renderer/features/playlists/components/playlist-query-builder'; @@ -16,7 +15,6 @@ import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/dele import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store'; -import { searchSongs } from '/@/renderer/utils/search-songs'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Box } from '/@/shared/components/box/box'; import { Group } from '/@/shared/components/group/group'; @@ -28,7 +26,7 @@ import { Play } from '/@/shared/types/types'; const PlaylistDetailSongListRoute = () => { const { t } = useTranslation(); const navigate = useNavigate(); - const tableRef = useRef(null); + const tableRef = useRef(null); const { playlistId } = useParams() as { playlistId: string }; const server = useCurrentServer(); 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 c403d83a2..7039ed45c 100644 --- a/src/renderer/features/similar-songs/components/similar-songs-list.tsx +++ b/src/renderer/features/similar-songs/components/similar-songs-list.tsx @@ -1,9 +1,8 @@ -import { RowDoubleClickedEvent } from '@ag-grid-community/core'; -import { AgGridReact } from '@ag-grid-community/react'; import { useQuery } from '@tanstack/react-query'; import { useRef } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; +import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback'; import { songsQueries } from '/@/renderer/features/songs/api/songs-api'; import { Spinner } from '/@/shared/components/spinner/spinner'; @@ -16,7 +15,7 @@ export type SimilarSongsListProps = { }; export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListProps) => { - const tableRef = useRef | null>(null); + const tableRef = useRef(null); // const tableConfig = useTableSettings(fullScreen ? 'fullScreen' : 'songs'); const songQuery = useQuery( @@ -40,16 +39,6 @@ export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListPr // const onCellContextMenu = useHandleTableContextMenu(LibraryItem.SONG, SONG_CONTEXT_MENU_ITEMS); - const handleRowDoubleClick = (e: RowDoubleClickedEvent) => { - if (!e.data || !songQuery.data) return; - - // handlePlayQueueAdd?.({ - // byData: songQuery.data, - // initialSongId: e.data.id, - // playType: playButtonBehavior, - // }); - }; - return songQuery.isLoading ? ( ) : ( diff --git a/src/renderer/hooks/use-display-refresh.ts b/src/renderer/hooks/use-display-refresh.ts deleted file mode 100644 index 1358b783d..000000000 --- a/src/renderer/hooks/use-display-refresh.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - -import { ChangeEvent, MutableRefObject, useCallback } from 'react'; - -import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid'; -import { useListContext } from '/@/renderer/context/list-context'; -import { - UseHandleListFilterChangeProps, - useListFilterRefresh, -} from '/@/renderer/hooks/use-list-filter-refresh'; -import { useListStoreActions, useListStoreByKey } from '/@/renderer/store'; -import { ListDisplayType } from '/@/shared/types/types'; - -export type UseDisplayRefreshProps = UseHandleListFilterChangeProps & { - gridRef: MutableRefObject; - itemCount?: number; - tableRef: MutableRefObject; -}; - -export const useDisplayRefresh = ({ - gridRef, - isClientSideSort, - itemCount, - itemType, - server, - tableRef, -}: UseDisplayRefreshProps) => { - const { customFilters, handlePlay, pageKey } = useListContext(); - const { display, filter } = useListStoreByKey({ key: pageKey }); - - const { handleRefreshGrid, handleRefreshTable } = useListFilterRefresh({ - isClientSideSort, - itemCount, - itemType, - server, - }); - const { setFilter, setTablePagination } = useListStoreActions(); - - const refresh = useCallback( - (filter: unknown) => { - if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) { - handleRefreshTable(tableRef, filter); - setTablePagination({ data: { currentPage: 0 }, key: pageKey }); - } else { - handleRefreshGrid(gridRef, filter); - } - }, - [ - display, - gridRef, - handleRefreshGrid, - handleRefreshTable, - pageKey, - setTablePagination, - tableRef, - ], - ); - - const search = useCallback( - (e: ChangeEvent) => { - const searchTerm = e.target.value === '' ? undefined : e.target.value; - const updatedFilters = setFilter({ - customFilters, - data: { searchTerm }, - itemType, - key: pageKey, - }); - return updatedFilters; - }, - [customFilters, itemType, pageKey, setFilter], - ); - - return { customFilters, filter, handlePlay, refresh, search }; -}; diff --git a/src/renderer/hooks/use-list-filter-refresh.ts b/src/renderer/hooks/use-list-filter-refresh.ts deleted file mode 100644 index dea20dcb0..000000000 --- a/src/renderer/hooks/use-list-filter-refresh.ts +++ /dev/null @@ -1,177 +0,0 @@ -import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; - -import { IDatasource } from '@ag-grid-community/core'; -import { QueryKey, useQueryClient } from '@tanstack/react-query'; -import orderBy from 'lodash/orderBy'; -import { MutableRefObject, useCallback, useMemo } from 'react'; - -import { api } from '/@/renderer/api'; -import { queryKeys } from '/@/renderer/api/query-keys'; -import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid/virtual-infinite-grid'; -import { BasePaginatedResponse, LibraryItem, ServerListItem } from '/@/shared/types/domain-types'; - -export interface UseHandleListFilterChangeProps { - isClientSideSort?: boolean; - itemCount?: number; - itemType: LibraryItem; - server: null | ServerListItem; -} - -const BLOCK_SIZE = 500; - -export const useListFilterRefresh = ({ - isClientSideSort, - itemCount, - itemType, - server, -}: UseHandleListFilterChangeProps) => { - const queryClient = useQueryClient(); - - const queryKeyFn: ((serverId: string, query: Record) => QueryKey) | null = - useMemo(() => { - switch (itemType) { - case LibraryItem.ALBUM: - return queryKeys.albums.list; - case LibraryItem.ALBUM_ARTIST: - return queryKeys.albumArtists.list; - case LibraryItem.ARTIST: - return queryKeys.artists.list; - case LibraryItem.GENRE: - return queryKeys.genres.list; - case LibraryItem.PLAYLIST: - return queryKeys.playlists.list; - case LibraryItem.SONG: - return queryKeys.songs.list; - default: - return null; - } - }, [itemType]); - - const queryFn: ((args: any) => Promise | null | undefined>) | null = - useMemo(() => { - switch (itemType) { - case LibraryItem.ALBUM: - return api.controller.getAlbumList; - case LibraryItem.ALBUM_ARTIST: - return api.controller.getAlbumArtistList; - case LibraryItem.ARTIST: - return api.controller.getArtistList; - case LibraryItem.GENRE: - return api.controller.getGenreList; - case LibraryItem.PLAYLIST: - return api.controller.getPlaylistList; - case LibraryItem.SONG: - return api.controller.getSongList; - default: - return null; - } - }, [itemType]); - - const handleRefreshTable = useCallback( - async (tableRef: MutableRefObject, filter: any) => { - if (!tableRef || !queryKeyFn || !queryFn) { - return; - } - - const dataSource: IDatasource = { - getRows: async (params) => { - const limit = params.endRow - params.startRow; - const startIndex = params.startRow; - - const query = { ...filter, limit, startIndex }; - - const queryKey = queryKeyFn(server?.id || '', query); - - const results = await queryClient.fetchQuery({ - queryFn: async ({ signal }) => { - return queryFn({ - apiClientProps: { - serverId: server?.id || '', - signal, - }, - query, - }); - }, - queryKey, - }); - - if (isClientSideSort && results?.items) { - const sortedResults = orderBy( - results.items, - [(item) => String(item[filter.sortBy]).toLowerCase()], - filter.sortOrder === 'DESC' ? ['desc'] : ['asc'], - ); - - params.successCallback( - sortedResults || [], - results?.totalRecordCount || itemCount, - ); - return; - } - - if (results?.totalRecordCount === null) { - const hasMoreRows = results?.items?.length === BLOCK_SIZE; - const lastRowIndex = hasMoreRows - ? undefined - : (filter.offset || 0) + results.items.length; - - params.successCallback( - results?.items || [], - hasMoreRows ? undefined : lastRowIndex, - ); - return; - } - - params.successCallback(results?.items || [], results?.totalRecordCount || 0); - }, - - rowCount: undefined, - }; - - tableRef.current?.api.setDatasource(dataSource); - tableRef.current?.api.purgeInfiniteCache(); - tableRef.current?.api.ensureIndexVisible(0, 'top'); - }, - [isClientSideSort, itemCount, queryClient, queryFn, queryKeyFn, server], - ); - - const handleRefreshGrid = useCallback( - async (gridRef: MutableRefObject, filter: any) => { - if (!gridRef || !queryKeyFn || !queryFn) { - return; - } - - gridRef.current?.scrollTo(0); - gridRef.current?.resetLoadMoreItemsCache(); - - const query = { ...filter, limit: 200, startIndex: 0 }; - - const queryKey = queryKeyFn(server?.id || '', query); - - const res = await queryClient.fetchQuery({ - queryFn: async ({ signal }) => { - return queryFn({ - apiClientProps: { - serverId: server?.id || '', - signal, - }, - query, - }); - }, - queryKey, - }); - - if (!res?.items) { - return; - } - - gridRef.current?.setItemData(res.items); - }, - [queryClient, queryFn, queryKeyFn, server], - ); - - return { - handleRefreshGrid, - handleRefreshTable, - }; -}; diff --git a/src/renderer/hooks/use-song-change.ts b/src/renderer/hooks/use-song-change.ts deleted file mode 100644 index 7bf54c887..000000000 --- a/src/renderer/hooks/use-song-change.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { RowNode } from '@ag-grid-community/core'; -import { AgGridReact } from '@ag-grid-community/react'; -import { MutableRefObject, useCallback, useEffect } from 'react'; - -import { useEventStore, UserEvent } from '/@/renderer/store/event.store'; -import { Song } from '/@/shared/types/domain-types'; - -export const useSongChange = ( - handler: (ids: string[], event: UserEvent) => void, - enabled: boolean, -) => { - useEffect(() => { - if (!enabled) return () => {}; - - const unSub = useEventStore.subscribe((state) => { - if (state.event) { - handler(state.ids, state.event); - } - }); - - return () => { - unSub(); - }; - }, [handler, enabled]); -}; - -export const useTableChange = ( - tableRef: MutableRefObject, - enabled: boolean, -) => { - const handler = useCallback( - (ids: string[], event: UserEvent) => { - const api = tableRef.current?.api; - if (!api) return; - - const idSet = new Set(ids); - - api.forEachNode((node: RowNode) => { - if (!node.data || !idSet.has(node.data.id)) return; - - // Make sure to use setData instead of setDataValue. setDataValue - // will error if the column does not exist, whereas setData won't care - switch (event.event) { - case 'favorite': { - if (node.data.userFavorite !== event.favorite) { - node.setData({ ...node.data, userFavorite: event.favorite }); - } - break; - } - case 'play': - if (node.data.lastPlayedAt !== event.timestamp) { - node.setData({ - ...node.data, - lastPlayedAt: event.timestamp, - playCount: node.data.playCount + 1, - }); - } - node.data.lastPlayedAt = event.timestamp; - break; - case 'rating': { - if (node.data.userRating !== event.rating) { - node.setData({ ...node.data, userRating: event.rating }); - } - break; - } - } - }); - }, - [tableRef], - ); - - useSongChange(handler, enabled); -}; diff --git a/src/shared/styles/global.css b/src/shared/styles/global.css index 00e468969..16a1f986d 100644 --- a/src/shared/styles/global.css +++ b/src/shared/styles/global.css @@ -1,5 +1,3 @@ -@import url('./ag-grid.css'); - * { box-sizing: border-box; outline: none; @@ -296,96 +294,4 @@ button { @mixin dark-root { --theme-colors-border: rgb(255 255 255 / 10%); } - - .ag-theme-alpine-dark { - --ag-font-family: var(--theme-content-font-family); - --ag-borders: none; - --ag-border-color: var(--theme-colors-border); - --ag-header-background-color: var(--theme-colors-background); - --ag-header-foreground-color: var(--theme-colors-foreground); - --ag-background-color: var(--theme-colors-background); - --ag-odd-row-background-color: var(--theme-colors-background); - --ag-foreground-color: var(--theme-colors-foreground); - --ag-cell-horizontal-padding: var(--theme-spacing-sm); - --ag-row-hover-color: lighten(var(--theme-colors-background), 5%); - --ag-selected-row-background-color: lighten(var(--theme-colors-background), 10%); - --ag-header-column-resize-handle-width: 0; - } - - .ag-header { - width: auto; - border-bottom: 2px solid var(--theme-colors-border); - } - - .ag-ltr .ag-header-cell-resize { - right: 0; - } - - .ag-header:hover .ag-header-cell-resize { - position: absolute; - top: 25%; - width: 0.2em; - height: 50%; - border: 1px var(--theme-colors-border) solid; - } - - .ag-header-cell-label { - font-family: var(--theme-content-font-family); - font-weight: 500; - text-transform: uppercase; - } - - .ag-cell-rating, - .ag-cell-favorite { - display: none; - } - - .ag-cell-transparent { - opacity: 0; - } - - .ag-cell-rating.visible { - display: block; - } - - .ag-cell-favorite.visible { - display: block; - } - - .ag-row-hover { - .ag-cell-transparent { - opacity: 1; - } - - .ag-cell-rating, - .ag-cell-favorite { - display: block; - } - } - - .ag-cell-focus { - border: 1px var(--theme-colors-border) solid !important; - } - - @mixin dark-root { - .current-song { - .current-song-child { - font-weight: 500; - color: var(--theme-colors-primary-filled); - } - } - } - - @mixin light-root { - .current-song { - .current-song-child { - font-weight: 500; - color: var(--theme-colors-primary-filled); - } - } - } - - .current-song > .row-index.playing .current-song-index { - display: none; - } }