mirror of https://github.com/lidarr/Lidarr
New: Health check for import lists with missing root folders
Closes #1998
This commit is contained in:
parent
d400685cd1
commit
a7a5c7f700
|
@ -9,8 +9,10 @@ const ADD_NEW_KEY = 'addNew';
|
|||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.settings.rootFolders,
|
||||
(state, { value }) => value,
|
||||
(state, { includeMissingValue }) => includeMissingValue,
|
||||
(state, { includeNoChange }) => includeNoChange,
|
||||
(rootFolders, includeNoChange) => {
|
||||
(rootFolders, value, includeMissingValue, includeNoChange) => {
|
||||
const values = rootFolders.items.map((rootFolder) => {
|
||||
return {
|
||||
key: rootFolder.path,
|
||||
|
@ -25,7 +27,8 @@ function createMapStateToProps() {
|
|||
key: 'noChange',
|
||||
value: '',
|
||||
name: 'No Change',
|
||||
isDisabled: true
|
||||
isDisabled: true,
|
||||
isMissing: false
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,15 @@ function createMapStateToProps() {
|
|||
});
|
||||
}
|
||||
|
||||
if (includeMissingValue && !values.find((v) => v.key === value)) {
|
||||
values.push({
|
||||
key: value,
|
||||
value,
|
||||
isMissing: true,
|
||||
isDisabled: true
|
||||
});
|
||||
}
|
||||
|
||||
values.push({
|
||||
key: ADD_NEW_KEY,
|
||||
value: '',
|
||||
|
|
|
@ -18,3 +18,9 @@
|
|||
color: var(--darkGray);
|
||||
font-size: $smallFontSize;
|
||||
}
|
||||
|
||||
.isMissing {
|
||||
margin-left: 15px;
|
||||
color: var(--dangerColor);
|
||||
font-size: $smallFontSize;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'freeSpace': string;
|
||||
'isMissing': string;
|
||||
'isMobile': string;
|
||||
'optionText': string;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ function RootFolderSelectInputOption(props) {
|
|||
value,
|
||||
name,
|
||||
freeSpace,
|
||||
isMissing,
|
||||
isMobile,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
@ -29,11 +30,20 @@ function RootFolderSelectInputOption(props) {
|
|||
<div>{text}</div>
|
||||
|
||||
{
|
||||
freeSpace != null &&
|
||||
freeSpace == null ?
|
||||
null :
|
||||
<div className={styles.freeSpace}>
|
||||
{formatBytes(freeSpace)} Free
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isMissing ?
|
||||
<div className={styles.isMissing}>
|
||||
Missing
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</EnhancedSelectInputOption>
|
||||
);
|
||||
|
@ -43,6 +53,7 @@ RootFolderSelectInputOption.propTypes = {
|
|||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
freeSpace: PropTypes.number,
|
||||
isMissing: PropTypes.bool,
|
||||
isMobile: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ interface CssExports {
|
|||
'deleteButton': string;
|
||||
'hideMetadataProfile': string;
|
||||
'labelIcon': string;
|
||||
'message': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
|
|
|
@ -222,6 +222,7 @@ function EditImportListModalContent(props) {
|
|||
name="rootFolderPath"
|
||||
helpText={translate('RootFolderPathHelpText')}
|
||||
{...rootFolderPath}
|
||||
includeMissingValue={true}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.ImportLists;
|
||||
using NzbDrone.Core.Localization;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
|
||||
namespace NzbDrone.Core.HealthCheck.Checks
|
||||
{
|
||||
[CheckOn(typeof(ArtistsDeletedEvent))]
|
||||
[CheckOn(typeof(ArtistMovedEvent))]
|
||||
[CheckOn(typeof(AlbumImportedEvent), CheckOnCondition.FailedOnly)]
|
||||
[CheckOn(typeof(AlbumImportIncompleteEvent), CheckOnCondition.SuccessfulOnly)]
|
||||
public class ImportListRootFolderCheck : HealthCheckBase
|
||||
{
|
||||
private readonly IImportListFactory _importListFactory;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
|
||||
public ImportListRootFolderCheck(IImportListFactory importListFactory, IDiskProvider diskProvider, ILocalizationService localizationService)
|
||||
: base(localizationService)
|
||||
{
|
||||
_importListFactory = importListFactory;
|
||||
_diskProvider = diskProvider;
|
||||
}
|
||||
|
||||
public override HealthCheck Check()
|
||||
{
|
||||
var importLists = _importListFactory.All();
|
||||
var missingRootFolders = new Dictionary<string, List<ImportListDefinition>>();
|
||||
|
||||
foreach (var importList in importLists)
|
||||
{
|
||||
var rootFolderPath = importList.RootFolderPath;
|
||||
|
||||
if (missingRootFolders.ContainsKey(rootFolderPath))
|
||||
{
|
||||
missingRootFolders[rootFolderPath].Add(importList);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_diskProvider.FolderExists(rootFolderPath))
|
||||
{
|
||||
missingRootFolders.Add(rootFolderPath, new List<ImportListDefinition> { importList });
|
||||
}
|
||||
}
|
||||
|
||||
if (missingRootFolders.Any())
|
||||
{
|
||||
if (missingRootFolders.Count == 1)
|
||||
{
|
||||
var missingRootFolder = missingRootFolders.First();
|
||||
|
||||
return new HealthCheck(GetType(),
|
||||
HealthCheckResult.Error,
|
||||
string.Format(_localizationService.GetLocalizedString("ImportListRootFolderMissingRootHealthCheckMessage"), FormatRootFolder(missingRootFolder.Key, missingRootFolder.Value)),
|
||||
"#import-list-missing-root-folder");
|
||||
}
|
||||
|
||||
return new HealthCheck(GetType(),
|
||||
HealthCheckResult.Error,
|
||||
string.Format(_localizationService.GetLocalizedString("ImportListRootFolderMultipleMissingRootsHealthCheckMessage"), string.Join(" | ", missingRootFolders.Select(m => FormatRootFolder(m.Key, m.Value)))),
|
||||
"#import-list-missing-root-folder");
|
||||
}
|
||||
|
||||
return new HealthCheck(GetType());
|
||||
}
|
||||
|
||||
private string FormatRootFolder(string rootFolderPath, List<ImportListDefinition> importLists)
|
||||
{
|
||||
return $"{rootFolderPath} ({string.Join(", ", importLists.Select(l => l.Name))})";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue