mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
feat(ui): add quick and full scan options for individual libraries
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
acae163b0f
commit
8cebf82590
@ -300,6 +300,8 @@
|
||||
},
|
||||
"actions": {
|
||||
"scan": "Scanear Biblioteca",
|
||||
"quickScan": "Scan Rápido",
|
||||
"fullScan": "Scan Completo",
|
||||
"manageUsers": "Gerenciar Acesso do Usuário",
|
||||
"viewDetails": "Ver Detalhes"
|
||||
},
|
||||
@ -308,6 +310,9 @@
|
||||
"updated": "Biblioteca atualizada com sucesso",
|
||||
"deleted": "Biblioteca excluída com sucesso",
|
||||
"scanStarted": "Scan da biblioteca iniciada",
|
||||
"quickScanStarted": "Scan rápido iniciado",
|
||||
"fullScanStarted": "Scan completo iniciado",
|
||||
"scanError": "Erro ao iniciar o scan. Verifique os logs",
|
||||
"scanCompleted": "Scan da biblioteca concluída"
|
||||
},
|
||||
"validation": {
|
||||
|
||||
@ -302,6 +302,8 @@
|
||||
},
|
||||
"actions": {
|
||||
"scan": "Scan Library",
|
||||
"quickScan": "Quick Scan",
|
||||
"fullScan": "Full Scan",
|
||||
"manageUsers": "Manage User Access",
|
||||
"viewDetails": "View Details"
|
||||
},
|
||||
@ -310,6 +312,9 @@
|
||||
"updated": "Library updated successfully",
|
||||
"deleted": "Library deleted successfully",
|
||||
"scanStarted": "Library scan started",
|
||||
"quickScanStarted": "Quick scan started",
|
||||
"fullScanStarted": "Full scan started",
|
||||
"scanError": "Error starting scan. Check logs",
|
||||
"scanCompleted": "Library scan completed"
|
||||
},
|
||||
"validation": {
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
} from 'react-admin'
|
||||
import { useMediaQuery } from '@material-ui/core'
|
||||
import { List, DateField, useResourceRefresh, SizeField } from '../common'
|
||||
import LibraryListBulkActions from './LibraryListBulkActions'
|
||||
|
||||
const LibraryFilter = (props) => (
|
||||
<Filter {...props} variant={'outlined'}>
|
||||
@ -26,7 +27,7 @@ const LibraryList = (props) => {
|
||||
{...props}
|
||||
sort={{ field: 'name', order: 'ASC' }}
|
||||
exporter={false}
|
||||
bulkActionButtons={false}
|
||||
bulkActionButtons={!isXsmall && <LibraryListBulkActions />}
|
||||
filters={<LibraryFilter />}
|
||||
>
|
||||
{isXsmall ? (
|
||||
|
||||
11
ui/src/library/LibraryListBulkActions.jsx
Normal file
11
ui/src/library/LibraryListBulkActions.jsx
Normal file
@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
import LibraryScanButton from './LibraryScanButton'
|
||||
|
||||
const LibraryListBulkActions = (props) => (
|
||||
<>
|
||||
<LibraryScanButton fullScan={false} {...props} />
|
||||
<LibraryScanButton fullScan={true} {...props} />
|
||||
</>
|
||||
)
|
||||
|
||||
export default LibraryListBulkActions
|
||||
77
ui/src/library/LibraryScanButton.jsx
Normal file
77
ui/src/library/LibraryScanButton.jsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React, { useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
Button,
|
||||
useNotify,
|
||||
useRefresh,
|
||||
useTranslate,
|
||||
useUnselectAll,
|
||||
} from 'react-admin'
|
||||
import { useSelector } from 'react-redux'
|
||||
import SyncIcon from '@material-ui/icons/Sync'
|
||||
import CachedIcon from '@material-ui/icons/Cached'
|
||||
import subsonic from '../subsonic'
|
||||
|
||||
const LibraryScanButton = ({ fullScan, selectedIds, className }) => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const notify = useNotify()
|
||||
const refresh = useRefresh()
|
||||
const translate = useTranslate()
|
||||
const unselectAll = useUnselectAll()
|
||||
const scanStatus = useSelector((state) => state.activity.scanStatus)
|
||||
|
||||
const handleClick = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
// Build scan options
|
||||
const options = { fullScan }
|
||||
|
||||
// If specific libraries are selected, scan only those
|
||||
// Format: "libraryID:" to scan entire library (no folder path specified)
|
||||
if (selectedIds && selectedIds.length > 0) {
|
||||
options.path = selectedIds.map((id) => `${id}:`)
|
||||
}
|
||||
|
||||
await subsonic.startScan(options)
|
||||
const notificationKey = fullScan
|
||||
? 'resources.library.notifications.fullScanStarted'
|
||||
: 'resources.library.notifications.quickScanStarted'
|
||||
notify(notificationKey, 'info')
|
||||
refresh()
|
||||
|
||||
// Unselect all items after successful scan
|
||||
unselectAll('library')
|
||||
} catch (error) {
|
||||
notify('resources.library.notifications.scanError', 'warning')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const isDisabled = loading || scanStatus.scanning
|
||||
|
||||
const label = fullScan
|
||||
? translate('resources.library.actions.fullScan')
|
||||
: translate('resources.library.actions.quickScan')
|
||||
|
||||
const icon = fullScan ? <CachedIcon /> : <SyncIcon />
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
disabled={isDisabled}
|
||||
label={label}
|
||||
className={className}
|
||||
>
|
||||
{icon}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
LibraryScanButton.propTypes = {
|
||||
fullScan: PropTypes.bool.isRequired,
|
||||
selectedIds: PropTypes.array,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
export default LibraryScanButton
|
||||
@ -23,7 +23,13 @@ const url = (command, id, options) => {
|
||||
delete options.ts
|
||||
}
|
||||
Object.keys(options).forEach((k) => {
|
||||
params.append(k, options[k])
|
||||
const value = options[k]
|
||||
// Handle array parameters by appending each value separately
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => params.append(k, v))
|
||||
} else {
|
||||
params.append(k, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
return `/rest/${command}?${params.toString()}`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user