diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index 9ba4788c6..443cd41ec 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -30,7 +30,8 @@ func NewArtistRepository(ctx context.Context, o orm.Ormer) model.ArtistRepositor "name": "order_artist_name", } r.filterMappings = map[string]filterFunc{ - "name": fullTextFilter, + "name": fullTextFilter, + "starred": booleanFilter, } return r } @@ -40,7 +41,7 @@ func (r *artistRepository) selectArtist(options ...model.QueryOptions) SelectBui } func (r *artistRepository) CountAll(options ...model.QueryOptions) (int64, error) { - return r.count(Select(), options...) + return r.count(r.newSelectWithAnnotation("artist.id"), options...) } func (r *artistRepository) Exists(id string) (bool, error) { @@ -197,6 +198,21 @@ func (r *artistRepository) NewInstance() interface{} { return &model.Artist{} } -var _ model.ArtistRepository = (*artistRepository)(nil) +func (r artistRepository) Delete(id string) error { + return r.delete(Eq{"id": id}) +} + +func (r artistRepository) Save(entity interface{}) (string, error) { + mf := entity.(*model.Artist) + err := r.Put(mf) + return mf.ID, err +} + +func (r artistRepository) Update(entity interface{}, cols ...string) error { + mf := entity.(*model.Artist) + return r.Put(mf) +} + var _ model.ArtistRepository = (*artistRepository)(nil) var _ model.ResourceRepository = (*artistRepository)(nil) +var _ rest.Persistable = (*artistRepository)(nil) diff --git a/ui/src/artist/ArtistList.js b/ui/src/artist/ArtistList.js index 9329a371c..4f44e98b4 100644 --- a/ui/src/artist/ArtistList.js +++ b/ui/src/artist/ArtistList.js @@ -9,10 +9,12 @@ import { TextField, } from 'react-admin' import { useMediaQuery, withWidth } from '@material-ui/core' +import StarIcon from '@material-ui/icons/Star' import AddToPlaylistDialog from '../dialogs/AddToPlaylistDialog' import { ArtistContextMenu, List, + QuickFilter, SimpleList, useGetHandleArtistClick, } from '../common' @@ -20,6 +22,11 @@ import { const ArtistFilter = (props) => ( + } + defaultValue={true} + /> ) diff --git a/ui/src/common/ContextMenus.js b/ui/src/common/ContextMenus.js index e082c9b31..7089ec20f 100644 --- a/ui/src/common/ContextMenus.js +++ b/ui/src/common/ContextMenus.js @@ -6,8 +6,15 @@ import Menu from '@material-ui/core/Menu' import MenuItem from '@material-ui/core/MenuItem' import MoreVertIcon from '@material-ui/icons/MoreVert' import StarIcon from '@material-ui/icons/Star' +import StarBorderIcon from '@material-ui/icons/StarBorder' import { makeStyles } from '@material-ui/core/styles' -import { useDataProvider, useNotify, useTranslate } from 'react-admin' +import { + useDataProvider, + useNotify, + useRefresh, + useTranslate, + useUpdate, +} from 'react-admin' import { addTracks, playTracks, shuffleTracks } from '../audioplayer' import { openAddToPlaylist } from '../dialogs/dialogState' import subsonic from '../subsonic' @@ -21,16 +28,25 @@ const useStyles = makeStyles({ visibility: (props) => (props.visible ? 'visible' : 'hidden'), }, star: { - visibility: 'hidden', // TODO: Invisible for now + visibility: (props) => + props.visible || props.starred ? 'visible' : 'hidden', }, }) -const ContextMenu = ({ record, color, visible, songQueryParams }) => { - const classes = useStyles({ color, visible }) +const ContextMenu = ({ + resource, + showStar, + record, + color, + visible, + songQueryParams, +}) => { + const classes = useStyles({ color, visible, starred: record.starred }) const dataProvider = useDataProvider() const dispatch = useDispatch() const translate = useTranslate() const notify = useNotify() + const refresh = useRefresh() const [anchorEl, setAnchorEl] = useState(null) const options = { @@ -102,13 +118,46 @@ const ContextMenu = ({ record, color, visible, songQueryParams }) => { e.stopPropagation() } + const [toggleStarred, { loading: updating }] = useUpdate( + resource, + record.id, + { + ...record, + starred: !record.starred, + }, + { + undoable: false, + onFailure: (error) => { + console.log(error) + notify('ra.page.error', 'warning') + refresh() + }, + } + ) + + const handleToggleStar = (e) => { + toggleStarred() + e.stopPropagation() + } + const open = Boolean(anchorEl) return ( - - - + {showStar && ( + + {record.starred ? ( + + ) : ( + + )} + + )}