diff --git a/ui/src/album/AlbumSongs.js b/ui/src/album/AlbumSongs.js
index 1530934dc..b32f3ae9e 100644
--- a/ui/src/album/AlbumSongs.js
+++ b/ui/src/album/AlbumSongs.js
@@ -72,17 +72,16 @@ const useStyles = makeStyles(
const AlbumSongs = (props) => {
const classes = useStyles(props)
+ const { data, ids } = props
const dispatch = useDispatch()
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
- const { id: album_id, data, ids } = props
const version = useVersion()
return (
<>
diff --git a/ui/src/dataProvider/wrapperDataProvider.js b/ui/src/dataProvider/wrapperDataProvider.js
index 827ed1c85..7c83a099f 100644
--- a/ui/src/dataProvider/wrapperDataProvider.js
+++ b/ui/src/dataProvider/wrapperDataProvider.js
@@ -14,7 +14,6 @@ const mapResource = (resource, params) => {
let plsId = '0'
if (params.filter) {
plsId = params.filter.playlist_id
- delete params.filter.playlist_id
}
return [`playlist/${plsId}/tracks`, params]
diff --git a/ui/src/playlist/PlaylistShow.js b/ui/src/playlist/PlaylistShow.js
index e533816c5..676792934 100644
--- a/ui/src/playlist/PlaylistShow.js
+++ b/ui/src/playlist/PlaylistShow.js
@@ -1,43 +1,54 @@
import React from 'react'
-import { useSelector } from 'react-redux'
-import { useGetOne } from 'react-admin'
+import {
+ ReferenceManyField,
+ ShowContextProvider,
+ useShowContext,
+ useShowController,
+} from 'react-admin'
import PlaylistDetails from './PlaylistDetails'
-import { Title } from '../common'
import PlaylistSongs from './PlaylistSongs'
import PlaylistActions from './PlaylistActions'
-import PlaylistSongBulkActions from './PlaylistSongBulkActions'
-import { isReadOnly } from '../common/Writable'
-
-const PlaylistShow = (props) => {
- const viewVersion = useSelector((s) => s.admin.ui && s.admin.ui.viewVersion)
- const { data: record, error } = useGetOne('playlist', props.id, {
- v: viewVersion,
- })
-
- if (error) {
- return
ERROR: {error}
- }
+import { Title, isReadOnly } from '../common'
+const PlaylistShowLayout = (props) => {
+ const { loading, ...context } = useShowContext(props)
+ const { record } = context
return (
<>
-
-
}
- actions={
}
- filter={{ playlist_id: props.id }}
- resource={'playlistTrack'}
- exporter={false}
- perPage={0}
- pagination={null}
- bulkActionButtons={
-
- }
- />
+ {record &&
}
+ {record && (
+
+ }
+ actions={}
+ resource={'playlistTrack'}
+ exporter={false}
+ perPage={0}
+ pagination={null}
+ />
+
+ )}
>
)
}
+const PlaylistShow = (props) => {
+ const controllerProps = useShowController(props)
+ return (
+
+
+
+ )
+}
+
export default PlaylistShow
diff --git a/ui/src/playlist/PlaylistSongBulkActions.js b/ui/src/playlist/PlaylistSongBulkActions.js
index 391adbabe..8265554a1 100644
--- a/ui/src/playlist/PlaylistSongBulkActions.js
+++ b/ui/src/playlist/PlaylistSongBulkActions.js
@@ -1,17 +1,26 @@
import React, { Fragment, useEffect } from 'react'
-import { BulkDeleteButton, useUnselectAll } from 'react-admin'
+import {
+ BulkDeleteButton,
+ useUnselectAll,
+ ResourceContextProvider,
+} from 'react-admin'
import PropTypes from 'prop-types'
-const PlaylistSongBulkActions = ({ playlistId, ...rest }) => {
+// Replace original resource with "fake" one for removing tracks from playlist
+const PlaylistSongBulkActions = ({ playlistId, resource, ...rest }) => {
const unselectAll = useUnselectAll()
useEffect(() => {
unselectAll('playlistTrack')
// eslint-disable-next-line
}, [])
+
+ const mappedResource = `playlist/${playlistId}/tracks`
return (
-
-
-
+
+
+
+
+
)
}
diff --git a/ui/src/playlist/PlaylistSongs.js b/ui/src/playlist/PlaylistSongs.js
index 58154515f..b04968921 100644
--- a/ui/src/playlist/PlaylistSongs.js
+++ b/ui/src/playlist/PlaylistSongs.js
@@ -1,13 +1,13 @@
-import React from 'react'
+import React, { useCallback } from 'react'
import {
BulkActionsToolbar,
- DatagridLoading,
ListToolbar,
TextField,
- useListController,
useRefresh,
useDataProvider,
useNotify,
+ useVersion,
+ useListContext,
} from 'react-admin'
import classnames from 'classnames'
import { useDispatch } from 'react-redux'
@@ -24,6 +24,7 @@ import {
import AddToPlaylistDialog from '../dialogs/AddToPlaylistDialog'
import { AlbumLinkField } from '../song/AlbumLinkField'
import { playTracks } from '../actions'
+import PlaylistSongBulkActions from './PlaylistSongBulkActions'
const useStyles = makeStyles(
(theme) => ({
@@ -51,16 +52,23 @@ const useStyles = makeStyles(
flexWrap: 'wrap',
},
noResults: { padding: 20 },
+ toolbar: {
+ justifyContent: 'flex-start',
+ },
+ row: {
+ '&:hover': {
+ '& $contextMenu': {
+ visibility: 'visible',
+ },
+ },
+ },
+ contextMenu: {
+ visibility: 'hidden',
+ },
}),
{ name: 'RaList' }
)
-const useStylesListToolbar = makeStyles({
- toolbar: {
- justifyContent: 'flex-start',
- },
-})
-
const ReorderableList = ({ readOnly, children, ...rest }) => {
if (readOnly) {
return children
@@ -68,113 +76,96 @@ const ReorderableList = ({ readOnly, children, ...rest }) => {
return
{children}
}
-const PlaylistSongs = (props) => {
+const PlaylistSongs = ({ playlistId, readOnly, ...props }) => {
+ const { data, ids } = props
const classes = useStyles(props)
- const classesToolbar = useStylesListToolbar(props)
const dispatch = useDispatch()
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
- const controllerProps = useListController(props)
const dataProvider = useDataProvider()
const refresh = useRefresh()
const notify = useNotify()
- const { bulkActionButtons, expand, className, playlistId, readOnly } = props
- const { data, ids, version, total } = controllerProps
+ const version = useVersion()
- if (total === 0) {
- return null
- }
-
- const anySong = data[ids[0]]
- const showPlaceholder = !anySong || anySong.playlistId !== playlistId
- const hasBulkActions = props.bulkActionButtons !== false
-
- const reorder = (playlistId, id, newPos) => {
- dataProvider
- .update('playlistTrack', {
- id,
- data: { insert_before: newPos },
- filter: { playlist_id: playlistId },
- })
- .then(() => {
+ const onAddToPlaylist = useCallback(
+ (pls) => {
+ if (pls.id === playlistId) {
refresh()
- })
- .catch(() => {
- notify('ra.page.error', 'warning')
- })
- }
+ }
+ },
+ [playlistId, refresh]
+ )
- const onAddToPlaylist = (pls) => {
- if (pls.id === props.id) {
- refresh()
- }
- }
+ const reorder = useCallback(
+ (playlistId, id, newPos) => {
+ dataProvider
+ .update('playlistTrack', {
+ id,
+ data: { insert_before: newPos },
+ filter: { playlist_id: playlistId },
+ })
+ .then(() => {
+ refresh()
+ })
+ .catch(() => {
+ notify('ra.page.error', 'warning')
+ })
+ },
+ [dataProvider, notify, refresh]
+ )
- const handleDragEnd = (from, to) => {
- const toId = ids[to]
- const fromId = ids[from]
- reorder(playlistId, fromId, toId)
- }
+ const handleDragEnd = useCallback(
+ (from, to) => {
+ const toId = ids[to]
+ const fromId = ids[from]
+ reorder(playlistId, fromId, toId)
+ },
+ [playlistId, reorder, ids]
+ )
return (
<>
0,
+ [classes.bulkActionsDisplayed]: props.selectedIds.length > 0,
})}
key={version}
>
- {bulkActionButtons !== false && bulkActionButtons && (
-
- {bulkActionButtons}
-
- )}
- {showPlaceholder ? (
-
- ) : (
-
+
+
+
+ }
+ rowClick={(id) => dispatch(playTracks(data, ids, id))}
+ {...props}
+ hasBulkActions={true}
+ contextAlwaysVisible={!isDesktop}
+ classes={{ row: classes.row }}
>
- }
- rowClick={(id) => dispatch(playTracks(data, ids, id))}
- {...controllerProps}
- hasBulkActions={hasBulkActions}
- contextAlwaysVisible={!isDesktop}
- >
- {isDesktop && }
-
- {isDesktop && }
- {isDesktop && }
-
-
-
-
- )}
+ {isDesktop && }
+
+ {isDesktop && }
+ {isDesktop && }
+
+
+
+
@@ -182,4 +173,19 @@ const PlaylistSongs = (props) => {
)
}
-export default PlaylistSongs
+const SanitizedPlaylistSongs = (props) => {
+ const { loaded, loading, total, ...rest } = useListContext(props)
+ return (
+ <>
+ {loaded && (
+
+ )}
+ >
+ )
+}
+
+export default SanitizedPlaylistSongs