mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
Compare commits
2 Commits
9deb36dacf
...
bc5ba236e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc5ba236e0 | ||
|
|
c9c0861ec1 |
@ -207,6 +207,7 @@
|
|||||||
"sync": "Auto-import",
|
"sync": "Auto-import",
|
||||||
"path": "Import from"
|
"path": "Import from"
|
||||||
},
|
},
|
||||||
|
"byOwner": "by %{name}",
|
||||||
"actions": {
|
"actions": {
|
||||||
"selectPlaylist": "Select a playlist:",
|
"selectPlaylist": "Select a playlist:",
|
||||||
"addNewPlaylist": "Create \"%{name}\"",
|
"addNewPlaylist": "Create \"%{name}\"",
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
} from '@material-ui/core'
|
} from '@material-ui/core'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import { useTranslate } from 'react-admin'
|
import { useTranslate, usePermissions } from 'react-admin'
|
||||||
import { useCallback, useState, useEffect } from 'react'
|
import { useCallback, useState, useEffect } from 'react'
|
||||||
import Lightbox from 'react-image-lightbox'
|
import Lightbox from 'react-image-lightbox'
|
||||||
import 'react-image-lightbox/style.css'
|
import 'react-image-lightbox/style.css'
|
||||||
@ -86,6 +86,7 @@ const useStyles = makeStyles(
|
|||||||
const PlaylistDetails = (props) => {
|
const PlaylistDetails = (props) => {
|
||||||
const { record = {} } = props
|
const { record = {} } = props
|
||||||
const translate = useTranslate()
|
const translate = useTranslate()
|
||||||
|
const { permissions } = usePermissions()
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
|
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
|
||||||
const [isLightboxOpen, setLightboxOpen] = useState(false)
|
const [isLightboxOpen, setLightboxOpen] = useState(false)
|
||||||
@ -163,6 +164,14 @@ const PlaylistDetails = (props) => {
|
|||||||
<span> </span>
|
<span> </span>
|
||||||
)}
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{(record.public || permissions === 'admin') && (
|
||||||
|
<Typography component="p">
|
||||||
|
{translate('resources.playlist.byOwner', {
|
||||||
|
name: record.ownerName,
|
||||||
|
_: `by ${record.ownerName}`,
|
||||||
|
})}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
<CollapsibleComment record={record} />
|
<CollapsibleComment record={record} />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
61
ui/src/playlist/PlaylistDetails.test.jsx
Normal file
61
ui/src/playlist/PlaylistDetails.test.jsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render, screen, cleanup } from '@testing-library/react'
|
||||||
|
import PlaylistDetails from './PlaylistDetails'
|
||||||
|
import { usePermissions } from 'react-admin'
|
||||||
|
import { useMediaQuery } from '@material-ui/core'
|
||||||
|
|
||||||
|
vi.mock('react-admin', () => ({
|
||||||
|
usePermissions: vi.fn(),
|
||||||
|
useTranslate: () => (key, opts) => {
|
||||||
|
if (key === 'resources.playlist.byOwner') {
|
||||||
|
return `by ${opts.name}`
|
||||||
|
}
|
||||||
|
if (key === 'resources.song.name') {
|
||||||
|
return opts.smart_count === 1 ? 'Song' : 'Songs'
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
},
|
||||||
|
useRecordContext: (props) => props.record || {},
|
||||||
|
}))
|
||||||
|
|
||||||
|
vi.mock('@material-ui/core', async (importOriginal) => {
|
||||||
|
const actual = await importOriginal()
|
||||||
|
return { ...actual, useMediaQuery: vi.fn() }
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('<PlaylistDetails />', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks()
|
||||||
|
useMediaQuery.mockReturnValue(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(cleanup)
|
||||||
|
|
||||||
|
const baseRecord = {
|
||||||
|
id: 'pl1',
|
||||||
|
name: 'My Playlist',
|
||||||
|
songCount: 1,
|
||||||
|
duration: 60,
|
||||||
|
size: 1024,
|
||||||
|
ownerName: 'Owner',
|
||||||
|
public: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
it('shows owner for admin users', () => {
|
||||||
|
usePermissions.mockReturnValue({ permissions: 'admin' })
|
||||||
|
render(<PlaylistDetails record={baseRecord} />)
|
||||||
|
expect(screen.getByText('by Owner')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows owner for public playlists', () => {
|
||||||
|
usePermissions.mockReturnValue({ permissions: 'user' })
|
||||||
|
render(<PlaylistDetails record={{ ...baseRecord, public: true }} />)
|
||||||
|
expect(screen.getByText('by Owner')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('hides owner for private playlists when not admin', () => {
|
||||||
|
usePermissions.mockReturnValue({ permissions: 'user' })
|
||||||
|
render(<PlaylistDetails record={baseRecord} />)
|
||||||
|
expect(screen.queryByText('by Owner')).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
x
Reference in New Issue
Block a user