feat(uploads): match release groups with MusicBrainz and AcoustID
ci / module boundaries / boundaries (push) Successful in 10s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m30s
ci / api / api (push) Successful in 58s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m1s
ci / db / db (push) Failing after 25s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m36s
ci / ts / ts (packages + web) (push) Failing after 6m3s
ci / module boundaries / boundaries (push) Successful in 10s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m30s
ci / api / api (push) Successful in 58s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m1s
ci / db / db (push) Failing after 25s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m36s
ci / ts / ts (packages + web) (push) Failing after 6m3s
This commit is contained in:
1 parent
1e3a149aef
commit
39bf7d4b70
45 files changed
+4792
-417
No files matched your search
@@ -4,6 +4,7 @@ import { useId, useState } from 'react';
|
||||
import { needsFormatAttention } from './files';
|
||||
import { AudioPreview } from './AudioPreview';
|
||||
import { batchSummary } from './batchSummary';
|
||||
import { BatchRelease, type ReleaseGroup } from './BatchRelease';
|
||||
import { UploadStatusBadge, useReasonText, type UploadFile } from './common';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, cx, Icon } from '../../shared/ui/ui';
|
||||
@@ -28,6 +29,7 @@ export function BatchCard({
|
||||
}) {
|
||||
const { t, i18n } = useTranslation('admin');
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const [releaseGroups, setReleaseGroups] = useState<ReleaseGroup[]>([]);
|
||||
const contentId = useId();
|
||||
const first = files[0]!;
|
||||
const ids = files.map((f) => f.id);
|
||||
@@ -52,6 +54,7 @@ export function BatchCard({
|
||||
{t(first.batch_has_cover ? 'uploads.batch_cover_present' : 'uploads.batch_cover_absent')}
|
||||
</span>
|
||||
<span style={{ flex: 1 }} />
|
||||
{selectable && <BatchRelease files={files} onGroupsChange={setReleaseGroups} />}
|
||||
{selectable && (
|
||||
<Button variant="ghost" onClick={() => onEditBatch(first.batch_id)}>
|
||||
{t('uploads.edit_batch')}
|
||||
@@ -60,7 +63,17 @@ export function BatchCard({
|
||||
{first.batch_comment && <span className={u.comment}>«{first.batch_comment}»</span>}
|
||||
</div>
|
||||
<div id={contentId} hidden={collapsed}>
|
||||
{files.map((f) => (
|
||||
{(releaseGroups.length > 1 ? [
|
||||
...releaseGroups.map((group) => ({ group, rows: files.filter((f) => group.file_ids.includes(f.id)) })),
|
||||
{ group: undefined, rows: files.filter((f) => !releaseGroups.some((g) => g.file_ids.includes(f.id))) },
|
||||
] : [{ group: undefined, rows: files }]).filter((part) => part.rows.length > 0).map((part) => <div key={part.group?.id ?? 'other'}>
|
||||
{part.group && <div className={u.releaseHead}>
|
||||
{selectable && <input type="checkbox" aria-label={t('release_lookup.select_group', { album: part.group.album })} checked={part.rows.every((f) => selected.has(f.id))} onChange={(e) => onToggle(part.rows.map((f) => f.id), e.target.checked)} />}
|
||||
<strong>{part.group.artist} — {part.group.album}</strong>
|
||||
<span>{t('release_lookup.tracks_total', { total: part.group.file_ids.length })}</span>
|
||||
<span>{t(part.group.has_cover ? 'uploads.batch_cover_present' : 'uploads.batch_cover_absent')}</span>
|
||||
</div>}
|
||||
{part.rows.map((f) => (
|
||||
<QueueRow
|
||||
key={f.id}
|
||||
file={f}
|
||||
@@ -72,6 +85,7 @@ export function BatchCard({
|
||||
onRetry={() => onRetry(f.id)}
|
||||
/>
|
||||
))}
|
||||
</div>)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user