feat: media page T1

This commit is contained in:
fsylvain committed 2026-10-01 01:36:35 +02:00
1 parent 67d456baf6
commit 008b0dfbb9
46 files changed
+5742 -204

No files matched your search

@@ -0,0 +1,98 @@
import { describe, expect, it } from 'vitest'
import type { MediaItem } from '@/composables/useMedia'
import { groupDuplicates, mergeArticleCount } from '../mediaDuplicates'
function copy(id: number, usedIn: number, createdAt: string, overrides: Partial<MediaItem> = {}) {
return {
id,
filename: `copy-${id}.jpg`,
url: `/media/copy-${id}.jpg`,
size: 2516582,
content_type: 'image/jpeg',
width: 3600,
height: 2400,
sha256: 'aa',
uploaded_by: 'Inès Duarte',
created_at: createdAt,
used_in: usedIn,
duplicate: true,
...overrides,
} satisfies MediaItem
}
describe('groupDuplicates', () => {
it.each([
[
'the most used copy',
[
copy(1, 4, '2026-06-14T12:00:00Z'),
copy(2, 3, '2026-09-02T12:00:00Z'),
copy(3, 2, '2026-08-30T12:00:00Z'),
],
1,
],
[
'the oldest copy at equal use',
[copy(1, 2, '2026-08-29T12:00:00Z'), copy(2, 2, '2026-08-21T12:00:00Z')],
2,
],
[
'the oldest unused copy',
[copy(1, 0, '2026-09-03T12:00:00Z'), copy(2, 0, '2026-09-01T12:00:00Z')],
2,
],
[
'the lowest id at equal use and date',
[copy(9, 1, '2026-09-03T12:00:00Z'), copy(4, 1, '2026-09-03T12:00:00Z')],
4,
],
])('suggests %s', (_name, copies, suggestedId) => {
const [group] = groupDuplicates(copies)
expect(group!.suggested.id).toBe(suggestedId)
expect(group!.copies[0]!.id).toBe(suggestedId)
})
it('groups by sha256, orders copies and puts the oldest suggested copy first', () => {
const groups = groupDuplicates([
copy(7, 2, '2026-08-29T12:00:00Z', { sha256: 'bb', size: 3250585 }),
copy(5, 3, '2026-09-02T12:00:00Z'),
copy(9, 1, '2026-08-21T12:00:00Z', { sha256: 'bb', size: 3250585 }),
copy(12, 4, '2026-06-14T12:00:00Z'),
copy(6, 2, '2026-08-30T12:00:00Z'),
])
expect(groups.map((group) => group.copies.map((item) => item.id))).toEqual([
[12, 5, 6],
[7, 9],
])
expect(groups.map((group) => group.header)).toEqual([
'3 identical images · 2.4 MB each · 3600 × 2400',
'2 identical images · 3.1 MB each · 3600 × 2400',
])
})
it('reads Vector for SVG groups and ignores single copies', () => {
const groups = groupDuplicates([
copy(1, 0, '2026-09-01T12:00:00Z', { width: null, height: null, size: 8192 }),
copy(2, 0, '2026-09-02T12:00:00Z', { width: null, height: null, size: 8192 }),
copy(3, 0, '2026-09-02T12:00:00Z', { sha256: 'zz' }),
])
expect(groups).toHaveLength(1)
expect(groups[0]!.header).toBe('2 identical images · 8 KB each · Vector')
})
})
describe('mergeArticleCount', () => {
it('sums the use of every copy except the kept one', () => {
const copies = [
copy(12, 4, '2026-06-14T12:00:00Z'),
copy(5, 3, '2026-09-02T12:00:00Z'),
copy(6, 2, '2026-08-30T12:00:00Z'),
]
expect(mergeArticleCount(copies, 12)).toBe(5)
expect(mergeArticleCount(copies, 6)).toBe(7)
})
})