diff --git a/model/metadata/legacy_ids.go b/model/metadata/legacy_ids.go index 91ae44b89..25025ea19 100644 --- a/model/metadata/legacy_ids.go +++ b/model/metadata/legacy_ids.go @@ -51,20 +51,6 @@ func legacyMapAlbumName(md Metadata) string { // Keep the TaggedLikePicard logic for backwards compatibility func legacyReleaseDate(md Metadata) string { - // Start with defaults - date := md.Date(model.TagRecordingDate) - year := date.Year() - originalDate := md.Date(model.TagOriginalDate) - originalYear := originalDate.Year() - releaseDate := md.Date(model.TagReleaseDate) - releaseYear := releaseDate.Year() - - // MusicBrainz Picard writes the Release Date of an album to the Date tag, and leaves the Release Date tag empty - taggedLikePicard := (originalYear != 0) && - (releaseYear == 0) && - (year >= originalYear) - if taggedLikePicard { - return string(date) - } + _, _, releaseDate := md.mapDates() return string(releaseDate) } diff --git a/model/metadata/legacy_ids_test.go b/model/metadata/legacy_ids_test.go new file mode 100644 index 000000000..b6d096763 --- /dev/null +++ b/model/metadata/legacy_ids_test.go @@ -0,0 +1,30 @@ +package metadata + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("legacyReleaseDate", func() { + + DescribeTable("legacyReleaseDate", + func(recordingDate, originalDate, releaseDate, expected string) { + md := New("", Info{ + Tags: map[string][]string{ + "DATE": {recordingDate}, + "ORIGINALDATE": {originalDate}, + "RELEASEDATE": {releaseDate}, + }, + }) + + result := legacyReleaseDate(md) + Expect(result).To(Equal(expected)) + }, + Entry("regular mapping", "2020-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping", "2020-05-15", "2019-02-10", "", "2020-05-15"), + Entry("legacy mapping, originalYear < year", "2018-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, originalYear empty", "2020-05-15", "", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, releaseYear", "2020-05-15", "2019-02-10", "2021-01-01", "2021-01-01"), + Entry("legacy mapping, same dates", "2020-05-15", "2020-05-15", "", "2020-05-15"), + ) +}) diff --git a/model/metadata/map_mediafile.go b/model/metadata/map_mediafile.go index 47d2578ec..9a96ae922 100644 --- a/model/metadata/map_mediafile.go +++ b/model/metadata/map_mediafile.go @@ -1,6 +1,7 @@ package metadata import ( + "cmp" "encoding/json" "maps" "math" @@ -39,11 +40,9 @@ func (md Metadata) ToMediaFile(libID int, folderID string) model.MediaFile { mf.ExplicitStatus = md.mapExplicitStatusTag() // Dates - origDate := md.Date(model.TagOriginalDate) + date, origDate, relDate := md.mapDates() mf.OriginalYear, mf.OriginalDate = origDate.Year(), string(origDate) - relDate := md.Date(model.TagReleaseDate) mf.ReleaseYear, mf.ReleaseDate = relDate.Year(), string(relDate) - date := md.Date(model.TagRecordingDate) mf.Year, mf.Date = date.Year(), string(date) // MBIDs @@ -164,3 +163,22 @@ func (md Metadata) mapExplicitStatusTag() string { return "" } } + +func (md Metadata) mapDates() (date Date, originalDate Date, releaseDate Date) { + // Start with defaults + date = md.Date(model.TagRecordingDate) + originalDate = md.Date(model.TagOriginalDate) + releaseDate = md.Date(model.TagReleaseDate) + + // For some historic reason, taggers have been writing the Release Date of an album to the Date tag, + // and leave the Release Date tag empty. + legacyMappings := (originalDate != "") && + (releaseDate == "") && + (date >= originalDate) + if legacyMappings { + return originalDate, originalDate, date + } + // when there's no Date, first fall back to Original Date, then to Release Date. + date = cmp.Or(date, originalDate, releaseDate) + return date, originalDate, releaseDate +} diff --git a/model/metadata/map_mediafile_test.go b/model/metadata/map_mediafile_test.go index 7e11b1541..ddda39bc2 100644 --- a/model/metadata/map_mediafile_test.go +++ b/model/metadata/map_mediafile_test.go @@ -35,7 +35,7 @@ var _ = Describe("ToMediaFile", func() { } Describe("Dates", func() { - It("should parse the dates like Picard", func() { + It("should parse properly tagged dates ", func() { mf = toMediaFile(model.RawTags{ "ORIGINALDATE": {"1978-09-10"}, "DATE": {"1977-03-04"}, @@ -49,6 +49,32 @@ var _ = Describe("ToMediaFile", func() { Expect(mf.ReleaseYear).To(Equal(2002)) Expect(mf.ReleaseDate).To(Equal("2002-01-02")) }) + + It("should parse dates with only year", func() { + mf = toMediaFile(model.RawTags{ + "ORIGINALYEAR": {"1978"}, + "DATE": {"1977"}, + "RELEASEDATE": {"2002"}, + }) + + Expect(mf.Year).To(Equal(1977)) + Expect(mf.Date).To(Equal("1977")) + Expect(mf.OriginalYear).To(Equal(1978)) + Expect(mf.OriginalDate).To(Equal("1978")) + Expect(mf.ReleaseYear).To(Equal(2002)) + Expect(mf.ReleaseDate).To(Equal("2002")) + }) + + It("should parse dates tagged the legacy way (no release date)", func() { + mf = toMediaFile(model.RawTags{ + "DATE": {"2014"}, + "ORIGINALDATE": {"1966"}, + }) + + Expect(mf.Year).To(Equal(1966)) + Expect(mf.OriginalYear).To(Equal(1966)) + Expect(mf.ReleaseYear).To(Equal(2014)) + }) }) Describe("Lyrics", func() { diff --git a/model/metadata/metadata_test.go b/model/metadata/metadata_test.go index 5d9c4a3ed..d7473afa7 100644 --- a/model/metadata/metadata_test.go +++ b/model/metadata/metadata_test.go @@ -90,13 +90,14 @@ var _ = Describe("Metadata", func() { md = metadata.New(filePath, props) Expect(md.All()).To(SatisfyAll( - HaveLen(5), Not(HaveKey(unknownTag)), HaveKeyWithValue(model.TagTrackArtist, []string{"Artist Name", "Second Artist"}), HaveKeyWithValue(model.TagAlbum, []string{"Album Name"}), - HaveKeyWithValue(model.TagRecordingDate, []string{"2022-10-02", "2022"}), + HaveKeyWithValue(model.TagRecordingDate, []string{"2022-10-02"}), + HaveKeyWithValue(model.TagReleaseDate, []string{"2022"}), HaveKeyWithValue(model.TagGenre, []string{"Pop", "Rock"}), HaveKeyWithValue(model.TagTrackNumber, []string{"1/10"}), + HaveLen(6), )) }) diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 0f2a46dec..be2af3ee3 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -97,9 +97,10 @@ func NewAlbumRepository(ctx context.Context, db dbx.Builder) model.AlbumReposito r.tableName = "album" r.registerModel(&model.Album{}, albumFilters()) r.setSortMappings(map[string]string{ - "name": "order_album_name, order_album_artist_name", - "artist": "compilation, order_album_artist_name, order_album_name", - "album_artist": "compilation, order_album_artist_name, order_album_name", + "name": "order_album_name, order_album_artist_name", + "artist": "compilation, order_album_artist_name, order_album_name", + "album_artist": "compilation, order_album_artist_name, order_album_name", + // TODO Rename this to just year (or date) "max_year": "coalesce(nullif(original_date,''), cast(max_year as text)), release_date, name", "random": "random", "recently_added": recentlyAddedSort(), diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index d856391ff..59e7a775d 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -57,6 +57,7 @@ "genre": "Gênero", "compilation": "Coletânea", "year": "Ano", + "date": "Data de Lançamento", "updatedAt": "Últ. Atualização", "comment": "Comentário", "rating": "Classificação", diff --git a/resources/mappings.yaml b/resources/mappings.yaml index f4de96a74..66056fd57 100644 --- a/resources/mappings.yaml +++ b/resources/mappings.yaml @@ -118,10 +118,10 @@ main: aliases: [ tdor, originaldate, ----:com.apple.itunes:originaldate, wm/originalreleasetime, tory, originalyear, ----:com.apple.itunes:originalyear, wm/originalreleaseyear ] type: date recordingdate: - aliases: [ tdrc, date, icrd, ©day, wm/year, year ] + aliases: [ tdrc, date, recordingdate, icrd, record date ] type: date releasedate: - aliases: [ tdrl, releasedate ] + aliases: [ tdrl, releasedate, ©day, wm/year, year ] type: date catalognumber: aliases: [ txxx:catalognumber, catalognumber, ----:com.apple.itunes:catalognumber, wm/catalogno ] diff --git a/server/subsonic/filter/filters.go b/server/subsonic/filter/filters.go index 1b5416695..f8b42d312 100644 --- a/server/subsonic/filter/filters.go +++ b/server/subsonic/filter/filters.go @@ -62,13 +62,14 @@ func AlbumsByArtistID(artistId string) Options { } func AlbumsByYear(fromYear, toYear int) Options { - sortOption := "max_year, name" + orderOption := "" if fromYear > toYear { fromYear, toYear = toYear, fromYear - sortOption = "max_year desc, name" + orderOption = "desc" } return addDefaultFilters(Options{ - Sort: sortOption, + Sort: "max_year", + Order: orderOption, Filters: Or{ And{ GtOrEq{"min_year": fromYear}, @@ -118,7 +119,7 @@ func SongWithLyrics(artist, title string) Options { func ByGenre(genre string) Options { return addDefaultFilters(Options{ - Sort: "name asc", + Sort: "name", Filters: filterByGenre(genre), }) } diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 56b65f894..4faec158f 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -296,7 +296,7 @@ func childFromAlbum(ctx context.Context, al model.Album) responses.Child { child.Name = al.Name child.Album = al.Name child.Artist = al.AlbumArtist - child.Year = int32(al.MaxYear) + child.Year = int32(cmp.Or(al.MaxOriginalYear, al.MaxYear)) child.Genre = al.Genre child.CoverArt = al.CoverArtID().String() child.Created = &al.CreatedAt @@ -380,7 +380,7 @@ func buildAlbumID3(ctx context.Context, album model.Album) responses.AlbumID3 { dir.SongCount = int32(album.SongCount) dir.Duration = int32(album.Duration) dir.PlayCount = album.PlayCount - dir.Year = int32(album.MaxYear) + dir.Year = int32(cmp.Or(album.MaxOriginalYear, album.MaxYear)) dir.Genre = album.Genre if !album.CreatedAt.IsZero() { dir.Created = &album.CreatedAt diff --git a/ui/src/album/AlbumDatesField.jsx b/ui/src/album/AlbumDatesField.jsx new file mode 100644 index 000000000..e4cdeedce --- /dev/null +++ b/ui/src/album/AlbumDatesField.jsx @@ -0,0 +1,19 @@ +import { useRecordContext } from 'react-admin' +import { formatRange } from '../common/index.js' + +const originalYearSymbol = '♫' +const releaseYearSymbol = '○' + +export const AlbumDatesField = ({ className, ...rest }) => { + const record = useRecordContext(rest) + const releaseDate = record.releaseDate + const releaseYear = releaseDate?.toString().substring(0, 4) + const yearRange = + formatRange(record, 'originalYear') || record['maxYear']?.toString() + let label = yearRange + + if (releaseYear !== undefined && yearRange !== releaseYear) { + label = `${originalYearSymbol} ${yearRange} · ${releaseYearSymbol} ${releaseYear}` + } + return {label} +} diff --git a/ui/src/album/AlbumDetails.jsx b/ui/src/album/AlbumDetails.jsx index 690ae6604..f796f3b9d 100644 --- a/ui/src/album/AlbumDetails.jsx +++ b/ui/src/album/AlbumDetails.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react' +import { useCallback, useEffect, useState } from 'react' import { Card, CardContent, @@ -10,25 +10,25 @@ import { withWidth, } from '@material-ui/core' import { - useRecordContext, - useTranslate, ArrayField, - SingleFieldList, ChipField, Link, + SingleFieldList, + useRecordContext, + useTranslate, } from 'react-admin' import Lightbox from 'react-image-lightbox' import 'react-image-lightbox/style.css' import subsonic from '../subsonic' import { ArtistLinkField, + CollapsibleComment, DurationField, formatRange, - SizeField, LoveButton, RatingField, + SizeField, useAlbumsPerPage, - CollapsibleComment, } from '../common' import config from '../config' import { formatFullDate, intersperse } from '../utils' @@ -140,69 +140,55 @@ const GenreList = () => { ) } -const Details = (props) => { +export const Details = (props) => { const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const translate = useTranslate() const record = useRecordContext(props) + + // Create an array of detail elements let details = [] const addDetail = (obj) => { const id = details.length details.push({obj}) } - const originalYearRange = formatRange(record, 'originalYear') - const originalDate = record.originalDate - ? formatFullDate(record.originalDate) - : originalYearRange + // Calculate date related fields const yearRange = formatRange(record, 'year') const date = record.date ? formatFullDate(record.date) : yearRange - const releaseDate = record.releaseDate - ? formatFullDate(record.releaseDate) - : date - const showReleaseDate = date !== releaseDate && releaseDate.length > 3 - const showOriginalDate = - date !== originalDate && - originalDate !== releaseDate && - originalDate.length > 3 + const originalDate = record.originalDate + ? formatFullDate(record.originalDate) + : formatRange(record, 'originalYear') + const releaseDate = record?.releaseDate && formatFullDate(record.releaseDate) - showOriginalDate && - !isXsmall && + const dateToUse = originalDate || date + const isOriginalDate = originalDate && dateToUse !== date + const showDate = dateToUse && dateToUse !== releaseDate + + // Get label for the main date display + const getDateLabel = () => { + if (isXsmall) return '♫' + if (isOriginalDate) return translate('resources.album.fields.originalDate') + return null + } + + // Get label for release date display + const getReleaseDateLabel = () => { + if (!isXsmall) return translate('resources.album.fields.releaseDate') + if (showDate) return '○' + return null + } + + // Display dates with appropriate labels + if (showDate) { + addDetail(<>{[getDateLabel(), dateToUse].filter(Boolean).join(' ')}) + } + + if (releaseDate) { addDetail( - <> - {[translate('resources.album.fields.originalDate'), originalDate].join( - ' ', - )} - , + <>{[getReleaseDateLabel(), releaseDate].filter(Boolean).join(' ')}, ) - - yearRange && addDetail(<>{['♫', !isXsmall ? date : yearRange].join(' ')}) - - showReleaseDate && - addDetail( - <> - {(!isXsmall - ? [translate('resources.album.fields.releaseDate'), releaseDate] - : ['○', record.releaseDate.substring(0, 4)] - ).join(' ')} - , - ) - - const showReleases = record.releases > 1 - showReleases && - addDetail( - <> - {!isXsmall - ? [ - record.releases, - translate('resources.album.fields.releases', { - smart_count: record.releases, - }), - ].join(' ') - : ['(', record.releases, ')))'].join(' ')} - , - ) - + } addDetail( <> {record.songCount + @@ -215,6 +201,7 @@ const Details = (props) => { !isXsmall && addDetail() !isXsmall && addDetail() + // Return the details rendered with separators return <>{intersperse(details, ' · ')} } diff --git a/ui/src/album/AlbumDetails.test.jsx b/ui/src/album/AlbumDetails.test.jsx new file mode 100644 index 000000000..e03022677 --- /dev/null +++ b/ui/src/album/AlbumDetails.test.jsx @@ -0,0 +1,327 @@ +// ui/src/album/__tests__/AlbumDetails.test.jsx +import { describe, test, expect, beforeEach, afterEach } from 'vitest' +import { render } from '@testing-library/react' +import { RecordContextProvider } from 'react-admin' +import { useMediaQuery } from '@material-ui/core' +import { Details } from './AlbumDetails' + +// Mock useMediaQuery +vi.mock('@material-ui/core', async () => { + const actual = await import('@material-ui/core') + return { + ...actual, + useMediaQuery: vi.fn(), + } +}) + +describe('Details component', () => { + describe('Desktop view', () => { + beforeEach(() => { + // Set desktop view (isXsmall = false) + vi.mocked(useMediaQuery).mockReturnValue(false) + }) + + test('renders correctly with just year range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2020, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date and originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with releaseDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with all date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + }) + + describe('Mobile view', () => { + beforeEach(() => { + // Set mobile view (isXsmall = true) + vi.mocked(useMediaQuery).mockReturnValue(true) + }) + + afterEach(() => { + vi.clearAllMocks() + }) + + test('renders correctly with just year range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2020, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with date and originalDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with releaseDate', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with all date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + date: '2020-05-01', + originalDate: '2018-03-15', + releaseDate: '2020-06-15', + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with no date fields', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with year range (start and end years)', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + year: 2018, + yearEnd: 2020, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + + test('renders correctly with originalYear range', () => { + const record = { + id: '123', + name: 'Test Album', + songCount: 12, + duration: 3600, + size: 102400, + originalYear: 2015, + originalYearEnd: 2016, + } + + const { container } = render( + +
+ , + ) + + expect(container).toMatchSnapshot() + }) + }) +}) diff --git a/ui/src/album/AlbumGridView.jsx b/ui/src/album/AlbumGridView.jsx index efbfe6173..475519fca 100644 --- a/ui/src/album/AlbumGridView.jsx +++ b/ui/src/album/AlbumGridView.jsx @@ -13,14 +13,10 @@ import { linkToRecord, useListContext, Loading } from 'react-admin' import { withContentRect } from 'react-measure' import { useDrag } from 'react-dnd' import subsonic from '../subsonic' -import { - AlbumContextMenu, - PlayButton, - ArtistLinkField, - RangeDoubleField, -} from '../common' +import { AlbumContextMenu, PlayButton, ArtistLinkField } from '../common' import { DraggableTypes } from '../consts' import clsx from 'clsx' +import { AlbumDatesField } from './AlbumDatesField.jsx' const useStyles = makeStyles( (theme) => ({ @@ -187,16 +183,7 @@ const AlbumGridTile = ({ showArtist, record, basePath, ...props }) => { {showArtist ? ( ) : ( - + )} ) diff --git a/ui/src/album/AlbumInfo.jsx b/ui/src/album/AlbumInfo.jsx index d6d123895..453dbb167 100644 --- a/ui/src/album/AlbumInfo.jsx +++ b/ui/src/album/AlbumInfo.jsx @@ -20,6 +20,7 @@ import { ArtistLinkField, MultiLineTextField, ParticipantsInfo, + RangeField, } from '../common' const useStyles = makeStyles({ @@ -47,6 +48,20 @@ const AlbumInfo = (props) => { ), + date: + record?.maxYear && record.maxYear === record.minYear ? ( + + ) : ( + + ), + originalDate: + record?.maxOriginalYear && + record.maxOriginalYear === record.minOriginalYear ? ( + + ) : ( + + ), + releaseDate: , recordLabel: ( Desktop view > renders correctly with all date fields 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with date 1`] = ` +
+ + May 1, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with date and originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Desktop view > renders correctly with releaseDate 1`] = ` +
+ + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > Mobile view > renders correctly with all date fields 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + ○ Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with date 1`] = ` +
+ + ♫ May 1, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with date and originalDate 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with no date fields 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with originalDate 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with originalYear range 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with releaseDate 1`] = ` +
+ + Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > Mobile view > renders correctly with year range (start and end years) 1`] = ` +
+ + 12 resources.song.name + +
+`; + +exports[`Details component > renders correctly in mobile view 1`] = ` +
+ + ♫ Mar 15, 2018 + + · + + ○ Jun 15, 2020 + + · + + 12 resources.song.name + +
+`; + +exports[`Details component > renders correctly with all date fields 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with date 1`] = ` +
+ + May 1, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with date and originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with just year range 1`] = ` +
+ + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with originalDate 1`] = ` +
+ + resources.album.fields.originalDate Mar 15, 2018 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; + +exports[`Details component > renders correctly with releaseDate 1`] = ` +
+ + resources.album.fields.releaseDate Jun 15, 2020 + + · + + 12 resources.song.name + + · + + + 01:00:00 + + + · + + + 100 KB + + +
+`; diff --git a/ui/src/artist/ArtistShow.jsx b/ui/src/artist/ArtistShow.jsx index 2f3ff4299..b20fffeef 100644 --- a/ui/src/artist/ArtistShow.jsx +++ b/ui/src/artist/ArtistShow.jsx @@ -50,7 +50,7 @@ const ArtistDetails = (props) => { ) } -const AlbumShowLayout = (props) => { +const ArtistShowLayout = (props) => { const showContext = useShowContext(props) const record = useRecordContext() const { width } = props @@ -98,7 +98,7 @@ const ArtistShow = withWidth()((props) => { const controllerProps = useShowController(props) return ( - + ) }) diff --git a/ui/src/common/RangeDoubleField.jsx b/ui/src/common/RangeDoubleField.jsx deleted file mode 100644 index d388abeb7..000000000 --- a/ui/src/common/RangeDoubleField.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { useRecordContext } from 'react-admin' -import { formatRange } from '../common' - -export const RangeDoubleField = ({ - className, - source, - symbol1, - symbol2, - separator, - ...rest -}) => { - const record = useRecordContext(rest) - const yearRange = formatRange(record, source).toString() - const releases = [record.releases] - const releaseDate = [record.releaseDate] - const releaseYear = releaseDate.toString().substring(0, 4) - let subtitle = yearRange - - if (releases > 1) { - subtitle = [ - [yearRange && symbol1, yearRange].join(' '), - ['(', releases, ')))'].join(' '), - ].join(separator) - } - - if ( - yearRange !== releaseYear && - yearRange.length > 0 && - releaseYear.length > 0 - ) { - subtitle = [ - [yearRange && symbol1, yearRange].join(' '), - [symbol2, releaseYear].join(' '), - ].join(separator) - } - - return {subtitle} -} - -RangeDoubleField.propTypes = { - label: PropTypes.string, - record: PropTypes.object, - source: PropTypes.string.isRequired, -} - -RangeDoubleField.defaultProps = { - addLabel: true, -} diff --git a/ui/src/common/index.js b/ui/src/common/index.js index 91d153e29..1a43047c1 100644 --- a/ui/src/common/index.js +++ b/ui/src/common/index.js @@ -13,7 +13,6 @@ export * from './Pagination' export * from './PlayButton' export * from './QuickFilter' export * from './RangeField' -export * from './RangeDoubleField' export * from './ShuffleAllButton' export * from './SimpleList' export * from './SizeField' diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json index 678e42cd4..4183d0ccd 100644 --- a/ui/src/i18n/en.json +++ b/ui/src/i18n/en.json @@ -58,6 +58,7 @@ "genre": "Genre", "compilation": "Compilation", "year": "Year", + "date": "Recording Date", "originalDate": "Original", "releaseDate": "Released", "releases": "Release |||| Releases",