From f12854ef4b22be12290f08124e6e7b7c0340270f Mon Sep 17 00:00:00 2001 From: Mergen <71030751+MergenStudios@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:51:48 +0100 Subject: [PATCH 01/12] Update Setup instructions README.md In the curent README it was not made clear that db_host and db_port have to be added for power tools to work --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 92ceefe..c73171d 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,18 @@ services: - .env ``` -Add the Immich API Key and immich url's to the env file (which you already have for the immich) +Add the Immich API Key and immich url's to the env file (which you already have for the immich). +You also need to add `DB_PORT` (Default 5432) and `DB_HOST`, which has to be set to the name of the immich database +container (Default `immich_postgres`). ```bash IMMICH_API_KEY= # your_immich_api_key IMMICH_URL = "http://local-ip-of-immich:port" # Your immich instace ip address and port EXTERNAL_IMMICH_URL = "https://external-address" # External address of immich +DB_PORT = "5432" +DB_HOST = "immich_postgres" + # Optional GOOGLE_MAPS_API_KEY= # Google Maps API Key GEMINI_API_KEY= # Gemini API Key @@ -149,4 +154,4 @@ Google Gemini 1.5 Flash model is used for parsing your search query in "Find" pa ## Contributing -Feel free to contribute to this project, I'm open to any suggestions and improvements. Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) for more details. \ No newline at end of file +Feel free to contribute to this project, I'm open to any suggestions and improvements. Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) for more details. From cf59b4fa3f35c3dcdddb62f07eb99d5c96471458 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Tue, 29 Jul 2025 10:01:59 +0530 Subject: [PATCH 02/12] feat: album multi select using select Signed-off-by: Varun Raj --- src/components/albums/list/AlbumThumbnail.tsx | 24 +-- src/components/shared/FloatingBar.tsx | 6 +- src/hooks/index.ts | 1 + src/hooks/useAlbumSelection.ts | 68 +++++++++ src/pages/albums/index.tsx | 138 +++++++++++------- 5 files changed, 176 insertions(+), 61 deletions(-) create mode 100644 src/hooks/index.ts create mode 100644 src/hooks/useAlbumSelection.ts diff --git a/src/components/albums/list/AlbumThumbnail.tsx b/src/components/albums/list/AlbumThumbnail.tsx index e8019be..b2973fe 100644 --- a/src/components/albums/list/AlbumThumbnail.tsx +++ b/src/components/albums/list/AlbumThumbnail.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react' +import React, { useMemo } from 'react' import Link from 'next/link'; import { humanizeBytes, humanizeNumber, pluralize } from '@/helpers/string.helper'; @@ -12,16 +12,20 @@ import { Calendar, Camera } from 'lucide-react'; interface IAlbumThumbnailProps { album: IAlbum; - onSelect: (checked: boolean) => void; + onSelect: (albumId: string, isShiftClick?: boolean) => void; selected: boolean; } -export default function AlbumThumbnail({ album, onSelect, selected }: IAlbumThumbnailProps) { - const [isSelected, setIsSelected] = useState(selected); +export default function AlbumThumbnail({ album, onSelect, selected }: IAlbumThumbnailProps) { const numberOfDays = useMemo(() => { return differenceInDays(album.lastPhotoDate, album.firstPhotoDate); }, [album.firstPhotoDate, album.lastPhotoDate]); + const handleCheckboxChange = (event: React.MouseEvent) => { + const isShiftClick = event.shiftKey; + onSelect(album.id, isShiftClick); + }; + return (
@@ -54,15 +58,15 @@ export default function AlbumThumbnail({ album, onSelect, selected }: IAlbumThum {numberOfDays === 0 ? '1 day' : `${numberOfDays.toLocaleString() } days`}

-
+
-

{album.albumName}

+

{album.albumName}

-

{humanizeNumber(album.faceCount)} { +

{humanizeNumber(album.faceCount)} { pluralize(album.faceCount, 'person', 'people') }

-

{humanizeBytes(parseInt(album.size))}

+

{humanizeBytes(parseInt(album.size))}

diff --git a/src/components/shared/FloatingBar.tsx b/src/components/shared/FloatingBar.tsx index 701d509..81aea89 100644 --- a/src/components/shared/FloatingBar.tsx +++ b/src/components/shared/FloatingBar.tsx @@ -1,12 +1,14 @@ +import clsx from 'clsx'; import React from 'react' interface FloatingBarProps { children: React.ReactNode; + className?: string; } -export default function FloatingBar({ children }: FloatingBarProps) { +export default function FloatingBar({ children, className }: FloatingBarProps) { return ( -
+
{children}
) diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..7714555 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1 @@ +export { useAlbumSelection } from './useAlbumSelection' \ No newline at end of file diff --git a/src/hooks/useAlbumSelection.ts b/src/hooks/useAlbumSelection.ts new file mode 100644 index 0000000..3e6189c --- /dev/null +++ b/src/hooks/useAlbumSelection.ts @@ -0,0 +1,68 @@ +import { useState, useCallback } from 'react' +import { IAlbum } from '@/types/album' + +/** + * Custom hook for album selection with shift-click support + * @param albums - Array of albums to manage selection for + * @returns Selection state and methods + */ +export const useAlbumSelection = (albums: IAlbum[]) => { + const [selectedIds, setSelectedIds] = useState>(new Set()) + const [lastSelectedId, setLastSelectedId] = useState(null) + + const selectAlbum = useCallback((albumId: string, isShiftClick: boolean = false) => { + if (isShiftClick && lastSelectedId && lastSelectedId !== albumId) { + // Handle shift-click range selection + const currentIndex = albums.findIndex(album => album.id === albumId) + const lastIndex = albums.findIndex(album => album.id === lastSelectedId) + + if (currentIndex !== -1 && lastIndex !== -1) { + const startIndex = Math.min(currentIndex, lastIndex) + const endIndex = Math.max(currentIndex, lastIndex) + + const newSelectedIds = new Set(selectedIds) + for (let i = startIndex; i <= endIndex; i++) { + newSelectedIds.add(albums[i].id) + } + setSelectedIds(newSelectedIds) + } + } else { + // Toggle single selection + const newSelectedIds = new Set(selectedIds) + if (newSelectedIds.has(albumId)) { + newSelectedIds.delete(albumId) + } else { + newSelectedIds.add(albumId) + } + setSelectedIds(newSelectedIds) + } + + setLastSelectedId(albumId) + }, [albums, selectedIds, lastSelectedId]) + + const selectAll = useCallback(() => { + setSelectedIds(new Set(albums.map(album => album.id))) + }, [albums]) + + const clearSelection = useCallback(() => { + setSelectedIds(new Set()) + setLastSelectedId(null) + }, []) + + const isSelected = useCallback((albumId: string) => selectedIds.has(albumId), [selectedIds]) + + const selectedCount = selectedIds.size + const isAllSelected = albums.length > 0 && selectedCount === albums.length + const isPartiallySelected = selectedCount > 0 && selectedCount < albums.length + + return { + selectedIds: Array.from(selectedIds), + selectedCount, + isSelected, + selectAlbum, + selectAll, + clearSelection, + isAllSelected, + isPartiallySelected + } +} \ No newline at end of file diff --git a/src/pages/albums/index.tsx b/src/pages/albums/index.tsx index 1cc340b..570d6e0 100644 --- a/src/pages/albums/index.tsx +++ b/src/pages/albums/index.tsx @@ -4,7 +4,7 @@ import Loader from '@/components/ui/loader' import { useConfig } from '@/contexts/ConfigContext' import { deleteAlbums, listAlbums } from '@/handlers/api/album.handler' import { IAlbum } from '@/types/album' -import React, { useEffect, useMemo, useRef, useState } from 'react' +import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react' import AlbumThumbnail from '@/components/albums/list/AlbumThumbnail' import { Button } from '@/components/ui/button' import { Select, SelectItem, SelectContent, SelectTrigger, SelectValue } from '@/components/ui/select' @@ -14,6 +14,8 @@ import { Input } from '@/components/ui/input' import AlbumShareDialog, { IAlbumShareDialogRef } from '@/components/albums/share/AlbumShareDialog' import { AlertDialog } from '@/components/ui/alert-dialog' import toast from 'react-hot-toast' +import { useAlbumSelection } from '@/hooks' +import FloatingBar from '@/components/shared/FloatingBar' const SORT_BY_OPTIONS = [ { value: 'lastPhotoDate', label: 'Last Photo Date' }, @@ -25,6 +27,7 @@ const SORT_BY_OPTIONS = [ { value: 'albumSize', label: 'Album Size' }, { value: 'faceCount', label: 'Number of People' }, ] + export default function AlbumListPage() { const router = useRouter() const [search, setSearch] = useState('') @@ -33,7 +36,6 @@ export default function AlbumListPage() { const [albums, setAlbums] = useState([]) const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState('') - const [selectedAlbumsIds, setSelectedAlbumsIds] = useState([]) const albumShareDialogRef = useRef(null); const [deleting, setDeleting] = useState(false) @@ -41,6 +43,19 @@ export default function AlbumListPage() { const searchedAlbums = useMemo(() => albums.filter((album) => album.albumName.toLowerCase().includes(search.toLowerCase())), [albums, search]) + const { + selectedIds, + selectedCount, + isSelected, + selectAlbum, + selectAll, + clearSelection, + isAllSelected, + isPartiallySelected + } = useAlbumSelection(searchedAlbums) + + const selectedAlbums = useMemo(() => albums.filter((album) => selectedIds.includes(album.id)), [albums, selectedIds]) + const fetchAlbums = async () => { setLoading(true) listAlbums({ @@ -56,27 +71,16 @@ export default function AlbumListPage() { }) } - const selectedAlbums = useMemo(() => albums.filter((album) => selectedAlbumsIds.includes(album.id)), [albums, selectedAlbumsIds]) - useEffect(() => { fetchAlbums() }, [sortBy, sortOrder]) - - const handleSelect = (checked: boolean, albumId: string) => { - if (checked) { - setSelectedAlbumsIds([...selectedAlbumsIds, albumId]) - } else { - setSelectedAlbumsIds(selectedAlbumsIds.filter((id) => id !== albumId)) - } - } - const handleDeleteAlbums = async () => { setDeleting(true) - return deleteAlbums(selectedAlbumsIds).then(() => { - setSelectedAlbumsIds([]) - setAlbums(albums.filter((album) => !selectedAlbumsIds.includes(album.id))) - toast.success(`Deleted ${selectedAlbumsIds.length} albums`) + return deleteAlbums(selectedIds).then(() => { + clearSelection() + setAlbums(albums.filter((album) => !selectedIds.includes(album.id))) + toast.success(`Deleted ${selectedCount} albums`) }).catch((error) => { toast.error(error.message) }).finally(() => { @@ -97,48 +101,30 @@ export default function AlbumListPage() { handleSelect(checked, album.id)} + selected={isSelected(album.id)} + onSelect={selectAlbum} /> ))}
) } return ( - +
+ Manage Albums + {selectedCount > 0 && ( + + ({selectedCount} selected) + + )} + + } rightComponent={
- {!!selectedAlbumsIds.length && ( - <> - - - - - - - )} setSearch(e.target.value)} /> + setSearch(e.target.value)} /> +
+ + +
+ handleMaxDurationChange(e.target.value)} + onBlur={handleMaxDurationBlur} + className="w-20 h-8" + /> + s +
+ + + + {/* Asset Count */} +
+ {humanizeNumber(assets.length)} + {' '} + +
+ + ) + } + /> + + {renderContent()} + {selectedAssets.length > 0 && + +
+

+ {contextState.selectedIds.length} Selected +

+
+ {contextState.selectedIds.length === contextState.assets.length ? ( + + ) : ( + + )} +
+ + + +
+
+
+ } +
+ + ) +} From d443da7df2061b60d65f540b38c4e3c26ab35ee0 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 16:34:44 +0530 Subject: [PATCH 06/12] feat: manage duplicates in bulk Signed-off-by: Varun Raj --- bun.lockb | Bin 474514 -> 475839 bytes package.json | 2 + .../assets/duplicate-assets/BulkActionBar.tsx | 81 +++++ .../duplicate-assets/DuplicateAssetRecord.tsx | 265 ++++++++++++++ .../VirtualizedDuplicateList.tsx | 115 ++++++ src/config/constants/sidebarNavs.tsx | 10 +- src/config/routes.ts | 4 +- src/handlers/api/asset.handler.ts | 8 +- src/pages/api/immich-proxy/[...path].ts | 43 ++- src/pages/assets/bulk-duplicate-finder.tsx | 328 ++++++++++++++++++ src/types/asset.d.ts | 61 ++++ 11 files changed, 904 insertions(+), 13 deletions(-) create mode 100644 src/components/assets/duplicate-assets/BulkActionBar.tsx create mode 100644 src/components/assets/duplicate-assets/DuplicateAssetRecord.tsx create mode 100644 src/components/assets/duplicate-assets/VirtualizedDuplicateList.tsx create mode 100644 src/pages/assets/bulk-duplicate-finder.tsx diff --git a/bun.lockb b/bun.lockb index c4de24ec5e672a50d43255c5d0e8ce8603ac6c06..158441fff8252401976b5ece1738e3eb6ae64b11 100755 GIT binary patch delta 94622 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 delta 93745 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 diff --git a/package.json b/package.json index 4aacb22..cc00a8b 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@types/qs": "^6.9.15", "@types/react-autosuggest": "^10.1.11", "@types/react-calendar-heatmap": "^1.6.7", + "@types/react-window": "^1.8.8", "@vis.gl/react-google-maps": "^1.4.2", "axios": "^1.7.4", "chrono-node": "^1.4.9", @@ -66,6 +67,7 @@ "react-hot-toast": "^2.5.1", "react-leaflet": "^4.2.1", "react-mentions": "^4.4.10", + "react-window": "^1.8.11", "recharts": "^2.12.7", "remotion": "4.0.232", "sass": "^1.77.8", diff --git a/src/components/assets/duplicate-assets/BulkActionBar.tsx b/src/components/assets/duplicate-assets/BulkActionBar.tsx new file mode 100644 index 0000000..4b51463 --- /dev/null +++ b/src/components/assets/duplicate-assets/BulkActionBar.tsx @@ -0,0 +1,81 @@ +import React from 'react' +import { Button } from '@/components/ui/button' +import { Trash2, Check, X, RotateCcw } from 'lucide-react' +import { humanizeNumber } from '@/helpers/string.helper' + +interface BulkActionBarProps { + selectedCount: number + totalAssets: number + onDeleteSelected: () => void + onSelectAll: () => void + onDeselectAll: () => void + onInvertSelection: () => void + isVisible: boolean +} + +export default function BulkActionBar({ + selectedCount, + totalAssets, + onDeleteSelected, + onSelectAll, + onDeselectAll, + onInvertSelection, + isVisible +}: BulkActionBarProps) { + if (!isVisible) return null + + return ( +
+
+
+ {humanizeNumber(selectedCount)} of {humanizeNumber(totalAssets)} selected +
+ +
+ + + + + + +
+ + +
+
+
+ ) +} diff --git a/src/components/assets/duplicate-assets/DuplicateAssetRecord.tsx b/src/components/assets/duplicate-assets/DuplicateAssetRecord.tsx new file mode 100644 index 0000000..1248450 --- /dev/null +++ b/src/components/assets/duplicate-assets/DuplicateAssetRecord.tsx @@ -0,0 +1,265 @@ +import React, { useMemo } from 'react' +import { IDuplicateAssetRecord, IDuplicateAsset } from '@/types/asset' +import { ASSET_THUMBNAIL_PATH } from '@/config/routes' +import LazyImage from '@/components/ui/lazy-image' +import { Checkbox } from '@/components/ui/checkbox' +import { Button } from '@/components/ui/button' +import { AlertDialog } from '@/components/ui/alert-dialog' +import { humanizeBytes, humanizeNumber } from '@/helpers/string.helper' +import { formatDate } from '@/helpers/date.helper' +import { Camera, Calendar, HardDrive, MapPin, Trash2, Check, X, Shield } from 'lucide-react' + +interface DuplicateAssetRecordProps { + record: IDuplicateAssetRecord + selectedAssets: Set + onAssetSelect: (assetId: string, isShiftClick?: boolean) => void + onDeleteRecord: (record: IDuplicateAssetRecord) => void + onKeepSelected: (record: IDuplicateAssetRecord, selectedIds: string[], unselectedIds: string[]) => void + onKeepAllInRecord: (record: IDuplicateAssetRecord) => void +} + +interface DuplicateAssetItemProps { + asset: IDuplicateAsset + isSelected: boolean + onSelect: (assetId: string, isShiftClick?: boolean) => void +} + +function DuplicateAssetItem({ asset, isSelected, onSelect }: DuplicateAssetItemProps) { + const handleCheckboxChange = (event: React.MouseEvent) => { + const isShiftClick = event.shiftKey + onSelect(asset.id, isShiftClick) + } + + return ( +
+ + + {/* Asset details */} +
+

+ {asset.originalFileName} +

+ +
+
+ + {humanizeBytes(asset.exifInfo.fileSizeInByte)} +
+ +
+ + {asset.exifInfo.exifImageWidth} × {asset.exifInfo.exifImageHeight} +
+ + {asset.exifInfo.city && ( +
+ + {asset.exifInfo.city}, {asset.exifInfo.country} +
+ )} + + {asset.exifInfo.make && asset.exifInfo.model && ( +
+ {asset.exifInfo.make} {asset.exifInfo.model} +
+ )} +
+
+
+ ) +} + +export default function DuplicateAssetRecord({ + record, + selectedAssets, + onAssetSelect, + onDeleteRecord, + onKeepSelected, + onKeepAllInRecord +}: DuplicateAssetRecordProps) { + const recordAssetIds = record.assets.map(asset => asset.id) + const selectedInRecord = recordAssetIds.filter(id => selectedAssets.has(id)).length + const unselectedInRecord = record.assets.length - selectedInRecord + + // Calculate total size and selected/unselected sizes + const totalSize = useMemo(() => { + return record.assets.reduce((sum, asset) => sum + asset.exifInfo.fileSizeInByte, 0) + }, [record.assets]) + + const selectedSize = useMemo(() => { + return record.assets + .filter(asset => selectedAssets.has(asset.id)) + .reduce((sum, asset) => sum + asset.exifInfo.fileSizeInByte, 0) + }, [record.assets, selectedAssets]) + + const unselectedSize = useMemo(() => { + return record.assets + .filter(asset => !selectedAssets.has(asset.id)) + .reduce((sum, asset) => sum + asset.exifInfo.fileSizeInByte, 0) + }, [record.assets, selectedAssets]) + + const handleKeepAll = () => { + onKeepAllInRecord(record) + } + + const handleDeleteRecord = () => { + onDeleteRecord(record) + } + + const handleKeepSelected = () => { + const selectedAssetIds = record.assets + .filter(asset => selectedAssets.has(asset.id)) + .map(asset => asset.id) + + const unselectedAssetIds = record.assets + .filter(asset => !selectedAssets.has(asset.id)) + .map(asset => asset.id) + + if (selectedAssetIds.length === 0) return + + onKeepSelected(record, selectedAssetIds, unselectedAssetIds) + } + + return ( +
+
+
+
+
+ + {humanizeNumber(record.assets.length)} duplicate{record.assets.length !== 1 ? 's' : ''} +
+
+ + {humanizeBytes(totalSize)} total +
+ {selectedInRecord > 0 && ( +
+
+ + {selectedInRecord} to keep ({humanizeBytes(selectedSize)}) +
+
+ + {unselectedInRecord} to delete ({humanizeBytes(unselectedSize)} savings) +
+
+ )} +
+
+ + + + + {selectedInRecord > 0 && ( + + + + )} + + + + +
+
+
+ +
+ {record.assets.map((asset) => ( + + ))} +
+
+ ) +} diff --git a/src/components/assets/duplicate-assets/VirtualizedDuplicateList.tsx b/src/components/assets/duplicate-assets/VirtualizedDuplicateList.tsx new file mode 100644 index 0000000..8e580c3 --- /dev/null +++ b/src/components/assets/duplicate-assets/VirtualizedDuplicateList.tsx @@ -0,0 +1,115 @@ +import React, { useMemo } from 'react' +import { VariableSizeList as List } from 'react-window' +import { IDuplicateAssetRecord } from '@/types/asset' +import DuplicateAssetRecord from './DuplicateAssetRecord' + +interface VirtualizedDuplicateListProps { + duplicates: IDuplicateAssetRecord[] + selectedAssets: Set + onAssetSelect: (assetId: string, isShiftClick?: boolean) => void + onDeleteRecord: (record: IDuplicateAssetRecord) => void + onKeepSelected: (record: IDuplicateAssetRecord, selectedIds: string[], unselectedIds: string[]) => void + onKeepAllInRecord: (record: IDuplicateAssetRecord) => void + height: number +} + +interface ListItemProps { + index: number + style: React.CSSProperties + data: { + duplicates: IDuplicateAssetRecord[] + selectedAssets: Set + onAssetSelect: (assetId: string, isShiftClick?: boolean) => void + onDeleteRecord: (record: IDuplicateAssetRecord) => void + onKeepSelected: (record: IDuplicateAssetRecord, selectedIds: string[], unselectedIds: string[]) => void + onKeepAllInRecord: (record: IDuplicateAssetRecord) => void + } +} + +const ListItem: React.FC = ({ index, style, data }) => { + const { duplicates, selectedAssets, onAssetSelect, onDeleteRecord, onKeepSelected, onKeepAllInRecord } = data + const record = duplicates[index] + + return ( +
+
+ +
+
+ ) +} + +// Calculate dynamic height for each duplicate record +const getItemSize = (record: IDuplicateAssetRecord): number => { + // Base height for the header section + let height = 120 // Header + margin + + // Calculate grid rows needed + const assetsPerRow = 5 // xl:grid-cols-5 is the max + const rows = Math.ceil(record.assets.length / assetsPerRow) + + // Each asset item is approximately 320px tall (200px image + 120px details) + const assetRowHeight = 320 + + return height + (rows * assetRowHeight) + 32 // Add some margin +} + +export default function VirtualizedDuplicateList({ + duplicates, + selectedAssets, + onAssetSelect, + onDeleteRecord, + onKeepSelected, + onKeepAllInRecord, + height +}: VirtualizedDuplicateListProps) { + // Custom item size getter for VariableSizeList + const getItemHeight = (index: number) => { + if (index >= duplicates.length) return 0 + return getItemSize(duplicates[index]) + } + + // Data to pass to each list item + const itemData = { + duplicates, + selectedAssets, + onAssetSelect, + onDeleteRecord, + onKeepSelected, + onKeepAllInRecord + } + + // For better performance with many items, we'll use a custom implementation + // that handles variable heights properly + return ( +
+ {duplicates.length === 0 ? ( +
+

No duplicate records to display

+
+ ) : ( + + {ListItem} + + )} +
+ ) +} diff --git a/src/config/constants/sidebarNavs.tsx b/src/config/constants/sidebarNavs.tsx index b4de6fc..6b95734 100644 --- a/src/config/constants/sidebarNavs.tsx +++ b/src/config/constants/sidebarNavs.tsx @@ -1,4 +1,4 @@ -import { GalleryHorizontal, GalleryVerticalEnd, Image as ImageIcon, MapPin, MapPinX, Rewind, Search, User, Video } from "lucide-react"; +import { Copy, GalleryHorizontal, GalleryVerticalEnd, Image as ImageIcon, MapPin, MapPinX, Rewind, Search, User, Video } from "lucide-react"; export const sidebarNavs = [ // { @@ -47,6 +47,12 @@ export const sidebarNavs = [ title: "Empty Videos", link: "/assets/empty-videos", icon:
); + return ( - <> - = 0} - index={index} - close={() => setIndex(-1)} +
+ -
- -
- +
); } diff --git a/src/components/assets/missing-location/MissingLocationAssets.tsx b/src/components/assets/missing-location/MissingLocationAssets.tsx index e122784..a60b2b4 100644 --- a/src/components/assets/missing-location/MissingLocationAssets.tsx +++ b/src/components/assets/missing-location/MissingLocationAssets.tsx @@ -1,9 +1,5 @@ -import "yet-another-react-lightbox/styles.css"; import { IAsset } from "@/types/asset"; -import React, { useEffect, useMemo, useState, MouseEvent } from "react"; -import { Gallery } from "react-grid-gallery"; -import Lightbox from "yet-another-react-lightbox"; -import Captions from "yet-another-react-lightbox/plugins/captions"; +import React, { useEffect, useMemo, useState } from "react"; import { CalendarArrowUp, Hourglass, @@ -11,7 +7,7 @@ import { import { usePhotoSelectionContext } from "@/contexts/PhotoSelectionContext"; import { listMissingLocationAssets } from "@/handlers/api/asset.handler"; import { useConfig } from "@/contexts/ConfigContext"; -import LazyGridImage from "@/components/ui/lazy-grid-image"; +import AssetGrid from "@/components/shared/AssetGrid"; interface IProps { groupBy: "date" | "album"; @@ -30,9 +26,6 @@ export default function MissingLocationAssets({ groupBy }: IProps) { const [loading, setLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(null); - const [index, setIndex] = useState(-1); - const [lastSelectedIndex, setLastSelectedIndex] = useState(-1); - const fetchAssets = async () => { if (!startDate && !albumId) return; setLoading(true); @@ -46,7 +39,7 @@ export default function MissingLocationAssets({ groupBy }: IProps) { .finally(() => setLoading(false)); }; - const images = useMemo(() => { + const processedAssets = useMemo(() => { let sortedAssets: IAsset[]; try { if (sortOrder === "desc") @@ -58,76 +51,23 @@ export default function MissingLocationAssets({ groupBy }: IProps) { sortedAssets = [...assets]; } - return sortedAssets. - map((p) => ({ - ...p, - src: p.url as string, - original: p.previewUrl as string, - width: p.exifImageWidth as number, - height: p.exifImageHeight as number, - isSelected: selectedIds.includes(p.id), - orientation: 1, - tags: [ - { - title: "Immich Link", - value: ( - - Open in Immich - - ), - }, - ], - })); - }, [assets, selectedIds, sortOrder, exImmichUrl]); + return sortedAssets.map((asset) => ({ + ...asset, + tags: [ + { + title: "Immich Link", + value: ( + + Open in Immich + + ), + }, + ], + })); + }, [assets, sortOrder, exImmichUrl]); - const slides = useMemo( - () => - images.map(({ original, width, height }) => ({ - src: original, - width, - height, - })), - [images] - ); - - const handleClick = (idx: number, asset: IAsset, event: MouseEvent) => { - if (selectedIds.length > 0) { - handleSelect(idx, asset, event); - } - else - { - setIndex(idx); - } - }; - - const handleSelect = (_idx: number, asset: IAsset, event: MouseEvent) => { - event.stopPropagation(); - const isPresent = selectedIds.includes(asset.id); - if (isPresent) { - updateContext({ - selectedIds: selectedIds.filter((id) => id !== asset.id), - }); - } else { - const clickedIndex = images.findIndex((image) => { - return image.id === asset.id; - }); - if (event.shiftKey && lastSelectedIndex !== -1) { - const startIndex = Math.min(clickedIndex, lastSelectedIndex); - const endIndex = Math.max(clickedIndex, lastSelectedIndex); - if (startIndex >= 0 && endIndex < images.length) { - const newSelectedIds = images.slice(startIndex, endIndex + 1).map((image) => image.id); - const allSelectedIds = [...selectedIds, ...newSelectedIds]; - const uniqueSelectedIds = [...new Set(allSelectedIds)]; - updateContext({ selectedIds: uniqueSelectedIds }); - } else { - console.warn("Shift-select index out of bounds"); - updateContext({ selectedIds: [...selectedIds, asset.id] }); - } - } else { - updateContext({ selectedIds: [...selectedIds, asset.id] }); - } - setLastSelectedIndex(clickedIndex); - } + const handleSelectionChange = (ids: string[]) => { + updateContext({ selectedIds: ids }); }; useEffect(() => { @@ -155,30 +95,13 @@ export default function MissingLocationAssets({ groupBy }: IProps) { ); return ( - <> - = 0} - index={index} - close={() => setIndex(-1)} +
+ -
- -
- +
); } From dcac170d7bd74bf522ac810f46850a2d488737b5 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 16:57:06 +0530 Subject: [PATCH 08/12] fix: share link to show assets which are not in any of the album Signed-off-by: Varun Raj --- src/pages/api/share-link/[token]/assets.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/api/share-link/[token]/assets.ts b/src/pages/api/share-link/[token]/assets.ts index dee5525..eed067c 100644 --- a/src/pages/api/share-link/[token]/assets.ts +++ b/src/pages/api/share-link/[token]/assets.ts @@ -1,7 +1,7 @@ import { db } from "@/config/db"; import { ENV } from "@/config/environment"; -import { desc, gte, lte } from "drizzle-orm"; -import { eq, inArray } from "drizzle-orm"; +import { desc, gte, lte, sql } from "drizzle-orm"; +import { eq, inArray, or, isNull, count } from "drizzle-orm"; import { assetFaces, assets, exif } from "@/schema"; import { and } from "drizzle-orm"; import { JsonWebTokenError, sign, verify } from "jsonwebtoken"; @@ -76,8 +76,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) orientation: exif.orientation, }).from(assets) .innerJoin(assetFaces, eq(assets.id, assetFaces.assetId)) - .innerJoin(albumsAssetsAssets, eq(assets.id, albumsAssetsAssets.assetsId)) - .innerJoin(albums, eq(albumsAssetsAssets.albumsId, albums.id)) + .leftJoin(albumsAssetsAssets, eq(assets.id, albumsAssetsAssets.assetsId)) + .leftJoin(albums, eq(albumsAssetsAssets.albumsId, albums.id)) .innerJoin(exif, eq(exif.assetId, assets.id)) .where(and( filteredPersonIds?.length > 0 ? inArray(assetFaces.personId, filteredPersonIds) : undefined, From 0ea429578ec78c1d75054418225c5327b17a6c18 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 16:57:48 +0530 Subject: [PATCH 09/12] fix: share link album sort fix Signed-off-by: Varun Raj --- src/pages/api/share-link/[token]/assets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/api/share-link/[token]/assets.ts b/src/pages/api/share-link/[token]/assets.ts index eed067c..635a8fb 100644 --- a/src/pages/api/share-link/[token]/assets.ts +++ b/src/pages/api/share-link/[token]/assets.ts @@ -88,7 +88,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) eq(assets.visibility, "timeline"), eq(assets.isOffline, false), )) - .orderBy(desc(assets.createdAt)); + .orderBy(desc(assets.localDateTime)); const cleanedAssets = dbAssets.map((asset) => { return { From 53fa52cfd78efb0eadc71740b529c3a4d00be84c Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 17:24:00 +0530 Subject: [PATCH 10/12] fix: selection is unified across the tool Signed-off-by: Varun Raj --- src/components/shared/AssetGrid.tsx | 50 ++++++++++++++++++++------- src/handlers/api/asset.handler.ts | 2 +- src/pages/albums/potential-albums.tsx | 7 ++-- src/pages/assets/empty-videos.tsx | 1 + 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/components/shared/AssetGrid.tsx b/src/components/shared/AssetGrid.tsx index 065cf07..fbcd366 100644 --- a/src/components/shared/AssetGrid.tsx +++ b/src/components/shared/AssetGrid.tsx @@ -1,12 +1,13 @@ import "yet-another-react-lightbox/styles.css"; import { IAsset } from '@/types/asset'; -import React, { useEffect, useMemo, useState } from 'react' +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react' import Lightbox from 'yet-another-react-lightbox'; import { Gallery } from "react-grid-gallery"; import LazyGridImage from "../ui/lazy-grid-image"; import Download from "yet-another-react-lightbox/plugins/download"; import Video from "yet-another-react-lightbox/plugins/video"; +import { usePhotoSelectionContext } from '@/contexts/PhotoSelectionContext'; interface AssetGridProps { @@ -16,10 +17,31 @@ interface AssetGridProps { onSelectionChange?: (ids: string[]) => void; } -export default function AssetGrid({ assets, isInternal = true, selectable = false, onSelectionChange }: AssetGridProps) { +interface AssetGridRef { + getSelectedIds: () => string[]; + selectAll: () => void; + unselectAll: () => void; +} + +const AssetGrid = forwardRef(({ assets, isInternal = true, selectable = false, onSelectionChange }, ref) => { const [index, setIndex] = useState(-1); - const [selectedIds, setSelectedIds] = useState([]); const [lastSelectedIndex, setLastSelectedIndex] = useState(-1); + + // Use context for selection state + const { selectedIds, updateContext } = usePhotoSelectionContext(); + + useImperativeHandle(ref, () => ({ + getSelectedIds: () => selectedIds, + selectAll: () => { + const allIds = assets.map((asset) => asset.id); + updateContext({ selectedIds: allIds }); + onSelectionChange?.(allIds); + }, + unselectAll: () => { + updateContext({ selectedIds: [] }); + onSelectionChange?.([]); + }, + }), [assets, selectedIds, updateContext]); const handleClick = (index: number, asset: IAsset, event: React.MouseEvent) => { @@ -35,8 +57,9 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals event.stopPropagation(); const isPresent = selectedIds.includes(asset.id); if (isPresent) { - setSelectedIds(selectedIds.filter((id) => id !== asset.id)); - onSelectionChange?.(selectedIds.filter((id) => id !== asset.id)); + const newSelectedIds = selectedIds.filter((id) => id !== asset.id); + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); } else { const clickedIndex = images.findIndex((image) => { return image.id === asset.id; @@ -44,14 +67,15 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals if (event.shiftKey) { const startIndex = Math.min(clickedIndex, lastSelectedIndex); const endIndex = Math.max(clickedIndex, lastSelectedIndex); - const newSelectedIds = images.slice(startIndex, endIndex + 1).map((image) => image.id); - const allSelectedIds = [...selectedIds, ...newSelectedIds]; + const rangeSelectedIds = images.slice(startIndex, endIndex + 1).map((image) => image.id); + const allSelectedIds = [...selectedIds, ...rangeSelectedIds]; const uniqueSelectedIds = [...new Set(allSelectedIds)]; - setSelectedIds(uniqueSelectedIds); + updateContext({ selectedIds: uniqueSelectedIds }); onSelectionChange?.(uniqueSelectedIds); } else { - setSelectedIds([...selectedIds, asset.id]); - onSelectionChange?.([...selectedIds, asset.id]); + const newSelectedIds = [...selectedIds, asset.id]; + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); } setLastSelectedIndex(clickedIndex); } @@ -93,7 +117,7 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals const handleEsc = (event: KeyboardEvent) => { if (event.key === "Escape") { - setSelectedIds([]); + updateContext({ selectedIds: [] }); onSelectionChange?.([]); } }; @@ -122,4 +146,6 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals /> ); -} +}) +AssetGrid.displayName = "AssetGrid"; +export default AssetGrid; diff --git a/src/handlers/api/asset.handler.ts b/src/handlers/api/asset.handler.ts index 7b86638..85667a5 100644 --- a/src/handlers/api/asset.handler.ts +++ b/src/handlers/api/asset.handler.ts @@ -73,7 +73,7 @@ export const getAssetGeoHeatmap = async (filters: IHeatMapParams) => { } export const deleteAssets = async (ids: string[]) => { - return API.delete(UPDATE_ASSETS_PATH, { ids }); + return API.delete(UPDATE_ASSETS_PATH, { ids, force: true }); } export interface IEmptyVideosParams { diff --git a/src/pages/albums/potential-albums.tsx b/src/pages/albums/potential-albums.tsx index 322559a..98fe253 100644 --- a/src/pages/albums/potential-albums.tsx +++ b/src/pages/albums/potential-albums.tsx @@ -150,6 +150,7 @@ export default function PotentialAlbums() { {contextState.selectedIds.length} Selected

+ {contextState.selectedIds.length === contextState.assets.length ? ( - - + )}
diff --git a/src/pages/assets/empty-videos.tsx b/src/pages/assets/empty-videos.tsx index 5daae3b..e0b1e6b 100644 --- a/src/pages/assets/empty-videos.tsx +++ b/src/pages/assets/empty-videos.tsx @@ -22,6 +22,7 @@ export default function EmptyVideosPage() { const [assets, setAssets] = useState([]) const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState('') + // Initialize filters from URL params or defaults const getInitialFilters = () => { From c64959f6d6b6f6de339fe30cde3e77231b3f6e49 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 17:41:45 +0530 Subject: [PATCH 11/12] fix: design and performance fixes in album list Signed-off-by: Varun Raj --- bun.lockb | Bin 475839 -> 475839 bytes docs/VIRTUALIZED_ASSET_GRID.md | 155 +++++++++++ package.json | 2 +- src/components/shared/AssetGridExample.tsx | 87 ++++++ src/components/shared/FloatingBar.tsx | 2 +- .../shared/ResponsiveVirtualizedAssetGrid.tsx | 254 ++++++++++++++++++ .../shared/VirtualizedAssetGrid.tsx | 205 ++++++++++++++ src/components/ui/data-table.tsx | 20 +- src/hooks/index.ts | 3 +- src/hooks/useGridDimensions.ts | 82 ++++++ src/pages/albums/[albumId].tsx | 2 +- src/pages/albums/index.tsx | 4 +- src/pages/albums/potential-albums.tsx | 2 +- src/pages/assets/empty-videos.tsx | 2 +- src/pages/assets/missing-locations.tsx | 2 +- src/pages/find/index.tsx | 2 +- 16 files changed, 795 insertions(+), 29 deletions(-) create mode 100644 docs/VIRTUALIZED_ASSET_GRID.md create mode 100644 src/components/shared/AssetGridExample.tsx create mode 100644 src/components/shared/ResponsiveVirtualizedAssetGrid.tsx create mode 100644 src/components/shared/VirtualizedAssetGrid.tsx create mode 100644 src/hooks/useGridDimensions.ts diff --git a/bun.lockb b/bun.lockb index 158441fff8252401976b5ece1738e3eb6ae64b11..7310b1b28ea4f4484bf9a9178bf065f5c78bbe4d 100755 GIT binary patch delta 282 zcmV+#0p{{{$1b!##F%k5%l&xMXqjGq50cWH*~HT+7^47Ao(Bu})T& z0Tq*BP%D!VNeGkJmJ9(ElVMORgAkXu5SIZ>hCt?XOidvZKa8Xq=q6T3V{tDnOtrdJ zUK+*m20-2K(>F(9vba(DDtz#va#ZUlfha4~GM=C=_JtquQ6{dId0UsA9Re6YmDX1h z6M=8SEbkKR(^t{mfgId15sN--idg)%aikTTt+!U268V1`6($Hx4=}cjJvO%{P6uqM zk(7C^`T(D{hxHu-hxHu;xAh$a^{WFhE;G07$poY~1Tii%0GAOI1sR8~0R^|N0R~1n g12HZ$m-jjbSeF4g1|*lyItC7hfjb7bfjb922kQ271^@s6 delta 282 zcmV+#0p{Fwiwu>G=4bh?CQ251iZX1hO!qpTFLbYabHu})T& z0Th#APAiiTNeGkJmJ9(DlVMIPgAkXu5SIZ>hCn=$zSFv!dUy_P?q%)IFA3XTeR;fd zBzTKX{AtCj9k*uilCac7yJDG+wOf4vwG|LSKpw{(R*{i~7$TAZOl_B)9Re6YoH3e$_?!X<&^#vbB-%sQEas z_6f^1q>g4zhxHu-hxHu;xAh$a^{WFgE-|<5$poY~1TZc!0GAOI1sR8~0R^|N0R~1n g128Tzm-jjbSeJ1=1|yfwItCAifjb7bfjb922b8vZ^Z)<= diff --git a/docs/VIRTUALIZED_ASSET_GRID.md b/docs/VIRTUALIZED_ASSET_GRID.md new file mode 100644 index 0000000..2235259 --- /dev/null +++ b/docs/VIRTUALIZED_ASSET_GRID.md @@ -0,0 +1,155 @@ +# Virtualized Asset Grid Components + +This document explains how to use the new React Window-based virtualized asset grid components for better performance with large datasets. + +## Overview + +The virtualized asset grid components provide significant performance improvements when displaying large numbers of assets by only rendering the items that are currently visible in the viewport. This is especially useful for photo galleries with thousands of images. + +## Components + +### 1. VirtualizedAssetGrid + +A basic virtualized grid with fixed dimensions. + +```tsx +import VirtualizedAssetGrid from '@/components/shared/VirtualizedAssetGrid'; + + +``` + +**Props:** +- `assets`: Array of IAsset objects +- `selectable`: Whether assets can be selected (default: false) +- `onSelectionChange`: Callback when selection changes +- `columnCount`: Number of columns (default: 5) +- `itemSize`: Size of each item in pixels (default: 200) +- `height`: Height of the grid container (default: 600) + +### 2. ResponsiveVirtualizedAssetGrid + +A responsive virtualized grid that automatically adjusts to container size. + +```tsx +import ResponsiveVirtualizedAssetGrid from '@/components/shared/ResponsiveVirtualizedAssetGrid'; + + +``` + +**Props:** +- `assets`: Array of IAsset objects +- `selectable`: Whether assets can be selected (default: false) +- `onSelectionChange`: Callback when selection changes +- `targetItemSize`: Target size for each item (default: 200) +- `gap`: Gap between items in pixels (default: 8) +- `minColumns`: Minimum number of columns (default: 2) +- `maxColumns`: Maximum number of columns (default: 8) +- `className`: Additional CSS classes + +## Features + +### Selection +Both components support asset selection with the following features: +- Click to select/deselect individual assets +- Shift+click for range selection +- ESC key to clear all selections +- Visual indicators for selected items + +### Lightbox Integration +Both components integrate with the existing lightbox for full-screen viewing: +- Click on an asset to open in lightbox +- Video support with duration display +- Download functionality + +### Performance Optimizations +- Only renders visible items +- Lazy loading of images +- Efficient memory usage +- Smooth scrolling performance + +## Migration from AssetGrid + +To migrate from the existing `AssetGrid` component: + +### Before: +```tsx +import AssetGrid from '@/components/shared/AssetGrid'; + + +``` + +### After: +```tsx +import ResponsiveVirtualizedAssetGrid from '@/components/shared/ResponsiveVirtualizedAssetGrid'; + +
+ +
+``` + +**Important:** The virtualized components require a container with a defined height. Make sure to wrap them in a div with appropriate height styling. + +## Custom Hook: useGridDimensions + +The `useGridDimensions` hook can be used to calculate optimal grid dimensions: + +```tsx +import { useGridDimensions } from '@/hooks'; + +const gridDimensions = useGridDimensions({ + containerWidth: 800, + containerHeight: 600, + itemSize: 200, + gap: 8, + minColumns: 2, + maxColumns: 8 +}); +``` + +## Example Usage + +See `src/components/shared/AssetGridExample.tsx` for a complete example showing different configurations of the virtualized grid components. + +## Performance Considerations + +- Use `ResponsiveVirtualizedAssetGrid` for most use cases as it automatically adapts to container size +- Set appropriate `targetItemSize` based on your design requirements +- Consider using smaller `gap` values for dense layouts +- The components work best with containers that have a defined height + +## Browser Support + +The components use modern browser APIs: +- ResizeObserver (for responsive behavior) +- IntersectionObserver (for lazy loading) +- CSS Grid and Flexbox + +For older browsers, consider using polyfills or the basic `VirtualizedAssetGrid` with fixed dimensions. diff --git a/package.json b/package.json index cc00a8b..913f8b2 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@remotion/cli": "4.0.232", "@remotion/eslint-plugin": "^4.0.232", "@tanstack/react-query": "^5.69.0", - "@tanstack/react-table": "^8.20.1", + "@tanstack/react-table": "^8.21.3", "@types/cookie": "^0.6.0", "@types/qs": "^6.9.15", "@types/react-autosuggest": "^10.1.11", diff --git a/src/components/shared/AssetGridExample.tsx b/src/components/shared/AssetGridExample.tsx new file mode 100644 index 0000000..e1913c7 --- /dev/null +++ b/src/components/shared/AssetGridExample.tsx @@ -0,0 +1,87 @@ +import React, { useRef } from 'react'; +import { IAsset } from '@/types/asset'; +import VirtualizedAssetGrid from './VirtualizedAssetGrid'; +import ResponsiveVirtualizedAssetGrid from './ResponsiveVirtualizedAssetGrid'; +import { Button } from '@/components/ui/button'; + +interface AssetGridExampleProps { + assets: IAsset[]; + onSelectionChange?: (ids: string[]) => void; +} + +export default function AssetGridExample({ assets, onSelectionChange }: AssetGridExampleProps) { + const gridRef = useRef(null); + + const handleSelectAll = () => { + gridRef.current?.selectAll(); + }; + + const handleUnselectAll = () => { + gridRef.current?.unselectAll(); + }; + + return ( +
+
+ + +
+ + {/* Example 1: Basic Virtualized Grid with fixed dimensions */} +
+

Fixed Size Virtualized Grid

+
+ +
+
+ + {/* Example 2: Responsive Virtualized Grid */} +
+

Responsive Virtualized Grid

+
+ +
+
+ + {/* Example 3: Responsive Grid with different target sizes */} +
+

Small Items Virtualized Grid

+
+ +
+
+
+ ); +} diff --git a/src/components/shared/FloatingBar.tsx b/src/components/shared/FloatingBar.tsx index 81aea89..072eb13 100644 --- a/src/components/shared/FloatingBar.tsx +++ b/src/components/shared/FloatingBar.tsx @@ -8,7 +8,7 @@ interface FloatingBarProps { export default function FloatingBar({ children, className }: FloatingBarProps) { return ( -
+
{children}
) diff --git a/src/components/shared/ResponsiveVirtualizedAssetGrid.tsx b/src/components/shared/ResponsiveVirtualizedAssetGrid.tsx new file mode 100644 index 0000000..95d0294 --- /dev/null +++ b/src/components/shared/ResponsiveVirtualizedAssetGrid.tsx @@ -0,0 +1,254 @@ +import "yet-another-react-lightbox/styles.css"; + +import { IAsset } from '@/types/asset'; +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState, useCallback, useRef } from 'react' +import Lightbox from 'yet-another-react-lightbox'; +import Download from "yet-another-react-lightbox/plugins/download"; +import Video from "yet-another-react-lightbox/plugins/video"; +import { usePhotoSelectionContext } from '@/contexts/PhotoSelectionContext'; +import { FixedSizeGrid as Grid } from 'react-window'; +import LazyImage from '../ui/lazy-image'; +import { humanizeDuration } from '@/helpers/string.helper'; +import { PlayIcon } from '@radix-ui/react-icons'; +import { useGridDimensions } from '@/hooks'; + +interface ResponsiveVirtualizedAssetGridProps { + assets: IAsset[]; + isInternal?: boolean; + selectable?: boolean; + onSelectionChange?: (ids: string[]) => void; + targetItemSize?: number; + gap?: number; + minColumns?: number; + maxColumns?: number; + className?: string; +} + +interface ResponsiveVirtualizedAssetGridRef { + getSelectedIds: () => string[]; + selectAll: () => void; + unselectAll: () => void; +} + +const ResponsiveVirtualizedAssetGrid = forwardRef(({ + assets, + isInternal = true, + selectable = false, + onSelectionChange, + targetItemSize = 200, + gap = 8, + minColumns = 2, + maxColumns = 8, + className = "" +}, ref) => { + const [index, setIndex] = useState(-1); + const [lastSelectedIndex, setLastSelectedIndex] = useState(-1); + const containerRef = useRef(null); + const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); + + // Use context for selection state + const { selectedIds, updateContext } = usePhotoSelectionContext(); + + // Calculate grid dimensions + const gridDimensions = useGridDimensions({ + containerWidth: containerSize.width, + containerHeight: containerSize.height, + itemSize: targetItemSize, + gap, + minColumns, + maxColumns + }); + + // Update row count when assets change + useEffect(() => { + gridDimensions.updateRowCount(assets.length); + }, [assets.length, gridDimensions]); + + // Resize observer to handle container size changes + useEffect(() => { + if (!containerRef.current) return; + + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + setContainerSize({ width, height }); + } + }); + + resizeObserver.observe(containerRef.current); + + return () => { + resizeObserver.disconnect(); + }; + }, []); + + useImperativeHandle(ref, () => ({ + getSelectedIds: () => selectedIds, + selectAll: () => { + const allIds = assets.map((asset) => asset.id); + updateContext({ selectedIds: allIds }); + onSelectionChange?.(allIds); + }, + unselectAll: () => { + updateContext({ selectedIds: [] }); + onSelectionChange?.([]); + }, + }), [assets, selectedIds, updateContext]); + + const slides = useMemo(() => { + return assets.map((asset) => ({ + ...asset, + orientation: 1, + src: asset.previewUrl as string, + type: (asset.type === "VIDEO" ? "video" : "image") as any, + sources: + asset.type === "VIDEO" + ? [ + { + src: asset.downloadUrl as string, + type: "video/mp4", + }, + ] + : undefined, + height: asset.exifImageHeight as number, + width: asset.exifImageWidth as number, + downloadUrl: asset.downloadUrl as string, + })); + }, [assets]); + + const handleClick = useCallback((index: number, asset: IAsset, event: React.MouseEvent) => { + if (selectedIds.length > 0) { + handleSelect(index, asset, event); + } else { + setIndex(index); + } + }, [selectedIds]); + + const handleSelect = useCallback((_idx: number, asset: IAsset, event: React.MouseEvent) => { + event.stopPropagation(); + const isPresent = selectedIds.includes(asset.id); + if (isPresent) { + const newSelectedIds = selectedIds.filter((id) => id !== asset.id); + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); + } else { + const clickedIndex = assets.findIndex((a) => a.id === asset.id); + if (event.shiftKey) { + const startIndex = Math.min(clickedIndex, lastSelectedIndex); + const endIndex = Math.max(clickedIndex, lastSelectedIndex); + const rangeSelectedIds = assets.slice(startIndex, endIndex + 1).map((a) => a.id); + const allSelectedIds = [...selectedIds, ...rangeSelectedIds]; + const uniqueSelectedIds = [...new Set(allSelectedIds)]; + updateContext({ selectedIds: uniqueSelectedIds }); + onSelectionChange?.(uniqueSelectedIds); + } else { + const newSelectedIds = [...selectedIds, asset.id]; + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); + } + setLastSelectedIndex(clickedIndex); + } + }, [selectedIds, assets, lastSelectedIndex, updateContext, onSelectionChange]); + + const handleEsc = useCallback((event: KeyboardEvent) => { + if (event.key === "Escape") { + updateContext({ selectedIds: [] }); + onSelectionChange?.([]); + } + }, [updateContext, onSelectionChange]); + + useEffect(() => { + window.addEventListener("keydown", handleEsc); + return () => window.removeEventListener("keydown", handleEsc); + }, [handleEsc]); + + // Cell renderer for React Window + const Cell = useCallback(({ columnIndex, rowIndex, style }: { columnIndex: number; rowIndex: number; style: React.CSSProperties }) => { + const assetIndex = rowIndex * gridDimensions.columnCount + columnIndex; + const asset = assets[assetIndex]; + + if (!asset) { + return
; + } + + const isSelected = selectedIds.includes(asset.id); + + return ( +
handleClick(assetIndex, asset, e)} + > +
+ + {asset.type === "VIDEO" && ( +
+ + {asset.duration && ( + + {humanizeDuration(asset.duration)} + + )} +
+ )} + {selectable && ( +
+ )} +
+
+ ); + }, [assets, selectedIds, gridDimensions.columnCount, handleClick, selectable, gap]); + + // Don't render grid until we have container dimensions + if (containerSize.width === 0 || gridDimensions.rowCount === 0) { + return ( +
+
+
Loading...
+
+
+ ); + } + + return ( +
+ = 0} + index={index} + close={() => setIndex(-1)} + /> + + {Cell} + +
+ ); +}); + +ResponsiveVirtualizedAssetGrid.displayName = "ResponsiveVirtualizedAssetGrid"; +export default ResponsiveVirtualizedAssetGrid; diff --git a/src/components/shared/VirtualizedAssetGrid.tsx b/src/components/shared/VirtualizedAssetGrid.tsx new file mode 100644 index 0000000..c038131 --- /dev/null +++ b/src/components/shared/VirtualizedAssetGrid.tsx @@ -0,0 +1,205 @@ +import "yet-another-react-lightbox/styles.css"; + +import { IAsset } from '@/types/asset'; +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState, useCallback } from 'react' +import Lightbox from 'yet-another-react-lightbox'; +import Download from "yet-another-react-lightbox/plugins/download"; +import Video from "yet-another-react-lightbox/plugins/video"; +import { usePhotoSelectionContext } from '@/contexts/PhotoSelectionContext'; +import { FixedSizeGrid as Grid } from 'react-window'; +import LazyImage from '../ui/lazy-image'; +import { humanizeDuration } from '@/helpers/string.helper'; +import { PlayIcon } from '@radix-ui/react-icons'; + +interface VirtualizedAssetGridProps { + assets: IAsset[]; + isInternal?: boolean; + selectable?: boolean; + onSelectionChange?: (ids: string[]) => void; + columnCount?: number; + itemSize?: number; + height?: number; +} + +interface VirtualizedAssetGridRef { + getSelectedIds: () => string[]; + selectAll: () => void; + unselectAll: () => void; +} + +const VirtualizedAssetGrid = forwardRef(({ + assets, + isInternal = true, + selectable = false, + onSelectionChange, + columnCount = 5, + itemSize = 200, + height = 600 +}, ref) => { + const [index, setIndex] = useState(-1); + const [lastSelectedIndex, setLastSelectedIndex] = useState(-1); + + // Use context for selection state + const { selectedIds, updateContext } = usePhotoSelectionContext(); + + useImperativeHandle(ref, () => ({ + getSelectedIds: () => selectedIds, + selectAll: () => { + const allIds = assets.map((asset) => asset.id); + updateContext({ selectedIds: allIds }); + onSelectionChange?.(allIds); + }, + unselectAll: () => { + updateContext({ selectedIds: [] }); + onSelectionChange?.([]); + }, + }), [assets, selectedIds, updateContext]); + + const slides = useMemo(() => { + return assets.map((asset) => ({ + ...asset, + orientation: 1, + src: asset.previewUrl as string, + type: (asset.type === "VIDEO" ? "video" : "image") as any, + sources: + asset.type === "VIDEO" + ? [ + { + src: asset.downloadUrl as string, + type: "video/mp4", + }, + ] + : undefined, + height: asset.exifImageHeight as number, + width: asset.exifImageWidth as number, + downloadUrl: asset.downloadUrl as string, + })); + }, [assets]); + + const handleClick = useCallback((index: number, asset: IAsset, event: React.MouseEvent) => { + if (selectedIds.length > 0) { + handleSelect(index, asset, event); + } else { + setIndex(index); + } + }, [selectedIds]); + + const handleSelect = useCallback((_idx: number, asset: IAsset, event: React.MouseEvent) => { + event.stopPropagation(); + const isPresent = selectedIds.includes(asset.id); + if (isPresent) { + const newSelectedIds = selectedIds.filter((id) => id !== asset.id); + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); + } else { + const clickedIndex = assets.findIndex((a) => a.id === asset.id); + if (event.shiftKey) { + const startIndex = Math.min(clickedIndex, lastSelectedIndex); + const endIndex = Math.max(clickedIndex, lastSelectedIndex); + const rangeSelectedIds = assets.slice(startIndex, endIndex + 1).map((a) => a.id); + const allSelectedIds = [...selectedIds, ...rangeSelectedIds]; + const uniqueSelectedIds = [...new Set(allSelectedIds)]; + updateContext({ selectedIds: uniqueSelectedIds }); + onSelectionChange?.(uniqueSelectedIds); + } else { + const newSelectedIds = [...selectedIds, asset.id]; + updateContext({ selectedIds: newSelectedIds }); + onSelectionChange?.(newSelectedIds); + } + setLastSelectedIndex(clickedIndex); + } + }, [selectedIds, assets, lastSelectedIndex, updateContext, onSelectionChange]); + + const handleEsc = useCallback((event: KeyboardEvent) => { + if (event.key === "Escape") { + updateContext({ selectedIds: [] }); + onSelectionChange?.([]); + } + }, [updateContext, onSelectionChange]); + + useEffect(() => { + window.addEventListener("keydown", handleEsc); + return () => window.removeEventListener("keydown", handleEsc); + }, [handleEsc]); + + // Calculate grid dimensions + const rowCount = Math.ceil(assets.length / columnCount); + const width = columnCount * itemSize; + + // Cell renderer for React Window + const Cell = useCallback(({ columnIndex, rowIndex, style }: { columnIndex: number; rowIndex: number; style: React.CSSProperties }) => { + const assetIndex = rowIndex * columnCount + columnIndex; + const asset = assets[assetIndex]; + + if (!asset) { + return
; + } + + const isSelected = selectedIds.includes(asset.id); + + return ( +
handleClick(assetIndex, asset, e)} + > +
+ + {asset.type === "VIDEO" && ( +
+ + {asset.duration && ( + + {humanizeDuration(asset.duration)} + + )} +
+ )} + {selectable && ( +
+ )} +
+
+ ); + }, [assets, selectedIds, columnCount, handleClick, selectable]); + + return ( +
+ = 0} + index={index} + close={() => setIndex(-1)} + /> + + {Cell} + +
+ ); +}); + +VirtualizedAssetGrid.displayName = "VirtualizedAssetGrid"; +export default VirtualizedAssetGrid; diff --git a/src/components/ui/data-table.tsx b/src/components/ui/data-table.tsx index 8fd8bb6..cfc3b73 100644 --- a/src/components/ui/data-table.tsx +++ b/src/components/ui/data-table.tsx @@ -13,20 +13,15 @@ import { useReactTable, VisibilityState, } from "@tanstack/react-table" -import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react" +import { ChevronDown } from "lucide-react" import { Button } from "@/components/ui/button" -import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" -import { Input } from "@/components/ui/input" import { TableRoot, TableBody, @@ -94,7 +89,6 @@ export function DataTable({ enableSorting: true, enableFilters: true, enableColumnFilters: true, - enablePagination: true, }) // Sync external selection with table selection @@ -175,22 +169,10 @@ export function DataTable({ { - // Prevent row click from interfering with link clicks - if (e.target instanceof HTMLAnchorElement) { - e.stopPropagation() - } - }} > {row.getVisibleCells().map((cell) => ( { - // Allow link clicks to propagate - if (e.target instanceof HTMLAnchorElement) { - e.stopPropagation() - } - }} > {flexRender( cell.column.columnDef.cell, diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 7714555..2a4749c 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1 +1,2 @@ -export { useAlbumSelection } from './useAlbumSelection' \ No newline at end of file +export { useAlbumSelection } from './useAlbumSelection' +export { useGridDimensions } from './useGridDimensions' \ No newline at end of file diff --git a/src/hooks/useGridDimensions.ts b/src/hooks/useGridDimensions.ts new file mode 100644 index 0000000..c22aba9 --- /dev/null +++ b/src/hooks/useGridDimensions.ts @@ -0,0 +1,82 @@ +import { useState, useEffect, useCallback } from 'react'; + +interface UseGridDimensionsProps { + containerWidth: number; + containerHeight: number; + itemSize: number; + gap?: number; + minColumns?: number; + maxColumns?: number; +} + +interface GridDimensions { + columnCount: number; + rowCount: number; + itemSize: number; + gap: number; + width: number; + height: number; +} + +export const useGridDimensions = ({ + containerWidth, + containerHeight, + itemSize, + gap = 8, + minColumns = 2, + maxColumns = 10 +}: UseGridDimensionsProps): GridDimensions => { + const [dimensions, setDimensions] = useState({ + columnCount: minColumns, + rowCount: 0, + itemSize, + gap, + width: containerWidth, + height: containerHeight + }); + + const calculateDimensions = useCallback(() => { + if (containerWidth <= 0) return; + + // Calculate optimal column count based on container width + const availableWidth = containerWidth - gap; // Account for gap + const optimalColumnCount = Math.floor(availableWidth / (itemSize + gap)); + + // Clamp column count between min and max + const columnCount = Math.max(minColumns, Math.min(maxColumns, optimalColumnCount)); + + // Calculate actual item size to fit the container + const actualItemSize = (availableWidth - (columnCount - 1) * gap) / columnCount; + + // Calculate total width needed + const totalWidth = columnCount * actualItemSize + (columnCount - 1) * gap; + + // Calculate height (this will be updated when we know the total number of items) + const totalHeight = containerHeight; + + setDimensions({ + columnCount, + rowCount: 0, // Will be calculated when we have the data + itemSize: actualItemSize, + gap, + width: totalWidth, + height: totalHeight + }); + }, [containerWidth, containerHeight, itemSize, gap, minColumns, maxColumns]); + + useEffect(() => { + calculateDimensions(); + }, [calculateDimensions]); + + const updateRowCount = useCallback((totalItems: number) => { + setDimensions(prev => ({ + ...prev, + rowCount: Math.ceil(totalItems / prev.columnCount) + })); + }, []); + + return { + ...dimensions, + updateRowCount + }; +}; diff --git a/src/pages/albums/[albumId].tsx b/src/pages/albums/[albumId].tsx index 2cf9e87..c67c7bf 100644 --- a/src/pages/albums/[albumId].tsx +++ b/src/pages/albums/[albumId].tsx @@ -145,7 +145,7 @@ export default function AlbumListPage() { } return ( - +
+
@@ -233,7 +233,7 @@ export default function AlbumListPage() { /> {renderContent()} {currentSelectedCount > 0 && ( - +

{currentSelectedCount} Selected diff --git a/src/pages/albums/potential-albums.tsx b/src/pages/albums/potential-albums.tsx index 98fe253..e9cccf6 100644 --- a/src/pages/albums/potential-albums.tsx +++ b/src/pages/albums/potential-albums.tsx @@ -112,7 +112,7 @@ export default function PotentialAlbums() { } return ( - +

+
+
+
{geminiEnabled ? ( <> From ed411ae68e1710fb461b742491fb4911475aea25 Mon Sep 17 00:00:00 2001 From: Varun Raj Date: Sat, 23 Aug 2025 18:07:10 +0530 Subject: [PATCH 12/12] fix: data table fixes Signed-off-by: Varun Raj --- bun.lockb | Bin 475839 -> 490231 bytes package.json | 1 + src/components/ui/context-menu.tsx | 197 +++++++++++++++ src/components/ui/data-table.tsx | 380 ++++++++++++++++------------- src/pages/albums/index.tsx | 10 +- 5 files changed, 413 insertions(+), 175 deletions(-) create mode 100644 src/components/ui/context-menu.tsx diff --git a/bun.lockb b/bun.lockb index 7310b1b28ea4f4484bf9a9178bf065f5c78bbe4d..f82886271f2b8cb8281196536ccad690efe87604 100755 GIT binary patch delta 91001 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 delta 84734 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 Mt{!sK?YlYuANgZ*L;wH) diff --git a/package.json b/package.json index 913f8b2..91dd1ea 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.0", "@radix-ui/react-checkbox": "^1.1.2", + "@radix-ui/react-context-menu": "^2.2.16", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-hover-card": "^1.1.1", diff --git a/src/components/ui/context-menu.tsx b/src/components/ui/context-menu.tsx new file mode 100644 index 0000000..6d0fd00 --- /dev/null +++ b/src/components/ui/context-menu.tsx @@ -0,0 +1,197 @@ +import * as React from "react" +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" +import { cn } from "@/lib/utils" +import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons" + +const ContextMenu = ContextMenuPrimitive.Root + +const ContextMenuTrigger = ContextMenuPrimitive.Trigger + +const ContextMenuGroup = ContextMenuPrimitive.Group + +const ContextMenuPortal = ContextMenuPrimitive.Portal + +const ContextMenuSub = ContextMenuPrimitive.Sub + +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup + +const ContextMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName + +const ContextMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName + +const ContextMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName + +const ContextMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName + +const ContextMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuCheckboxItem.displayName = + ContextMenuPrimitive.CheckboxItem.displayName + +const ContextMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName + +const ContextMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName + +const ContextMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName + +const ContextMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +ContextMenuShortcut.displayName = "ContextMenuShortcut" + +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +} diff --git a/src/components/ui/data-table.tsx b/src/components/ui/data-table.tsx index cfc3b73..cc3aeb6 100644 --- a/src/components/ui/data-table.tsx +++ b/src/components/ui/data-table.tsx @@ -22,6 +22,13 @@ import { DropdownMenuContent, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuTrigger, +} from "@/components/ui/context-menu" import { TableRoot, TableBody, @@ -35,190 +42,221 @@ interface DataTableProps { columns: ColumnDef[] data: TData[] onRowSelectionChange?: (selectedIds: string[]) => void - selectedIds?: string[] getRowId?: (row: TData) => string searchValue?: string onSearchChange?: (value: string) => void } -export function DataTable({ - columns, - data, - onRowSelectionChange, - selectedIds = [], - getRowId, - searchValue, - onSearchChange, -}: DataTableProps) { - const [sorting, setSorting] = React.useState([]) - const [columnFilters, setColumnFilters] = React.useState([]) - const [columnVisibility, setColumnVisibility] = React.useState({}) - - // Initialize row selection from selectedIds - const initialRowSelection = React.useMemo(() => { - const selection: Record = {} - selectedIds.forEach(id => { - selection[id] = true +export interface DataTableRef { + selectRows: (rowIds: string[]) => void + selectAllRows: () => void + deselectAllRows: () => void + getSelectedRows: () => string[] + clearSelection: () => void +} + +const DataTable = React.forwardRef, DataTableProps>( + ({ columns, data, onRowSelectionChange, getRowId, searchValue, onSearchChange }, ref) => { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState({}) + const [rowSelection, setRowSelection] = React.useState>({}) + + const table = useReactTable({ + data, + columns, + getRowId: getRowId || ((row: any) => row.id), + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + // Add these options to prevent potential issues + enableRowSelection: true, + enableMultiRowSelection: true, + enableSorting: true, + enableFilters: true, + enableColumnFilters: true, }) - return selection - }, [selectedIds]) - - const [rowSelection, setRowSelection] = React.useState>(initialRowSelection) - const table = useReactTable({ - data, - columns, - getRowId: getRowId || ((row: any) => row.id), - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnVisibilityChange: setColumnVisibility, - onRowSelectionChange: setRowSelection, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection, - }, - // Add these options to prevent potential issues - enableRowSelection: true, - enableMultiRowSelection: true, - enableSorting: true, - enableFilters: true, - enableColumnFilters: true, - }) + // Expose methods via ref + React.useImperativeHandle(ref, () => ({ + selectRows: (rowIds: string[]) => { + const newSelection: Record = {} + rowIds.forEach(id => { + newSelection[id] = true + }) + setRowSelection(newSelection) + }, + selectAllRows: () => { + const allRowIds = table.getRowModel().rows.map(row => row.id) + const newSelection: Record = {} + allRowIds.forEach(id => { + newSelection[id] = true + }) + setRowSelection(newSelection) + }, + deselectAllRows: () => { + setRowSelection({}) + }, + getSelectedRows: () => { + return Object.keys(rowSelection).filter(id => rowSelection[id]) + }, + clearSelection: () => { + setRowSelection({}) + }, + }), [table]) - // Sync external selection with table selection - React.useEffect(() => { - const newRowSelection: Record = {} - selectedIds.forEach((id) => { - newRowSelection[id] = true - }) - setRowSelection(newRowSelection) - }, [selectedIds]) + // Sync external search with table filter + React.useEffect(() => { + if (searchValue !== undefined) { + table.getColumn("albumName")?.setFilterValue(searchValue) + } + }, [searchValue, table]) - // Sync external search with table filter - React.useEffect(() => { - if (searchValue !== undefined) { - table.getColumn("albumName")?.setFilterValue(searchValue) + // Notify parent of selection changes + React.useEffect(() => { + const selectedRowIds = Object.keys(rowSelection).filter(id => rowSelection[id]) + onRowSelectionChange?.(selectedRowIds) + }, [rowSelection, onRowSelectionChange]) + + const handleShowAllColumns = () => { + table.toggleAllColumnsVisible(true) } - }, [searchValue, table]) - // Notify parent of selection changes - React.useEffect(() => { - const selectedRowIds = Object.keys(rowSelection).filter(id => rowSelection[id]) - onRowSelectionChange?.(selectedRowIds) - }, [rowSelection, onRowSelectionChange]) + const handleHideAllColumns = () => { + table.toggleAllColumnsVisible(false) + } - return ( -
-
- - - - - - {table - .getAllColumns() - .filter((column) => column.getCanHide()) - .map((column) => { - return ( - - column.toggleVisibility(!!value) - } - > - {column.id} - - ) - })} - - -
-
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + + + header.column.toggleVisibility()} + > + {header.column.getIsVisible() ? "Hide Column" : "Show Column"} + + + + Show All Columns + + + Hide All Columns + + +
+ Column Visibility +
+ {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + column.toggleVisibility()} + className="flex items-center justify-between" + > + {column.id} +
+ + ) + })} + + + ) + })} - )) - ) : ( - - - No results. - - - )} - - -
-
-
- {table.getFilteredSelectedRowModel().rows.length} of{" "} - {table.getFilteredRowModel().rows.length} row(s) selected. + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
-
- - +
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ + +
-
- ) -} \ No newline at end of file + ) + } +) + +DataTable.displayName = "DataTable" + +export default DataTable \ No newline at end of file diff --git a/src/pages/albums/index.tsx b/src/pages/albums/index.tsx index af4c45f..f018ce4 100644 --- a/src/pages/albums/index.tsx +++ b/src/pages/albums/index.tsx @@ -16,7 +16,7 @@ import { AlertDialog } from '@/components/ui/alert-dialog' import toast from 'react-hot-toast' import { useAlbumSelection } from '@/hooks' import FloatingBar from '@/components/shared/FloatingBar' -import { DataTable } from '@/components/ui/data-table' +import DataTable, { DataTableRef } from '@/components/ui/data-table' import { albumColumns } from '@/components/albums/AlbumTableColumns' const SORT_BY_OPTIONS = [ @@ -41,6 +41,8 @@ export default function AlbumListPage() { const [errorMessage, setErrorMessage] = useState('') const albumShareDialogRef = useRef(null); const [deleting, setDeleting] = useState(false) + + const dataTableRef = useRef>(null) // Separate selection state for table view const [tableSelectedIds, setTableSelectedIds] = useState([]) @@ -103,9 +105,9 @@ export default function AlbumListPage() { }) } - const handleTableSelectionChange = (selectedRowIds: string[]) => { + const handleTableSelectionChange = useCallback((selectedRowIds: string[]) => { setTableSelectedIds(selectedRowIds) - } + }, []) const handleSelectAll = () => { if (viewMode === 'table') { @@ -140,11 +142,11 @@ export default function AlbumListPage() { row.id} searchValue={search} onSearchChange={setSearch} + ref={dataTableRef} />
)