mirror of
https://github.com/navidrome/navidrome.git
synced 2025-12-23 23:18:05 -05:00
feat(ui): show playlist owner
This commit is contained in:
@@ -191,6 +191,7 @@
|
||||
"sync": "Auto-import",
|
||||
"path": "Import from"
|
||||
},
|
||||
"byOwner": "by %{name}",
|
||||
"actions": {
|
||||
"selectPlaylist": "Select a playlist:",
|
||||
"addNewPlaylist": "Create \"%{name}\"",
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
useMediaQuery,
|
||||
} from '@material-ui/core'
|
||||
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 Lightbox from 'react-image-lightbox'
|
||||
import 'react-image-lightbox/style.css'
|
||||
@@ -82,6 +82,7 @@ const useStyles = makeStyles(
|
||||
const PlaylistDetails = (props) => {
|
||||
const { record = {} } = props
|
||||
const translate = useTranslate()
|
||||
const { permissions } = usePermissions()
|
||||
const classes = useStyles()
|
||||
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
|
||||
const [isLightboxOpen, setLightboxOpen] = useState(false)
|
||||
@@ -159,6 +160,14 @@ const PlaylistDetails = (props) => {
|
||||
<span> </span>
|
||||
)}
|
||||
</Typography>
|
||||
{(record.public || permissions === 'admin') && (
|
||||
<Typography component="p">
|
||||
{translate('resources.playlist.byOwner', {
|
||||
name: record.ownerName,
|
||||
_: `by ${record.ownerName}`,
|
||||
})}
|
||||
</Typography>
|
||||
)}
|
||||
<CollapsibleComment record={record} />
|
||||
</CardContent>
|
||||
</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()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user