diff --git a/ui/src/album/AlbumDetails.js b/ui/src/album/AlbumDetails.js
index ffce4e7bd..64775e7a6 100644
--- a/ui/src/album/AlbumDetails.js
+++ b/ui/src/album/AlbumDetails.js
@@ -8,7 +8,13 @@ import {
Typography,
useMediaQuery,
} from '@material-ui/core'
-import { useTranslate } from 'react-admin'
+import {
+ useRecordContext,
+ useTranslate,
+ ArrayField,
+ SingleFieldList,
+ ChipField,
+} from 'react-admin'
import clsx from 'clsx'
import Lightbox from 'react-image-lightbox'
import 'react-image-lightbox/style.css'
@@ -22,6 +28,7 @@ import {
RatingField,
} from '../common'
import config from '../config'
+import { intersperse } from '../utils'
const useStyles = makeStyles(
(theme) => ({
@@ -85,6 +92,9 @@ const useStyles = makeStyles(
recordName: {},
recordArtist: {},
recordMeta: {},
+ genreList: {
+ marginTop: theme.spacing(1),
+ },
}),
{
name: 'NDAlbumDetails',
@@ -126,23 +136,49 @@ const AlbumComment = ({ record }) => {
)
}
-const AlbumDetails = ({ record }) => {
+const GenreList = () => {
+ const classes = useStyles()
+ return (
+
+
+
+
+
+ )
+}
+
+const Details = (props) => {
+ const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
+ const translate = useTranslate()
+ const record = useRecordContext(props)
+ let details = []
+ const addDetail = (obj) => {
+ const id = details.length
+ details.push({obj})
+ }
+
+ const year = formatRange(record, 'year')
+ year && addDetail(<>{year}>)
+ addDetail(
+ <>
+ {record.songCount +
+ ' ' +
+ translate('resources.song.name', {
+ smart_count: record.songCount,
+ })}
+ >
+ )
+ !isXsmall && addDetail()
+ !isXsmall && addDetail()
+
+ return <>{intersperse(details, ' · ')}>
+}
+
+const AlbumDetails = (props) => {
+ const record = useRecordContext(props)
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
const classes = useStyles()
const [isLightboxOpen, setLightboxOpen] = React.useState(false)
- const translate = useTranslate()
-
- const genreYear = (record) => {
- let genreDateLine = []
- if (record.genre) {
- genreDateLine.push(record.genre)
- }
- const year = formatRange(record, 'year')
- if (year) {
- genreDateLine.push(year)
- }
- return genreDateLine.join(' · ')
- }
const imageUrl = subsonic.getCoverArtUrl(record, 300)
const fullImageUrl = subsonic.getCoverArtUrl(record)
@@ -188,16 +224,7 @@ const AlbumDetails = ({ record }) => {
- {genreYear(record)}
-
-
- {record.songCount}{' '}
- {translate('resources.song.name', {
- smart_count: record.songCount,
- })}
- {' · '} {' '}
- {' · '}
-
+
{config.enableStarRating && (
@@ -208,6 +235,7 @@ const AlbumDetails = ({ record }) => {
/>
)}
+
{isDesktop && record['comment'] && }
diff --git a/ui/src/album/AlbumTableView.js b/ui/src/album/AlbumTableView.js
index f7446f615..7e346f0ec 100644
--- a/ui/src/album/AlbumTableView.js
+++ b/ui/src/album/AlbumTableView.js
@@ -1,5 +1,4 @@
import React, { useMemo } from 'react'
-import Paper from '@material-ui/core/Paper'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import inflection from 'inflection'
@@ -7,12 +6,15 @@ import TableCell from '@material-ui/core/TableCell'
import TableContainer from '@material-ui/core/TableContainer'
import TableRow from '@material-ui/core/TableRow'
import {
+ ArrayField,
BooleanField,
+ ChipField,
Datagrid,
DateField,
NumberField,
- Show,
+ SingleFieldList,
TextField,
+ useRecordContext,
useTranslate,
} from 'react-admin'
import { useMediaQuery } from '@material-ui/core'
@@ -60,43 +62,50 @@ const useStyles = makeStyles({
const AlbumDetails = (props) => {
const classes = useStyles()
const translate = useTranslate()
- const { record } = props
+ const record = useRecordContext(props)
const data = {
- albumArtist: ,
- genre: ,
- compilation: ,
- updatedAt: ,
- comment: ,
- }
- if (!record.comment) {
- delete data.comment
+ albumArtist: ,
+ genre: (
+
+
+
+
+
+ ),
+ compilation: ,
+ updatedAt: ,
+ comment: ,
}
+
+ const optionalFields = ['comment', 'genre']
+ optionalFields.forEach((field) => {
+ !record[field] && delete data[field]
+ })
+
return (
-
-
-
-
- {Object.keys(data).map((key) => {
- return (
-
-
- {translate(`resources.album.fields.${key}`, {
- _: inflection.humanize(inflection.underscore(key)),
- })}
- :
-
- {data[key]}
-
- )
- })}
-
-
-
-
+
+
+
+ {Object.keys(data).map((key) => {
+ return (
+
+
+ {translate(`resources.album.fields.${key}`, {
+ _: inflection.humanize(inflection.underscore(key)),
+ })}
+ :
+
+ {data[key]}
+
+ )
+ })}
+
+
+
)
}
diff --git a/ui/src/common/BitrateField.js b/ui/src/common/BitrateField.js
index d6ac2fd03..8b9552ef1 100644
--- a/ui/src/common/BitrateField.js
+++ b/ui/src/common/BitrateField.js
@@ -1,7 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
+import { useRecordContext } from 'react-admin'
-export const BitrateField = ({ record = {}, source }) => {
+export const BitrateField = ({ source, ...rest }) => {
+ const record = useRecordContext(rest)
return {`${record[source]} kbps`}
}
diff --git a/ui/src/common/DurationField.js b/ui/src/common/DurationField.js
index 0222faa88..730acdbee 100644
--- a/ui/src/common/DurationField.js
+++ b/ui/src/common/DurationField.js
@@ -1,8 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { formatDuration } from '../utils'
+import { useRecordContext } from 'react-admin'
-export const DurationField = ({ record = {}, source }) => {
+export const DurationField = ({ source, ...rest }) => {
+ const record = useRecordContext(rest)
try {
return {formatDuration(record[source])}
} catch (e) {
diff --git a/ui/src/common/LoveButton.js b/ui/src/common/LoveButton.js
index 7e38f7bef..7a1fa0207 100644
--- a/ui/src/common/LoveButton.js
+++ b/ui/src/common/LoveButton.js
@@ -5,6 +5,7 @@ import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'
import IconButton from '@material-ui/core/IconButton'
import { makeStyles } from '@material-ui/core/styles'
import { useToggleLove } from './useToggleLove'
+import { useRecordContext } from 'react-admin'
const useStyles = makeStyles({
love: {
@@ -16,7 +17,6 @@ const useStyles = makeStyles({
export const LoveButton = ({
resource,
- record,
color,
visible,
size,
@@ -25,6 +25,7 @@ export const LoveButton = ({
disabled,
...rest
}) => {
+ const record = useRecordContext(rest) || {}
const classes = useStyles({ color, visible, loved: record.starred })
const [toggleLove, loading] = useToggleLove(resource, record)
@@ -56,7 +57,7 @@ export const LoveButton = ({
LoveButton.propTypes = {
resource: PropTypes.string.isRequired,
- record: PropTypes.object.isRequired,
+ record: PropTypes.object,
visible: PropTypes.bool,
color: PropTypes.string,
size: PropTypes.string,
@@ -66,7 +67,6 @@ LoveButton.propTypes = {
LoveButton.defaultProps = {
addLabel: true,
- record: {},
visible: true,
size: 'small',
color: 'inherit',
diff --git a/ui/src/common/MultiLineTextField.js b/ui/src/common/MultiLineTextField.js
index 1053e7f4a..5148482dd 100644
--- a/ui/src/common/MultiLineTextField.js
+++ b/ui/src/common/MultiLineTextField.js
@@ -2,18 +2,19 @@ import React, { memo } from 'react'
import Typography from '@material-ui/core/Typography'
import sanitizeFieldRestProps from './sanitizeFieldRestProps'
import md5 from 'blueimp-md5'
+import { useRecordContext } from 'react-admin'
export const MultiLineTextField = memo(
({
className,
emptyText,
source,
- record,
firstLine,
maxLines,
addLabel,
...rest
}) => {
+ const record = useRecordContext(rest)
const value = record && record[source]
let lines = value ? value.split('\n') : []
if (maxLines || firstLine) {
@@ -46,7 +47,6 @@ export const MultiLineTextField = memo(
)
MultiLineTextField.defaultProps = {
- record: {},
addLabel: true,
firstLine: 0,
}
diff --git a/ui/src/common/RangeField.js b/ui/src/common/RangeField.js
index 7e9bbc930..7ea83330a 100644
--- a/ui/src/common/RangeField.js
+++ b/ui/src/common/RangeField.js
@@ -1,5 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
+import { useRecordContext } from 'react-admin'
export const formatRange = (record, source) => {
const nameCapitalized = source.charAt(0).toUpperCase() + source.slice(1)
@@ -15,7 +16,8 @@ export const formatRange = (record, source) => {
return range.join('-')
}
-export const RangeField = ({ className, record = {}, source }) => {
+export const RangeField = ({ className, source, ...rest }) => {
+ const record = useRecordContext(rest)
return {formatRange(record, source)}
}
diff --git a/ui/src/common/RatingField.js b/ui/src/common/RatingField.js
index b22c535b8..fe9171527 100644
--- a/ui/src/common/RatingField.js
+++ b/ui/src/common/RatingField.js
@@ -5,6 +5,7 @@ import { makeStyles } from '@material-ui/core/styles'
import StarBorderIcon from '@material-ui/icons/StarBorder'
import clsx from 'clsx'
import { useRating } from './useRating'
+import { useRecordContext } from 'react-admin'
const useStyles = makeStyles({
rating: {
@@ -21,14 +22,15 @@ const useStyles = makeStyles({
export const RatingField = ({
resource,
- record,
visible,
className,
size,
color,
+ ...rest
}) => {
+ const record = useRecordContext(rest) || {}
const [rate, rating] = useRating(resource, record)
- const classes = useStyles({ visible, rating: record.rating, color })
+ const classes = useStyles({ color, visible })
const stopPropagation = (e) => {
e.stopPropagation()
@@ -60,13 +62,12 @@ export const RatingField = ({
}
RatingField.propTypes = {
resource: PropTypes.string.isRequired,
- record: PropTypes.object.isRequired,
+ record: PropTypes.object,
visible: PropTypes.bool,
size: PropTypes.string,
}
RatingField.defaultProps = {
- record: {},
visible: true,
size: 'small',
color: 'inherit',
diff --git a/ui/src/common/SizeField.js b/ui/src/common/SizeField.js
index c5c02c5e6..64eaaf888 100644
--- a/ui/src/common/SizeField.js
+++ b/ui/src/common/SizeField.js
@@ -1,8 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { formatBytes } from '../utils'
+import { useRecordContext } from 'react-admin'
-export const SizeField = ({ record = {}, source }) => {
+export const SizeField = ({ source, ...rest }) => {
+ const record = useRecordContext(rest)
return {formatBytes(record[source])}
}
diff --git a/ui/src/common/SongDetails.js b/ui/src/common/SongDetails.js
index e95cf0264..05ad06883 100644
--- a/ui/src/common/SongDetails.js
+++ b/ui/src/common/SongDetails.js
@@ -1,5 +1,4 @@
import React from 'react'
-import Paper from '@material-ui/core/Paper'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import TableCell from '@material-ui/core/TableCell'
@@ -11,6 +10,10 @@ import {
TextField,
NumberField,
useTranslate,
+ ArrayField,
+ SingleFieldList,
+ ChipField,
+ useRecordContext,
} from 'react-admin'
import inflection from 'inflection'
import { BitrateField, SizeField } from './index'
@@ -26,35 +29,38 @@ const useStyles = makeStyles({
export const SongDetails = (props) => {
const classes = useStyles()
const translate = useTranslate()
- const { record } = props
+ const record = useRecordContext(props)
const data = {
- path: ,
- album: ,
- discSubtitle: ,
- albumArtist: ,
- genre: ,
- compilation: ,
- bitRate: ,
- size: ,
- updatedAt: ,
- playCount: ,
- bpm: ,
- comment: ,
- }
- if (!record.discSubtitle) {
- delete data.discSubtitle
- }
- if (!record.comment) {
- delete data.comment
- }
- if (!record.bpm) {
- delete data.bpm
+ path: ,
+ album: ,
+ discSubtitle: ,
+ albumArtist: ,
+ genre: (
+
+
+
+
+
+ ),
+ compilation: ,
+ bitRate: ,
+ size: ,
+ updatedAt: ,
+ playCount: ,
+ bpm: ,
+ comment: ,
}
+
+ const optionalFields = ['discSubtitle', 'comment', 'bpm', 'genre']
+ optionalFields.forEach((field) => {
+ !record[field] && delete data[field]
+ })
if (record.playCount > 0) {
data.playDate =
}
+
return (
-
+
{Object.keys(data).map((key) => {
diff --git a/ui/src/utils/index.js b/ui/src/utils/index.js
index da366f14e..ee1093300 100644
--- a/ui/src/utils/index.js
+++ b/ui/src/utils/index.js
@@ -1,5 +1,6 @@
export * from './baseUrl'
export * from './docsUrl'
export * from './formatters'
+export * from './intersperse'
export * from './notifications'
export * from './openInNewTab'
diff --git a/ui/src/utils/intersperse.js b/ui/src/utils/intersperse.js
new file mode 100644
index 000000000..01ff7f87c
--- /dev/null
+++ b/ui/src/utils/intersperse.js
@@ -0,0 +1,20 @@
+/* intersperse: Return an array with the separator interspersed between
+ * each element of the input array.
+ *
+ * > _([1,2,3]).intersperse(0)
+ * [1,0,2,0,3]
+ *
+ * From: https://stackoverflow.com/a/23619085
+ */
+export const intersperse = (arr, sep) => {
+ if (arr.length === 0) {
+ return []
+ }
+
+ return arr.slice(1).reduce(
+ function (xs, x, i) {
+ return xs.concat([sep, x])
+ },
+ [arr[0]]
+ )
+}