Add rename show functionality: implement API endpoint for renaming shows, update Show model to support name changes, and enhance ShowMetadataCard UI for name input. Update translations for new UI elements to improve user experience.
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
clearMetadata,
|
||||
getMetadataProviders,
|
||||
refreshEpisodesMetadata,
|
||||
renameShow,
|
||||
searchMetadata,
|
||||
setShowOriginalName,
|
||||
setShowPoster,
|
||||
@@ -26,8 +27,8 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
const { t } = useTranslation()
|
||||
const [galleryOpen, setGalleryOpen] = useState(false)
|
||||
const [provider, setProvider] = useState('')
|
||||
const [name, setName] = useState(show.name)
|
||||
const [originalName, setOriginalName] = useState(show.originalName ?? '')
|
||||
const [query, setQuery] = useState(show.originalName || show.name)
|
||||
const [results, setResults] = useState<MetadataCandidate[]>([])
|
||||
const [searched, setSearched] = useState(false)
|
||||
const [description, setDescription] = useState(show.description ?? '')
|
||||
@@ -52,9 +53,11 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
})
|
||||
|
||||
const effectiveProvider = provider || providers?.[0] || ''
|
||||
// Метаданные ищем по оригинальному названию (иначе — по обычному).
|
||||
const searchTerm = originalName.trim() || name.trim()
|
||||
|
||||
const search = useMutation({
|
||||
mutationFn: () => searchMetadata(effectiveProvider, query.trim()),
|
||||
mutationFn: () => searchMetadata(effectiveProvider, searchTerm),
|
||||
onSuccess: (data) => {
|
||||
setResults(data)
|
||||
setSearched(true)
|
||||
@@ -76,10 +79,11 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
const save = useMutation({
|
||||
mutationFn: async () => {
|
||||
const yearNum = year.trim() ? Number(year) : null
|
||||
const nameChanged = originalName.trim() !== (show.originalName ?? '')
|
||||
const infoChanged =
|
||||
(description.trim() || null) !== (show.description ?? null) || yearNum !== (show.year ?? null)
|
||||
if (nameChanged) await setShowOriginalName(show.id, originalName.trim() || null)
|
||||
if (name.trim() && name.trim() !== show.name) await renameShow(show.id, name.trim())
|
||||
if (originalName.trim() !== (show.originalName ?? ''))
|
||||
await setShowOriginalName(show.id, originalName.trim() || null)
|
||||
if (infoChanged)
|
||||
await updateMetadata(show.id, { description: description.trim() || null, year: yearNum })
|
||||
},
|
||||
@@ -140,31 +144,29 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Поиск + ручная правка */}
|
||||
{/* Название + поиск + ручная правка */}
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-4">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.metadata.name')}</Label>
|
||||
<Input value={name} maxLength={256} onChange={(e) => setName(e.target.value)} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label>{t('admin.metadata.originalName')}</Label>
|
||||
<Input
|
||||
value={originalName}
|
||||
maxLength={256}
|
||||
placeholder={t('admin.metadata.originalNamePlaceholder')}
|
||||
onChange={(e) => setOriginalName(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setOriginalName(e.target.value)
|
||||
setSearched(false)
|
||||
}}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">{t('admin.metadata.originalNameHint')}</p>
|
||||
</div>
|
||||
|
||||
{providers && providers.length > 0 && (
|
||||
{providers && providers.length > 0 && (searched || results.length > 0) && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>{t('admin.metadata.searchLabel')}</Label>
|
||||
<Input
|
||||
value={query}
|
||||
onChange={(e) => {
|
||||
setQuery(e.target.value)
|
||||
setSearched(false)
|
||||
}}
|
||||
placeholder={t('admin.metadata.searchPlaceholder')}
|
||||
/>
|
||||
|
||||
{searched && results.length === 0 && (
|
||||
<p className="text-xs text-muted-foreground">{t('admin.metadata.nothingFound')}</p>
|
||||
)}
|
||||
@@ -241,14 +243,14 @@ export function ShowMetadataCard({ show, onChanged }: { show: ShowDto; onChanged
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={search.isPending || !query.trim()}
|
||||
disabled={search.isPending || !searchTerm}
|
||||
onClick={() => search.mutate()}
|
||||
>
|
||||
{t('admin.metadata.searchBtn')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button size="sm" disabled={save.isPending} onClick={() => save.mutate()}>
|
||||
<Button size="sm" disabled={save.isPending || !name.trim()} onClick={() => save.mutate()}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
{linked && (
|
||||
|
||||
@@ -24,6 +24,10 @@ export function createShow(body: {
|
||||
return apiRequest<CreatedIdResponse>('/admin/shows', { method: 'POST', body })
|
||||
}
|
||||
|
||||
export function renameShow(id: string, name: string) {
|
||||
return apiRequest<void>(`/admin/shows/${id}/name`, { method: 'PUT', body: { name } })
|
||||
}
|
||||
|
||||
export function setShowOriginalName(id: string, originalName: string | null) {
|
||||
return apiRequest<void>(`/admin/shows/${id}/original-name`, {
|
||||
method: 'PUT',
|
||||
|
||||
@@ -285,7 +285,7 @@ const resources = {
|
||||
title: 'Метаданные',
|
||||
pickFromGallery: 'Выбрать из галереи',
|
||||
pickPoster: 'Из галереи',
|
||||
searchLabel: 'Поиск метаданных',
|
||||
name: 'Название',
|
||||
originalName: 'Оригинальное название (eng)',
|
||||
originalNamePlaceholder: 'Например: Family Guy',
|
||||
originalNameHint: 'По нему ищутся метаданные; на экранах показывается обычное название.',
|
||||
@@ -591,7 +591,7 @@ const resources = {
|
||||
title: 'Metadata',
|
||||
pickFromGallery: 'Pick from gallery',
|
||||
pickPoster: 'From gallery',
|
||||
searchLabel: 'Metadata search',
|
||||
name: 'Name',
|
||||
originalName: 'Original name (eng)',
|
||||
originalNamePlaceholder: 'e.g. Family Guy',
|
||||
originalNameHint: 'Metadata is looked up by this; screens still show the regular name.',
|
||||
|
||||
Reference in New Issue
Block a user