diff --git a/frontend/src/Components/FileBrowser/FileBrowserModalContent.js b/frontend/src/Components/FileBrowser/FileBrowserModalContent.js index 39e0eb326..d1ddeab25 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserModalContent.js +++ b/frontend/src/Components/FileBrowser/FileBrowserModalContent.js @@ -143,22 +143,22 @@ class FileBrowserModalContent extends Component { { emptyParent && - + } { !emptyParent && parent && - + } { diff --git a/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js b/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js index 54ae097bb..7d4fa9b25 100644 --- a/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js +++ b/frontend/src/Components/FileBrowser/FileBrowserModalContentConnector.js @@ -48,14 +48,20 @@ class FileBrowserModalContentConnector extends Component { // Lifecycle componentDidMount() { - this.props.fetchPaths({ path: this.props.value }); + this.props.fetchPaths({ + path: this.props.value, + allowFoldersWithoutTrailingSlashes: true + }); } // // Listeners onFetchPaths = (path) => { - this.props.fetchPaths({ path }); + this.props.fetchPaths({ + path, + allowFoldersWithoutTrailingSlashes: true + }); } onClearPaths = () => { diff --git a/frontend/src/Store/Actions/pathActions.js b/frontend/src/Store/Actions/pathActions.js index ad1817cb0..129a9cb4d 100644 --- a/frontend/src/Store/Actions/pathActions.js +++ b/frontend/src/Store/Actions/pathActions.js @@ -44,15 +44,21 @@ export const actionHandlers = handleThunks({ [FETCH_PATHS]: function(getState, payload, dispatch) { dispatch(set({ section, isFetching: true })); + const { + path, + allowFoldersWithoutTrailingSlashes = false + } = payload; + const promise = $.ajax({ url: '/filesystem', data: { - path: payload.path + path, + allowFoldersWithoutTrailingSlashes } }); promise.done((data) => { - dispatch(updatePaths({ path: payload.path, ...data })); + dispatch(updatePaths({ path, ...data })); dispatch(set({ section, diff --git a/src/Lidarr.Api.V1/FileSystem/FileSystemModule.cs b/src/Lidarr.Api.V1/FileSystem/FileSystemModule.cs index 0ed90e37c..5fb003601 100644 --- a/src/Lidarr.Api.V1/FileSystem/FileSystemModule.cs +++ b/src/Lidarr.Api.V1/FileSystem/FileSystemModule.cs @@ -32,9 +32,9 @@ namespace Lidarr.Api.V1.FileSystem { var pathQuery = Request.Query.path; var includeFiles = Request.GetBooleanQueryParameter("includeFiles"); + var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes"); - - return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles).AsResponse(); + return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes).AsResponse(); } private Response GetEntityType() diff --git a/src/NzbDrone.Common.Test/DiskTests/DirectoryLookupServiceFixture.cs b/src/NzbDrone.Common.Test/DiskTests/DirectoryLookupServiceFixture.cs index 804666ea1..78aa99f7d 100644 --- a/src/NzbDrone.Common.Test/DiskTests/DirectoryLookupServiceFixture.cs +++ b/src/NzbDrone.Common.Test/DiskTests/DirectoryLookupServiceFixture.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using FluentAssertions; @@ -49,7 +49,7 @@ namespace NzbDrone.Common.Test.DiskTests .Setup(s => s.GetDirectoryInfos(It.IsAny())) .Returns(_folders); - Subject.LookupContents(root, false).Directories.Should().NotContain(Path.Combine(root, RECYCLING_BIN)); + Subject.LookupContents(root, false, false).Directories.Should().NotContain(Path.Combine(root, RECYCLING_BIN)); } [Test] @@ -62,7 +62,7 @@ namespace NzbDrone.Common.Test.DiskTests .Setup(s => s.GetDirectoryInfos(It.IsAny())) .Returns(_folders); - Subject.LookupContents(root, false).Directories.Should().NotContain(Path.Combine(root, SYSTEM_VOLUME_INFORMATION)); + Subject.LookupContents(root, false, false).Directories.Should().NotContain(Path.Combine(root, SYSTEM_VOLUME_INFORMATION)); } [Test] @@ -75,8 +75,8 @@ namespace NzbDrone.Common.Test.DiskTests .Setup(s => s.GetDirectoryInfos(It.IsAny())) .Returns(_folders); - var result = Subject.LookupContents(root, false); - + var result = Subject.LookupContents(root, false, false); + result.Directories.Should().HaveCount(_folders.Count - 3); result.Directories.Should().NotContain(f => f.Name == RECYCLING_BIN); diff --git a/src/NzbDrone.Common/Disk/FileSystemLookupService.cs b/src/NzbDrone.Common/Disk/FileSystemLookupService.cs index f58e7942c..dfef2578c 100644 --- a/src/NzbDrone.Common/Disk/FileSystemLookupService.cs +++ b/src/NzbDrone.Common/Disk/FileSystemLookupService.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Common.Disk { public interface IFileSystemLookupService { - FileSystemResult LookupContents(string query, bool includeFiles); + FileSystemResult LookupContents(string query, bool includeFiles, bool allowFoldersWithoutTrailingSlashes); } public class FileSystemLookupService : IFileSystemLookupService @@ -51,14 +51,13 @@ namespace NzbDrone.Common.Disk _diskProvider = diskProvider; } - public FileSystemResult LookupContents(string query, bool includeFiles) + public FileSystemResult LookupContents(string query, bool includeFiles, bool allowFoldersWithoutTrailingSlashes) { - var result = new FileSystemResult(); - if (query.IsNullOrWhiteSpace()) { if (OsInfo.IsWindows) { + var result = new FileSystemResult(); result.Directories = GetDrives(); return result; @@ -67,41 +66,23 @@ namespace NzbDrone.Common.Disk query = "/"; } + if ( + allowFoldersWithoutTrailingSlashes && + query.IsPathValid() && + _diskProvider.FolderExists(query)) + { + return GetResult(query, includeFiles); + } + var lastSeparatorIndex = query.LastIndexOf(Path.DirectorySeparatorChar); var path = query.Substring(0, lastSeparatorIndex + 1); if (lastSeparatorIndex != -1) { - try - { - result.Parent = GetParent(path); - result.Directories = GetDirectories(path); - - if (includeFiles) - { - result.Files = GetFiles(path); - } - } - - catch (DirectoryNotFoundException) - { - return new FileSystemResult { Parent = GetParent(path) }; - } - catch (ArgumentException) - { - return new FileSystemResult(); - } - catch (IOException) - { - return new FileSystemResult { Parent = GetParent(path) }; - } - catch (UnauthorizedAccessException) - { - return new FileSystemResult { Parent = GetParent(path) }; - } + return GetResult(path, includeFiles); } - return result; + return new FileSystemResult(); } private List GetDrives() @@ -117,6 +98,41 @@ namespace NzbDrone.Common.Disk .ToList(); } + private FileSystemResult GetResult(string path, bool includeFiles) + { + var result = new FileSystemResult(); + + try + { + result.Parent = GetParent(path); + result.Directories = GetDirectories(path); + + if (includeFiles) + { + result.Files = GetFiles(path); + } + } + + catch (DirectoryNotFoundException) + { + return new FileSystemResult { Parent = GetParent(path) }; + } + catch (ArgumentException) + { + return new FileSystemResult(); + } + catch (IOException) + { + return new FileSystemResult { Parent = GetParent(path) }; + } + catch (UnauthorizedAccessException) + { + return new FileSystemResult { Parent = GetParent(path) }; + } + + return result; + } + private List GetDirectories(string path) { var directories = _diskProvider.GetDirectoryInfos(path)