diff --git a/ui/src/common/PathField.jsx b/ui/src/common/PathField.jsx index 115a2ee49..21822878a 100644 --- a/ui/src/common/PathField.jsx +++ b/ui/src/common/PathField.jsx @@ -1,24 +1,22 @@ import PropTypes from 'prop-types' import React from 'react' -import { useRecordContext } from 'react-admin' +import { usePermissions, useRecordContext } from 'react-admin' import config from '../config' export const PathField = (props) => { const record = useRecordContext(props) - return ( - - {record.libraryPath} - {config.separator} - {record.path} - - ) + const { permissions } = usePermissions() + let path = permissions === 'admin' ? record.libraryPath : '' + + if (path && path.endsWith(config.separator)) { + path = `${path}${record.path}` + } else { + path = path ? `${path}${config.separator}${record.path}` : record.path + } + + return {path} } PathField.propTypes = { - label: PropTypes.string, record: PropTypes.object, } - -PathField.defaultProps = { - addLabel: true, -} diff --git a/ui/src/common/PathField.test.jsx b/ui/src/common/PathField.test.jsx new file mode 100644 index 000000000..de8b90899 --- /dev/null +++ b/ui/src/common/PathField.test.jsx @@ -0,0 +1,86 @@ +import React from 'react' +import { render } from '@testing-library/react' +import { PathField } from './PathField' +import { usePermissions, useRecordContext } from 'react-admin' +import config from '../config' + +// Mock react-admin hooks +vi.mock('react-admin', () => ({ + usePermissions: vi.fn(), + useRecordContext: vi.fn(), +})) + +// Mock config +vi.mock('../config', () => ({ + default: { + separator: '/', + }, +})) + +describe('PathField', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('renders path without libraryPath for non-admin users', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'user' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('music/song.mp3') + expect(container.textContent).not.toContain('/data/media') + }) + + it('renders combined path for admin users when libraryPath does not end with separator', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('/data/media/music/song.mp3') + }) + + it('renders combined path for admin users when libraryPath ends with separator', () => { + // Setup + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music/song.mp3', + libraryPath: '/data/media/', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('/data/media/music/song.mp3') + }) + + it('works with a different separator from config', () => { + // Setup + config.separator = '\\' + usePermissions.mockReturnValue({ permissions: 'admin' }) + useRecordContext.mockReturnValue({ + path: 'music\\song.mp3', + libraryPath: 'C:\\data', + }) + + // Act + const { container } = render() + + // Assert + expect(container.textContent).toBe('C:\\data\\music\\song.mp3') + }) +})