build(ui): migrate from CRA/Jest to Vite/Vitest (#3311)
* feat: create vite project * feat: it's alive! * feat: `make dev` working! * feat: replace custom serviceWorker with vite plugin * test: replace Jest with Vitest * fix: run prettier * fix: skip eslint for now. * chore: remove ui.old folder * refactor: replace lodash.pick with simple destructuring * fix: eslint errors (wip) * fix: eslint errors (wip) * fix: display-name eslint errors (wip) * fix: no-console eslint errors (wip) * fix: react-refresh/only-export-components eslint errors (wip) * fix: react-refresh/only-export-components eslint errors (wip) * fix: react-refresh/only-export-components eslint errors (wip) * fix: react-refresh/only-export-components eslint errors (wip) * fix: build * fix: pwa manifest * refactor: pwa manifest * refactor: simplify PORT configuration * refactor: rename simple JS files * test: cover playlistUtils * fix: react-image-lightbox * feat(ui): add sourcemaps to help debug issues
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
AutocompleteInput,
|
||||
Filter,
|
||||
FunctionField,
|
||||
NumberField,
|
||||
ReferenceInput,
|
||||
SearchInput,
|
||||
TextField,
|
||||
useTranslate,
|
||||
} from 'react-admin'
|
||||
import { useMediaQuery } from '@material-ui/core'
|
||||
import FavoriteIcon from '@material-ui/icons/Favorite'
|
||||
import {
|
||||
DateField,
|
||||
DurationField,
|
||||
List,
|
||||
SongContextMenu,
|
||||
SongDatagrid,
|
||||
SongInfo,
|
||||
QuickFilter,
|
||||
SongTitleField,
|
||||
SongSimpleList,
|
||||
RatingField,
|
||||
useResourceRefresh,
|
||||
ArtistLinkField,
|
||||
} from '../common'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'
|
||||
import { setTrack } from '../actions'
|
||||
import { SongListActions } from './SongListActions'
|
||||
import { AlbumLinkField } from './AlbumLinkField'
|
||||
import { SongBulkActions, QualityInfo, useSelectedFields } from '../common'
|
||||
import config from '../config'
|
||||
import ExpandInfoDialog from '../dialogs/ExpandInfoDialog'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
contextHeader: {
|
||||
marginLeft: '3px',
|
||||
marginTop: '-2px',
|
||||
verticalAlign: 'text-top',
|
||||
},
|
||||
row: {
|
||||
'&:hover': {
|
||||
'& $contextMenu': {
|
||||
visibility: 'visible',
|
||||
},
|
||||
'& $ratingField': {
|
||||
visibility: 'visible',
|
||||
},
|
||||
},
|
||||
},
|
||||
contextMenu: {
|
||||
visibility: 'hidden',
|
||||
},
|
||||
ratingField: {
|
||||
visibility: 'hidden',
|
||||
},
|
||||
})
|
||||
|
||||
const SongFilter = (props) => {
|
||||
const translate = useTranslate()
|
||||
return (
|
||||
<Filter {...props} variant={'outlined'}>
|
||||
<SearchInput source="title" alwaysOn />
|
||||
<ReferenceInput
|
||||
label={translate('resources.song.fields.genre')}
|
||||
source="genre_id"
|
||||
reference="genre"
|
||||
perPage={0}
|
||||
sort={{ field: 'name', order: 'ASC' }}
|
||||
filterToQuery={(searchText) => ({ name: [searchText] })}
|
||||
>
|
||||
<AutocompleteInput emptyText="-- None --" />
|
||||
</ReferenceInput>
|
||||
{config.enableFavourites && (
|
||||
<QuickFilter
|
||||
source="starred"
|
||||
label={<FavoriteIcon fontSize={'small'} />}
|
||||
defaultValue={true}
|
||||
/>
|
||||
)}
|
||||
</Filter>
|
||||
)
|
||||
}
|
||||
|
||||
const SongList = (props) => {
|
||||
const classes = useStyles()
|
||||
const dispatch = useDispatch()
|
||||
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
|
||||
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
|
||||
useResourceRefresh('song')
|
||||
|
||||
const handleRowClick = (id, basePath, record) => {
|
||||
dispatch(setTrack(record))
|
||||
}
|
||||
|
||||
const toggleableFields = React.useMemo(() => {
|
||||
return {
|
||||
album: isDesktop && <AlbumLinkField source="album" sortByOrder={'ASC'} />,
|
||||
artist: <ArtistLinkField source="artist" />,
|
||||
albumArtist: <ArtistLinkField source="albumArtist" />,
|
||||
trackNumber: isDesktop && <NumberField source="trackNumber" />,
|
||||
playCount: isDesktop && (
|
||||
<NumberField source="playCount" sortByOrder={'DESC'} />
|
||||
),
|
||||
playDate: <DateField source="playDate" sortByOrder={'DESC'} showTime />,
|
||||
year: isDesktop && (
|
||||
<FunctionField
|
||||
source="year"
|
||||
render={(r) => r.year || ''}
|
||||
sortByOrder={'DESC'}
|
||||
/>
|
||||
),
|
||||
quality: isDesktop && <QualityInfo source="quality" sortable={false} />,
|
||||
channels: isDesktop && (
|
||||
<NumberField source="channels" sortByOrder={'ASC'} />
|
||||
),
|
||||
duration: <DurationField source="duration" />,
|
||||
rating: config.enableStarRating && (
|
||||
<RatingField
|
||||
source="rating"
|
||||
sortByOrder={'DESC'}
|
||||
resource={'song'}
|
||||
className={classes.ratingField}
|
||||
/>
|
||||
),
|
||||
bpm: isDesktop && <NumberField source="bpm" />,
|
||||
genre: <TextField source="genre" />,
|
||||
comment: <TextField source="comment" />,
|
||||
path: <TextField source="path" />,
|
||||
createdAt: <DateField source="createdAt" showTime />,
|
||||
}
|
||||
}, [isDesktop, classes.ratingField])
|
||||
|
||||
const columns = useSelectedFields({
|
||||
resource: 'song',
|
||||
columns: toggleableFields,
|
||||
defaultOff: [
|
||||
'channels',
|
||||
'bpm',
|
||||
'playDate',
|
||||
'albumArtist',
|
||||
'genre',
|
||||
'comment',
|
||||
'path',
|
||||
'createdAt',
|
||||
],
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<List
|
||||
{...props}
|
||||
sort={{ field: 'title', order: 'ASC' }}
|
||||
exporter={false}
|
||||
bulkActionButtons={<SongBulkActions />}
|
||||
actions={<SongListActions />}
|
||||
filters={<SongFilter />}
|
||||
perPage={isXsmall ? 50 : 15}
|
||||
>
|
||||
{isXsmall ? (
|
||||
<SongSimpleList />
|
||||
) : (
|
||||
<SongDatagrid
|
||||
rowClick={handleRowClick}
|
||||
contextAlwaysVisible={!isDesktop}
|
||||
classes={{ row: classes.row }}
|
||||
>
|
||||
<SongTitleField source="title" showTrackNumbers={false} />
|
||||
{columns}
|
||||
<SongContextMenu
|
||||
source={'starred_at'}
|
||||
sortByOrder={'DESC'}
|
||||
sortable={config.enableFavourites}
|
||||
className={classes.contextMenu}
|
||||
label={
|
||||
config.enableFavourites && (
|
||||
<FavoriteBorderIcon
|
||||
fontSize={'small'}
|
||||
className={classes.contextHeader}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</SongDatagrid>
|
||||
)}
|
||||
</List>
|
||||
<ExpandInfoDialog content={<SongInfo />} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SongList
|
||||
Reference in New Issue
Block a user