diff --git a/ui/src/common/SongDatagrid.jsx b/ui/src/common/SongDatagrid.jsx
index d2c98bbe7..4a813f84d 100644
--- a/ui/src/common/SongDatagrid.jsx
+++ b/ui/src/common/SongDatagrid.jsx
@@ -78,7 +78,7 @@ const useStyles = makeStyles({
},
})
-const DiscSubtitleRow = forwardRef(
+export const DiscSubtitleRow = forwardRef(
({ record, onClick, colSpan, contextAlwaysVisible }, ref) => {
const translate = useTranslate()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
@@ -153,13 +153,17 @@ const DiscSubtitleRow = forwardRef(
{subtitle}
{isLightboxOpen && !imageError && (
-
+ // Lightbox portals out of the row, but React still bubbles its
+ // events up this tree, where the row's onClick would play the disc.
+ e.stopPropagation()}>
+
+
)}
diff --git a/ui/src/common/SongDatagrid.test.jsx b/ui/src/common/SongDatagrid.test.jsx
new file mode 100644
index 000000000..f8459d8eb
--- /dev/null
+++ b/ui/src/common/SongDatagrid.test.jsx
@@ -0,0 +1,74 @@
+import React from 'react'
+import { render, fireEvent, screen } from '@testing-library/react'
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+import { createTheme, ThemeProvider } from '@material-ui/core/styles'
+import { DiscSubtitleRow } from './SongDatagrid'
+
+vi.mock('../subsonic', () => ({
+ default: { getDiscCoverArtUrl: () => 'http://localhost/cover.jpg' },
+}))
+
+vi.mock('react-redux', () => ({ useDispatch: () => vi.fn() }))
+
+vi.mock('../common', () => ({ AlbumContextMenu: () => null }))
+
+vi.mock('react-dnd', () => ({ useDrag: () => [{}, vi.fn()] }))
+
+const record = {
+ id: 'song-1',
+ albumId: 'album-1',
+ album: 'The Album',
+ discNumber: 2,
+ discSubtitle: 'Bonus Disc',
+ updatedAt: '2024-01-01',
+}
+
+const renderRow = (onClick) =>
+ render(
+
+
+ ,
+ )
+
+const openLightbox = () => {
+ fireEvent.click(document.querySelector('img'))
+ expect(document.querySelector('.ril__closeButton')).toBeTruthy()
+}
+
+describe('DiscSubtitleRow', () => {
+ beforeEach(() => vi.clearAllMocks())
+
+ it('plays the disc when the row is clicked', () => {
+ const onClick = vi.fn()
+ renderRow(onClick)
+ fireEvent.click(screen.getByText('Bonus Disc'))
+ expect(onClick).toHaveBeenCalledWith(2)
+ })
+
+ it('does not play the disc when opening the lightbox', () => {
+ const onClick = vi.fn()
+ renderRow(onClick)
+ openLightbox()
+ expect(onClick).not.toHaveBeenCalled()
+ })
+
+ it('does not play the disc when closing the lightbox', () => {
+ const onClick = vi.fn()
+ renderRow(onClick)
+ openLightbox()
+ fireEvent.click(document.querySelector('.ril__closeButton'))
+ expect(onClick).not.toHaveBeenCalled()
+ })
+
+ it('does not play the disc when clicking the lightbox backdrop', () => {
+ const onClick = vi.fn()
+ renderRow(onClick)
+ openLightbox()
+ fireEvent.click(document.querySelector('.ril__inner'))
+ expect(onClick).not.toHaveBeenCalled()
+ })
+})