diff --git a/CLA.md b/CLA.md new file mode 100644 index 000000000..3198fdb1e --- /dev/null +++ b/CLA.md @@ -0,0 +1,68 @@ +# NzbDrone Individual Contributor License Agreement # + +Thank you for your interest in contributing to NzbDrone ("We" or "Us"). +This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please complete the form below. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us. + +## 1. Definitions ## + +"You" means the individual who Submits a Contribution to Us. +"Contribution" means any work of authorship that is Submitted by You to Us in which You own or assert ownership of the Copyright. If You do not own the Copyright in the entire work of authorship, please follow the instructions in . +"Copyright" means all rights protecting works of authorship owned or controlled by You, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You. +"Material" means the work of authorship which is made available by Us to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material. +"Submit" means any form of electronic, verbal, or written communication sent to Us or our representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." +"Submission Date" means the date on which You Submit a Contribution to Us. +"Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier. + +## 2. Grant of Rights ## + +### 2.1 Copyright License ### +(a) You retain ownership of the Copyright in Your Contribution and have the same rights to use or license the Contribution which You would have had without entering into the Agreement. +(b) To the maximum extent permitted by the relevant law, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the Copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3. + +### 2.2 Patent License ### +For patent claims including, without limitation, method, process, and apparatus claims which You own, control or have the right to grant, now or in the future, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3. + +### 2.3 Outbound License ### +As a condition on the grant of rights in Sections 2.1 and 2.2, We agree to license the Contribution only under the terms of the license or licenses which We are using on the Submission Date for the Material (including any rights to adopt any future version of a license if permitted). + +### 2.4 Moral Rights. ### +If moral rights apply to the Contribution, to the maximum extent permitted by law, You waive and agree not to assert such moral rights against Us or our successors in interest, or any of our licensees, either direct or indirect. + +### 2.5 Our Rights. ### +You acknowledge that We are not obligated to use Your Contribution as part of the Material and may decide to include any Contribution We consider appropriate. + +### 2.6 Reservation of Rights. ### +Any rights not expressly licensed under this section are expressly reserved by You. + +## 3. Agreement ## + +You confirm that: +(a) You have the legal authority to enter into this Agreement. +(b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2. +(c) The grant of rights under Section 2 does not violate any grant of rights which You have made to third parties, including Your employer. If You are an employee, You have had Your employer approve this Agreement or sign the Entity version of this document. If You are less than eighteen years old, please have Your parents or guardian sign the Agreement. +(d) You have followed the instructions in , if You do not own the Copyright in the entire work of authorship Submitted. + +## 4. Disclaimer ## + +EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. + +## 5. Consequential Damage Waiver ## + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. + +## 6. Miscellaneous ## + +### 6.1 ### +This Agreement will be governed by and construed in accordance with the laws of excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement. + +### 6.2 ### +This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings. + +### 6.3 ### +If You or We assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement. + +### 6.4 ### +The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety. + +### 6.5 ### +If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..465170559 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# How to Contribute # + +We're always looking for people to help make NzbDrone even better, there are a number of ways to contribute. To get started, sign the Contributor License Agreement. + +## Documentation ## +Setup guides, FAQ, the more information we have on the wiki the better. + +## Development ## + +### Tools required ### +- Visual Studio 2012 +- HTML/Javascript editor of choice (Sublime Text/Webstorm/etc) +- npm (node package manager) +- git + +### Getting started ### + +1. Fork NzbDrone +2. Clone (develop branch) +3. Run `npm install` +4. Run `grunt` - Used to compile the UI components and copy them (leave this window open) +5. Compile in Visual Studio + +### Contributing Code ### +- If you're adding a new, already requested feature, please move it to In Progress on [Trello](http://trello.nzbdrone.com "Trello") so work is not duplicated. +- Rebase from NzbDrone's develop branch, don't merge +- Make meaningful commits, or squash them +- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements +- Reach out to us on the forums or on IRC if you have any questions +- Add tests (unit/integration) +- Commit with *nix line endings for consistency (We checkout Windows and commit *nix) +- Try to stick to one feature per request to keep things clean and easy to understand +- Use 4 spaces instead of tabs, this is the default for VS 2012 and WebStorm (to my knowledge) + +### Pull Requesting ### +- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability +- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it + +If you have any questions about any of this, please let us know. \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index b7ce1cfac..bf0f95d25 100644 --- a/build.ps1 +++ b/build.ps1 @@ -4,6 +4,7 @@ $outputFolderMono = '.\_output_mono' $testPackageFolder = '.\_tests\' $testSearchPattern = '*.Test\bin\x86\Release' $sourceFolder = '.\src' +$updateFolder = $outputFolder + '\NzbDrone.Update' Function Build() { @@ -27,6 +28,9 @@ Function Build() AddJsonNet + Write-Host "Removing Mono.Posix.dll" + Remove-Item "$outputFolder\Mono.Posix.dll" + Write-Host "##teamcity[progressFinish 'Build']" } @@ -35,21 +39,18 @@ Function CleanFolder($path) Write-Host Removing XMLDoc files get-childitem $path -File -Filter *.xml -Recurse | foreach ($_) {remove-item $_.fullname} - get-childitem $path -File -Filter *.transform -Recurse | foreach ($_) {remove-item $_.fullname} - + get-childitem $path -File -Filter *.transform -Recurse | foreach ($_) {remove-item $_.fullname} - get-childitem $path -File -Filter *.dll.config -Recurse | foreach ($_) {remove-item $_.fullname} + get-childitem $path -File -Filter *.dll.config -Recurse | foreach ($_) {remove-item $_.fullname} Write-Host Removing FluentValidation.Resources files get-childitem $path -File -Filter FluentValidation.resources.dll -recurse | foreach ($_) {remove-item $_.fullname} - get-childitem $path -File -Filter app.config -Recurse | foreach ($_) {remove-item $_.fullname} - + get-childitem $path -File -Filter app.config -Recurse | foreach ($_) {remove-item $_.fullname} Write-Host Removing .less files get-childitem $path -File -Filter *.less -Recurse | foreach ($_) {remove-item $_.fullname} - Write-Host Removing NuGet Remove-Item -Recurse -Force "$path\NuGet" @@ -84,20 +85,23 @@ Function PackageMono() get-childitem $outputFolderMono -File -Filter *.pdb -Recurse | foreach ($_) {remove-item $_.fullname} Write-Host Removing Service helpers - get-childitem $outputFolderMono -File -Filter ServiceUninstall.* -Recurse | foreach ($_) {remove-item $_.fullname} - get-childitem $outputFolderMono -File -Filter ServiceInstall.* -Recurse | foreach ($_) {remove-item $_.fullname} + get-childitem $outputFolderMono -File -Filter ServiceUninstall.* -Recurse | foreach ($_) {remove-item $_.fullname} + get-childitem $outputFolderMono -File -Filter ServiceInstall.* -Recurse | foreach ($_) {remove-item $_.fullname} Write-Host Removing native windows binaries Sqlite, MediaInfo - get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname} - get-childitem $outputFolderMono -File -Filter MediaInfo.* -Recurse | foreach ($_) {remove-item $_.fullname} + get-childitem $outputFolderMono -File -Filter sqlite3.* -Recurse | foreach ($_) {remove-item $_.fullname} + get-childitem $outputFolderMono -File -Filter MediaInfo.* -Recurse | foreach ($_) {remove-item $_.fullname} Write-Host "Adding MediaInfoDotNet.dll.config (for dllmap)" Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" $outputFolderMono Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe - Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.exe*" -Recurse | foreach ($_) {remove-item $_.fullname} + Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.exe*" -Recurse | foreach ($_) {remove-item $_.fullname} - Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.Console.exe*" -Recurse | foreach ($_) { + Write-Host Removing NzbDrone.Windows + get-childitem $outputFolderMono -File -Filter NzbDrone.Windows.* -Recurse | foreach ($_) {remove-item $_.fullname} + + Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.Console.exe*" -Recurse | foreach ($_) { $newName = $_.fullname -Replace ".Console","" Rename-Item $_.fullname $newName @@ -108,12 +112,11 @@ Function PackageMono() Write-Host "##teamcity[progressFinish 'Creating Mono Package']" } - Function AddJsonNet() { - get-childitem $outputFolder -File -Filter Newtonsoft.Json.* -Recurse | foreach ($_) {remove-item $_.fullname} - Copy-Item .\src\packages\Newtonsoft.Json.5.*\lib\net35\*.dll -Destination $outputFolder - Copy-Item .\src\packages\Newtonsoft.Json.5.*\lib\net35\*.dll -Destination $outputFolder\NzbDrone.Update + get-childitem $outputFolder -File -Filter Newtonsoft.Json.* -Recurse | foreach ($_) {remove-item $_.fullname} + Copy-Item .\src\packages\Newtonsoft.Json.5.*\lib\net35\*.dll -Destination $outputFolder + Copy-Item .\src\packages\Newtonsoft.Json.5.*\lib\net35\*.dll -Destination $outputFolder\NzbDrone.Update } Function PackageTests() @@ -127,8 +130,7 @@ Function PackageTests() Remove-Item -Recurse -Force $testPackageFolder -ErrorAction Continue } - - Get-ChildItem -Recurse -Directory | Where-Object {$_.FullName -like $testSearchPattern} | foreach($_){ + Get-ChildItem -Recurse -Directory | Where-Object {$_.FullName -like $testSearchPattern} | foreach($_){ Copy-Item -Recurse ($_.FullName + "\*") $testPackageFolder -ErrorAction Ignore } @@ -149,7 +151,6 @@ Function PackageTests() Write-Host "##teamcity[progressFinish 'Creating Test Package']" } - Function RunGrunt() { Write-Host "##teamcity[progressStart 'Running Grunt']" @@ -174,7 +175,17 @@ Function CheckExitCode() } } +Function CleanupWindowsPackage() +{ + Write-Host Removing NzbDrone.Mono + get-childitem $outputFolder -File -Filter NzbDrone.Mono.* -Recurse | foreach ($_) {remove-item $_.fullname} + + Write-Host Adding NzbDrone.Windows to UpdatePackage + Copy-Item $outputFolder\* $updateFolder -Filter NzbDrone.Windows.* +} + Build RunGrunt PackageMono PackageTests +CleanupWindowsPackage diff --git a/src/Libraries/Mono.Posix.dll b/src/Libraries/Mono.Posix.dll new file mode 100644 index 000000000..8e219445f Binary files /dev/null and b/src/Libraries/Mono.Posix.dll differ diff --git a/src/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs b/src/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs index 849773ddb..3fbdac946 100644 --- a/src/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs +++ b/src/NzbDrone.Api.Test/DirectoryLookupServiceFixture.cs @@ -6,6 +6,7 @@ using Moq; using NUnit.Framework; using NzbDrone.Api.Directories; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Test.Common; namespace NzbDrone.Api.Test diff --git a/src/NzbDrone.Api/Blacklist/BlacklistModule.cs b/src/NzbDrone.Api/Blacklist/BlacklistModule.cs new file mode 100644 index 000000000..913810767 --- /dev/null +++ b/src/NzbDrone.Api/Blacklist/BlacklistModule.cs @@ -0,0 +1,42 @@ +using System; +using NzbDrone.Core.Blacklisting; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Api.Blacklist +{ + public class BlacklistModule : NzbDroneRestModule + { + private readonly IBlacklistService _blacklistService; + + public BlacklistModule(IBlacklistService blacklistService) + { + _blacklistService = blacklistService; + GetResourcePaged = GetBlacklist; + DeleteResource = Delete; + } + + private PagingResource GetBlacklist(PagingResource pagingResource) + { + var pagingSpec = new PagingSpec + { + Page = pagingResource.Page, + PageSize = pagingResource.PageSize, + SortKey = pagingResource.SortKey, + SortDirection = pagingResource.SortDirection + }; + + //This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue + if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase)) + { + pagingSpec.SortKey = "series.title"; + } + + return ApplyToPage(_blacklistService.Paged, pagingSpec); + } + + private void Delete(int id) + { + _blacklistService.Delete(id); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Api/Blacklist/BlacklistResource.cs b/src/NzbDrone.Api/Blacklist/BlacklistResource.cs new file mode 100644 index 000000000..f2c27f2c4 --- /dev/null +++ b/src/NzbDrone.Api/Blacklist/BlacklistResource.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using NzbDrone.Api.REST; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Api.Blacklist +{ + public class BlacklistResource : RestResource + { + public int SeriesId { get; set; } + public List EpisodeIds { get; set; } + public string SourceTitle { get; set; } + public QualityModel Quality { get; set; } + public DateTime Date { get; set; } + } +} diff --git a/src/NzbDrone.Api/Directories/DirectoryLookupService.cs b/src/NzbDrone.Api/Directories/DirectoryLookupService.cs index 38c6b38e4..6f372d0e9 100644 --- a/src/NzbDrone.Api/Directories/DirectoryLookupService.cs +++ b/src/NzbDrone.Api/Directories/DirectoryLookupService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using NzbDrone.Common; +using NzbDrone.Common.Disk; namespace NzbDrone.Api.Directories { diff --git a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs index 46af86380..501e0b6fc 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/IndexHtmlMapper.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using Nancy; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Configuration; diff --git a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs index f251fff97..9d293ee65 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs @@ -1,6 +1,7 @@ using System.IO; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Api.Frontend.Mappers diff --git a/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs index 3fe35324b..f6864b06a 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/MediaCoverMapper.cs @@ -1,6 +1,7 @@ using System.IO; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Api.Frontend.Mappers diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs index da9fac532..5dbd3b734 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapper.cs @@ -1,6 +1,7 @@ using System.IO; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Api.Frontend.Mappers diff --git a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs index 4cc42f49f..1dd542692 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/StaticResourceMapperBase.cs @@ -3,6 +3,7 @@ using NLog; using Nancy; using Nancy.Responses; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Api.Frontend.Mappers diff --git a/src/NzbDrone.Api/Logs/LogFileModule.cs b/src/NzbDrone.Api/Logs/LogFileModule.cs index 4fe48d21e..b896e6020 100644 --- a/src/NzbDrone.Api/Logs/LogFileModule.cs +++ b/src/NzbDrone.Api/Logs/LogFileModule.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Api.Logs diff --git a/src/NzbDrone.Api/Logs/LogModule.cs b/src/NzbDrone.Api/Logs/LogModule.cs index 59ea4975d..8684e3250 100644 --- a/src/NzbDrone.Api/Logs/LogModule.cs +++ b/src/NzbDrone.Api/Logs/LogModule.cs @@ -23,6 +23,31 @@ namespace NzbDrone.Api.Logs pageSpec.SortKey = "id"; } + if (pagingResource.FilterKey == "level") + { + switch (pagingResource.FilterValue) + { + case "Fatal": + pageSpec.FilterExpression = h => h.Level == "Fatal"; + break; + case "Error": + pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error"; + break; + case "Warn": + pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn"; + break; + case "Info": + pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info"; + break; + case "Debug": + pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug"; + break; + case "Trace": + pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace"; + break; + } + } + return ApplyToPage(_logService.Paged, pageSpec); } } diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index 00f5f96e3..0371bd9cb 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -82,6 +82,8 @@ + + diff --git a/src/NzbDrone.Api/PagingResource.cs b/src/NzbDrone.Api/PagingResource.cs index ab53c24cd..96eeb7c48 100644 --- a/src/NzbDrone.Api/PagingResource.cs +++ b/src/NzbDrone.Api/PagingResource.cs @@ -9,6 +9,8 @@ namespace NzbDrone.Api public int PageSize { get; set; } public string SortKey { get; set; } public SortDirection SortDirection { get; set; } + public string FilterKey { get; set; } + public string FilterValue { get; set; } public int TotalRecords { get; set; } public List Records { get; set; } } diff --git a/src/NzbDrone.Api/REST/RestModule.cs b/src/NzbDrone.Api/REST/RestModule.cs index 1efcf0b3a..49cd14fa9 100644 --- a/src/NzbDrone.Api/REST/RestModule.cs +++ b/src/NzbDrone.Api/REST/RestModule.cs @@ -241,6 +241,16 @@ namespace NzbDrone.Api.REST } } + if (Request.Query.FilterKey != null) + { + pagingResource.FilterKey = Request.Query.FilterKey.ToString(); + + if (Request.Query.FilterValue != null) + { + pagingResource.FilterValue = Request.Query.FilterValue.ToString(); + } + } + return pagingResource; } } diff --git a/src/NzbDrone.App.Test/ContainerFixture.cs b/src/NzbDrone.App.Test/ContainerFixture.cs index d542b9dee..7c9dcba5b 100644 --- a/src/NzbDrone.App.Test/ContainerFixture.cs +++ b/src/NzbDrone.App.Test/ContainerFixture.cs @@ -27,7 +27,7 @@ namespace NzbDrone.App.Test } [Test] - public void should_be_able_to_resolve_downlodclients() + public void should_be_able_to_resolve_downloadclients() { MainAppContainerBuilder.BuildContainer(args).Resolve>().Should().NotBeEmpty(); } diff --git a/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj b/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj index 274499d34..badd7903b 100644 --- a/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj +++ b/src/NzbDrone.App.Test/NzbDrone.Host.Test.csproj @@ -97,6 +97,10 @@ + + xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Mono.*" "$(TargetDir)" +xcopy /s /y "$(SolutionDir)\..\_output\NzbDrone.Windows.*" "$(TargetDir)" + + \ No newline at end of file diff --git a/src/NzbDrone.Mono.Test/Properties/AssemblyInfo.cs b/src/NzbDrone.Mono.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a2dbbc810 --- /dev/null +++ b/src/NzbDrone.Mono.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NzbDrone.Mono.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NzbDrone.Mono.Test")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("45299d3c-34ff-48ca-9093-de2f037c38ac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/NzbDrone.Mono.Test/packages.config b/src/NzbDrone.Mono.Test/packages.config new file mode 100644 index 000000000..5c3ca54dd --- /dev/null +++ b/src/NzbDrone.Mono.Test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/NzbDrone.Mono/DiskProvider.cs b/src/NzbDrone.Mono/DiskProvider.cs new file mode 100644 index 000000000..cfbaa98c4 --- /dev/null +++ b/src/NzbDrone.Mono/DiskProvider.cs @@ -0,0 +1,138 @@ +using System; +using System.IO; +using System.Linq; +using Mono.Unix.Native; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnsureThat; +using NzbDrone.Common.Instrumentation; + +namespace NzbDrone.Mono +{ + public class DiskProvider : DiskProviderBase + { + private static readonly Logger Logger = NzbDroneLogger.GetLogger(); + + public override long? GetAvailableSpace(string path) + { + Ensure.That(path, () => path).IsValidPath(); + + var root = GetPathRoot(path); + + if (!FolderExists(root)) + throw new DirectoryNotFoundException(root); + + try + { + return GetDriveInfoLinux(path).AvailableFreeSpace; + } + catch (InvalidOperationException e) + { + Logger.ErrorException("Couldn't get free space for " + path, e); + } + + return null; + } + + public override void InheritFolderPermissions(string filename) + { + Ensure.That(filename, () => filename).IsValidPath(); + + try + { + var fs = File.GetAccessControl(filename); + fs.SetAccessRuleProtection(false, false); + File.SetAccessControl(filename, fs); + } + catch (NotImplementedException) + { + } + } + + public override void SetPermissions(string path, string mask, string user, string group) + { + Logger.Trace("Setting permissions: {0} on {1}", mask, path); + + var filePermissions = NativeConvert.FromOctalPermissionString(mask); + + if (Syscall.chmod(path, filePermissions) < 0) + { + var error = Stdlib.GetLastError(); + + throw new LinuxPermissionsException("Error setting file permissions: " + error); + } + + if (String.IsNullOrWhiteSpace(user) || String.IsNullOrWhiteSpace(group)) + { + Logger.Trace("User or Group for chown not configured, skipping chown."); + return; + } + + uint userId; + uint groupId; + + if (!uint.TryParse(user, out userId)) + { + var u = Syscall.getpwnam(user); + + if (u == null) + { + throw new LinuxPermissionsException("Unknown user: {0}", user); + } + + userId = u.pw_uid; + } + + if (!uint.TryParse(group, out groupId)) + { + var g = Syscall.getgrnam(user); + + if (g == null) + { + throw new LinuxPermissionsException("Unknown group: {0}", group); + } + + groupId = g.gr_gid; + } + + if (Syscall.chown(path, userId, groupId) < 0) + { + var error = Stdlib.GetLastError(); + + throw new LinuxPermissionsException("Error setting file owner: " + error); + } + } + + public override long? GetTotalSize(string path) + { + Ensure.That(path, () => path).IsValidPath(); + + var root = GetPathRoot(path); + + if (!FolderExists(root)) + throw new DirectoryNotFoundException(root); + + try + { + return GetDriveInfoLinux(path).TotalSize; + } + catch (InvalidOperationException e) + { + Logger.ErrorException("Couldn't get total space for " + path, e); + } + + return null; + } + + private DriveInfo GetDriveInfoLinux(string path) + { + var drives = DriveInfo.GetDrives(); + + return + drives.Where(drive => + drive.IsReady && path.StartsWith(drive.Name, StringComparison.CurrentCultureIgnoreCase)) + .OrderByDescending(drive => drive.Name.Length) + .First(); + } + } +} diff --git a/src/NzbDrone.Mono/LinuxPermissionsException.cs b/src/NzbDrone.Mono/LinuxPermissionsException.cs new file mode 100644 index 000000000..4b3587c36 --- /dev/null +++ b/src/NzbDrone.Mono/LinuxPermissionsException.cs @@ -0,0 +1,15 @@ +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Mono +{ + public class LinuxPermissionsException : NzbDroneException + { + public LinuxPermissionsException(string message, params object[] args) : base(message, args) + { + } + + public LinuxPermissionsException(string message) : base(message) + { + } + } +} diff --git a/src/NzbDrone.Mono/NzbDrone.Mono.csproj b/src/NzbDrone.Mono/NzbDrone.Mono.csproj new file mode 100644 index 000000000..91d0efeb3 --- /dev/null +++ b/src/NzbDrone.Mono/NzbDrone.Mono.csproj @@ -0,0 +1,93 @@ + + + + + Debug + AnyCPU + {15AD7579-A314-4626-B556-663F51D97CD1} + Library + Properties + NzbDrone.Mono + NzbDrone.Mono + v4.0 + 512 + + ..\ + true + + + true + full + false + ..\..\_output\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + ..\..\_output\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + ..\..\_output\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + False + ..\Libraries\Mono.Posix.dll + + + False + ..\packages\NLog.2.1.0\lib\net40\NLog.dll + + + + + + + + + + + + + + + + + {f2be0fdf-6e47-4827-a420-dd4ef82407f8} + NzbDrone.Common + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Mono/Properties/AssemblyInfo.cs b/src/NzbDrone.Mono/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..6a7d1a9dc --- /dev/null +++ b/src/NzbDrone.Mono/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NzbDrone.Mono")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NzbDrone.Mono")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("01493ea5-494f-43bf-be18-8ae4d0708fc6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/NzbDrone.Mono/packages.config b/src/NzbDrone.Mono/packages.config new file mode 100644 index 000000000..d5e3be0f3 --- /dev/null +++ b/src/NzbDrone.Mono/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index 35f24ff92..2c7e4b4f7 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -3,12 +3,15 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.Practices.Unity; using Moq; using Moq.Language.Flow; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Test.Common.AutoMoq.Unity; [assembly: InternalsVisibleTo("AutoMoq.Tests")] @@ -132,6 +135,8 @@ namespace NzbDrone.Test.Common.AutoMoq this.container = container; container.RegisterInstance(this); + RegisterPlatformLibrary(container); + registeredMocks = new Dictionary(); AddTheAutoMockingContainerExtensionToTheContainer(container); } @@ -164,6 +169,23 @@ namespace NzbDrone.Test.Common.AutoMoq return typeof(T); } + private void RegisterPlatformLibrary(IUnityContainer container) + { + var assemblyName = "NzbDrone.Windows"; + + if (OsInfo.IsLinux) + { + assemblyName = "NzbDrone.Mono"; + } + + if (!File.Exists(assemblyName + ".dll")) + { + return; + } + + Assembly.Load(assemblyName); + } + #endregion } } \ No newline at end of file diff --git a/src/NzbDrone.Update.Test/InstallUpdateServiceFixture.cs b/src/NzbDrone.Update.Test/InstallUpdateServiceFixture.cs index b7a4515ee..2e240decd 100644 --- a/src/NzbDrone.Update.Test/InstallUpdateServiceFixture.cs +++ b/src/NzbDrone.Update.Test/InstallUpdateServiceFixture.cs @@ -3,6 +3,7 @@ using System.IO; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Test.Common; using NzbDrone.Update.UpdateEngine; diff --git a/src/NzbDrone.Update/UpdateContainerBuilder.cs b/src/NzbDrone.Update/UpdateContainerBuilder.cs index 5f99a618c..f9d59d69f 100644 --- a/src/NzbDrone.Update/UpdateContainerBuilder.cs +++ b/src/NzbDrone.Update/UpdateContainerBuilder.cs @@ -1,19 +1,38 @@ -using NzbDrone.Common.Composition; +using System; +using System.Collections.Generic; +using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Update { public class UpdateContainerBuilder : ContainerBuilderBase { - private UpdateContainerBuilder(IStartupContext startupContext) - : base(startupContext, "NzbDrone.Update", "NzbDrone.Common") + private UpdateContainerBuilder(IStartupContext startupContext, string[] assemblies) + : base(startupContext, assemblies) { } public static IContainer Build(IStartupContext startupContext) { - return new UpdateContainerBuilder(startupContext).Container; + var assemblies = new List + { + "NzbDrone.Update", + "NzbDrone.Common" + }; + + if (OsInfo.IsWindows) + { + assemblies.Add("NzbDrone.Windows"); + } + + else + { + assemblies.Add("NzbDrone.Mono"); + } + + return new UpdateContainerBuilder(startupContext, assemblies.ToArray()).Container; } } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/src/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs b/src/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs index 91552105c..3787b25d3 100644 --- a/src/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs +++ b/src/NzbDrone.Update/UpdateEngine/BackupAndRestore.cs @@ -1,5 +1,6 @@ using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Update.UpdateEngine diff --git a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs index 0323360cc..0e6001677 100644 --- a/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs +++ b/src/NzbDrone.Update/UpdateEngine/InstallUpdateService.cs @@ -2,6 +2,7 @@ using System; using System.IO; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Disk; using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Update.UpdateEngine diff --git a/src/NzbDrone.Windows.Test/DiskProviderTests/DiskProviderFixture.cs b/src/NzbDrone.Windows.Test/DiskProviderTests/DiskProviderFixture.cs new file mode 100644 index 000000000..68b2d1f0c --- /dev/null +++ b/src/NzbDrone.Windows.Test/DiskProviderTests/DiskProviderFixture.cs @@ -0,0 +1,14 @@ +using NUnit.Framework; +using NzbDrone.Common.Test.DiskProviderTests; + +namespace NzbDrone.Windows.Test.DiskProviderTests +{ + [TestFixture] + public class DiskProviderFixture : DiskProviderFixtureBase + { + public DiskProviderFixture() + { + WindowsOnly(); + } + } +} diff --git a/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs b/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs new file mode 100644 index 000000000..a642b49a9 --- /dev/null +++ b/src/NzbDrone.Windows.Test/DiskProviderTests/FreeSpaceFixture.cs @@ -0,0 +1,14 @@ +using NUnit.Framework; +using NzbDrone.Common.Test.DiskProviderTests; + +namespace NzbDrone.Windows.Test.DiskProviderTests +{ + [TestFixture] + public class FreeSpaceFixture : FreeSpaceFixtureBase + { + public FreeSpaceFixture() + { + WindowsOnly(); + } + } +} diff --git a/src/NzbDrone.Windows.Test/DiskProviderTests/IsParentFixture.cs b/src/NzbDrone.Windows.Test/DiskProviderTests/IsParentFixture.cs new file mode 100644 index 000000000..00b6aa4c2 --- /dev/null +++ b/src/NzbDrone.Windows.Test/DiskProviderTests/IsParentFixture.cs @@ -0,0 +1,14 @@ +using NUnit.Framework; +using NzbDrone.Common.Test.DiskProviderTests; + +namespace NzbDrone.Windows.Test.DiskProviderTests +{ + [TestFixture] + public class IsParentFixtureFixture : IsParentFixtureBase + { + public IsParentFixtureFixture() + { + WindowsOnly(); + } + } +} diff --git a/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj b/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj new file mode 100644 index 000000000..098c95b80 --- /dev/null +++ b/src/NzbDrone.Windows.Test/NzbDrone.Windows.Test.csproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA} + Library + Properties + NzbDrone.Windows.Test + NzbDrone.Windows.Test + v4.0 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + False + ..\packages\NUnit.2.6.2\lib\nunit.framework.dll + + + + + + + + + + + + + + + + + + {bec74619-ddbb-4fba-b517-d3e20afc9997} + NzbDrone.Common.Test + + + {f2be0fdf-6e47-4827-a420-dd4ef82407f8} + NzbDrone.Common + + + {caddfce0-7509-4430-8364-2074e1eefca2} + NzbDrone.Test.Common + + + {911284d3-f130-459e-836c-2430b6fbf21d} + NzbDrone.Windows + + + + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Windows.Test/Properties/AssemblyInfo.cs b/src/NzbDrone.Windows.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..238a3d68a --- /dev/null +++ b/src/NzbDrone.Windows.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NzbDrone.Windows.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NzbDrone.Windows.Test")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("372cb8dc-5cdf-4fe4-9e1d-725827889bc7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/NzbDrone.Windows.Test/packages.config b/src/NzbDrone.Windows.Test/packages.config new file mode 100644 index 000000000..5c3ca54dd --- /dev/null +++ b/src/NzbDrone.Windows.Test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/NzbDrone.Windows/DiskProvider.cs b/src/NzbDrone.Windows/DiskProvider.cs new file mode 100644 index 000000000..db6a02304 --- /dev/null +++ b/src/NzbDrone.Windows/DiskProvider.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnsureThat; +using NzbDrone.Common.Instrumentation; + +namespace NzbDrone.Windows +{ + public class DiskProvider : DiskProviderBase + { + private static readonly Logger Logger = NzbDroneLogger.GetLogger(); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, + out ulong lpFreeBytesAvailable, + out ulong lpTotalNumberOfBytes, + out ulong lpTotalNumberOfFreeBytes); + + public override long? GetAvailableSpace(string path) + { + Ensure.That(path, () => path).IsValidPath(); + + var root = GetPathRoot(path); + + if (!FolderExists(root)) + throw new DirectoryNotFoundException(root); + + return DriveFreeSpaceEx(root); + } + + public override void InheritFolderPermissions(string filename) + { + Ensure.That(filename, () => filename).IsValidPath(); + + var fs = File.GetAccessControl(filename); + fs.SetAccessRuleProtection(false, false); + File.SetAccessControl(filename, fs); + } + + public override void SetPermissions(string path, string mask, string user, string group) + { + + } + + public override long? GetTotalSize(string path) + { + Ensure.That(path, () => path).IsValidPath(); + + var root = GetPathRoot(path); + + if (!FolderExists(root)) + throw new DirectoryNotFoundException(root); + + return DriveTotalSizeEx(root); + } + + private static long DriveFreeSpaceEx(string folderName) + { + Ensure.That(folderName, () => folderName).IsValidPath(); + + if (!folderName.EndsWith("\\")) + { + folderName += '\\'; + } + + ulong free = 0; + ulong dummy1 = 0; + ulong dummy2 = 0; + + if (GetDiskFreeSpaceEx(folderName, out free, out dummy1, out dummy2)) + { + return (long)free; + } + + return 0; + } + + private static long DriveTotalSizeEx(string folderName) + { + Ensure.That(folderName, () => folderName).IsValidPath(); + + if (!folderName.EndsWith("\\")) + { + folderName += '\\'; + } + + ulong total = 0; + ulong dummy1 = 0; + ulong dummy2 = 0; + + if (GetDiskFreeSpaceEx(folderName, out dummy1, out total, out dummy2)) + { + return (long)total; + } + + return 0; + } + } +} diff --git a/src/NzbDrone.Windows/NzbDrone.Windows.csproj b/src/NzbDrone.Windows/NzbDrone.Windows.csproj new file mode 100644 index 000000000..607f09a4e --- /dev/null +++ b/src/NzbDrone.Windows/NzbDrone.Windows.csproj @@ -0,0 +1,86 @@ + + + + + Debug + AnyCPU + {911284D3-F130-459E-836C-2430B6FBF21D} + Library + Properties + NzbDrone.Windows + NzbDrone.Windows + v4.0 + 512 + ..\ + true + + + true + full + false + ..\..\_output\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + ..\..\_output\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + ..\..\_output\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + ..\packages\NLog.2.1.0\lib\net40\NLog.dll + + + + + + + + + + + + + + + + + + + {f2be0fdf-6e47-4827-a420-dd4ef82407f8} + NzbDrone.Common + + + + + + \ No newline at end of file diff --git a/src/NzbDrone.Windows/Properties/AssemblyInfo.cs b/src/NzbDrone.Windows/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8a24ac703 --- /dev/null +++ b/src/NzbDrone.Windows/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NzbDrone.Windows")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NzbDrone.Windows")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cea28fa9-43d0-4682-99f2-d364377adbdf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/NzbDrone.Windows/packages.config b/src/NzbDrone.Windows/packages.config new file mode 100644 index 000000000..d5e3be0f3 --- /dev/null +++ b/src/NzbDrone.Windows/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/NzbDrone.sln b/src/NzbDrone.sln index c6f82ef3f..6607c1c36 100644 --- a/src/NzbDrone.sln +++ b/src/NzbDrone.sln @@ -66,108 +66,316 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.SignalR.Ow EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{F6E3A728-AE77-4D02-BAC8-82FBC1402DDA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Mono", "NzbDrone.Mono\NzbDrone.Mono.csproj", "{15AD7579-A314-4626-B556-663F51D97CD1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Windows", "NzbDrone.Windows\NzbDrone.Windows.csproj", "{911284D3-F130-459E-836C-2430B6FBF21D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{0F0D4998-8F5D-4467-A909-BB192C4B3B4B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{4EACDBBC-BCD7-4765-A57B-3E08331E4749}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Windows.Test", "NzbDrone.Windows.Test\NzbDrone.Windows.Test.csproj", "{80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Mono.Test", "NzbDrone.Mono.Test\NzbDrone.Mono.Test.csproj", "{40D72824-7D02-4A77-9106-8FE0EEA2B997}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|Any CPU.ActiveCfg = Debug|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|Mixed Platforms.Build.0 = Debug|x86 {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|x86.ActiveCfg = Debug|x86 {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Debug|x86.Build.0 = Debug|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|Any CPU.ActiveCfg = Release|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|Mixed Platforms.Build.0 = Release|x86 {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|x86.ActiveCfg = Release|x86 {D12F7F2F-8A3C-415F-88FA-6DD061A84869}.Release|x86.Build.0 = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|Any CPU.ActiveCfg = Debug|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|Mixed Platforms.Build.0 = Debug|x86 {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|x86.ActiveCfg = Debug|x86 {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Debug|x86.Build.0 = Debug|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|Any CPU.ActiveCfg = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|Mixed Platforms.Build.0 = Release|x86 {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|x86.ActiveCfg = Release|x86 {FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}.Release|x86.Build.0 = Release|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|Any CPU.ActiveCfg = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|Mixed Platforms.Build.0 = Debug|x86 {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|x86.ActiveCfg = Debug|x86 {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Debug|x86.Build.0 = Debug|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|Any CPU.ActiveCfg = Release|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|Mixed Platforms.Build.0 = Release|x86 {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|x86.ActiveCfg = Release|x86 {193ADD3B-792B-4173-8E4C-5A3F8F0237F0}.Release|x86.Build.0 = Release|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|Mixed Platforms.Build.0 = Debug|x86 {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|x86.ActiveCfg = Debug|x86 {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Debug|x86.Build.0 = Debug|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|Any CPU.ActiveCfg = Release|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|Mixed Platforms.Build.0 = Release|x86 {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x86.ActiveCfg = Release|x86 {C0EA1A40-91AD-4EEB-BD16-2DDDEBD20AE5}.Release|x86.Build.0 = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Any CPU.ActiveCfg = Debug|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|Mixed Platforms.Build.0 = Debug|x86 {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.ActiveCfg = Debug|x86 {FAFB5948-A222-4CF6-AD14-026BE7564802}.Debug|x86.Build.0 = Debug|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Any CPU.ActiveCfg = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|Mixed Platforms.Build.0 = Release|x86 {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.ActiveCfg = Release|x86 {FAFB5948-A222-4CF6-AD14-026BE7564802}.Release|x86.Build.0 = Release|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|Any CPU.ActiveCfg = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|Mixed Platforms.Build.0 = Debug|x86 {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|x86.ActiveCfg = Debug|x86 {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Debug|x86.Build.0 = Debug|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|Any CPU.ActiveCfg = Release|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|Mixed Platforms.Build.0 = Release|x86 {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|x86.ActiveCfg = Release|x86 {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}.Release|x86.Build.0 = Release|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|Any CPU.ActiveCfg = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|Mixed Platforms.Build.0 = Debug|x86 {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|x86.ActiveCfg = Debug|x86 {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Debug|x86.Build.0 = Debug|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|Any CPU.ActiveCfg = Release|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|Mixed Platforms.Build.0 = Release|x86 {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|x86.ActiveCfg = Release|x86 {35388E8E-0CDB-4A84-AD16-E4B6EFDA5D97}.Release|x86.Build.0 = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|Mixed Platforms.Build.0 = Debug|x86 {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|x86.ActiveCfg = Debug|x86 {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Debug|x86.Build.0 = Debug|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|Any CPU.ActiveCfg = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|Mixed Platforms.Build.0 = Release|x86 {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|x86.ActiveCfg = Release|x86 {F2BE0FDF-6E47-4827-A420-DD4EF82407F8}.Release|x86.Build.0 = Release|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|Any CPU.ActiveCfg = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|Mixed Platforms.Build.0 = Debug|x86 {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|x86.ActiveCfg = Debug|x86 {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Debug|x86.Build.0 = Debug|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|Any CPU.ActiveCfg = Release|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|Mixed Platforms.Build.0 = Release|x86 {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|x86.ActiveCfg = Release|x86 {BEC74619-DDBB-4FBA-B517-D3E20AFC9997}.Release|x86.Build.0 = Release|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|Mixed Platforms.Build.0 = Debug|x86 {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|x86.ActiveCfg = Debug|x86 {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Debug|x86.Build.0 = Debug|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|Any CPU.ActiveCfg = Release|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|Mixed Platforms.Build.0 = Release|x86 {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|x86.ActiveCfg = Release|x86 {CADDFCE0-7509-4430-8364-2074E1EEFCA2}.Release|x86.Build.0 = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|Mixed Platforms.Build.0 = Debug|x86 {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.ActiveCfg = Debug|x86 {6BCE712F-846D-4846-9D1B-A66B858DA755}.Debug|x86.Build.0 = Debug|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Any CPU.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|Mixed Platforms.Build.0 = Release|x86 {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.ActiveCfg = Release|x86 {6BCE712F-846D-4846-9D1B-A66B858DA755}.Release|x86.Build.0 = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Any CPU.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|Mixed Platforms.Build.0 = Debug|x86 {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.ActiveCfg = Debug|x86 {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Debug|x86.Build.0 = Debug|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Any CPU.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|Mixed Platforms.Build.0 = Release|x86 {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.ActiveCfg = Release|x86 {700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}.Release|x86.Build.0 = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|Mixed Platforms.Build.0 = Debug|x86 {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|x86.ActiveCfg = Debug|x86 {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Debug|x86.Build.0 = Debug|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|Any CPU.ActiveCfg = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|Mixed Platforms.Build.0 = Release|x86 {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|x86.ActiveCfg = Release|x86 {FD286DF8-2D3A-4394-8AD5-443FADE55FB2}.Release|x86.Build.0 = Release|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|Any CPU.ActiveCfg = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|Mixed Platforms.Build.0 = Debug|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|x86.ActiveCfg = Debug|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Debug|x86.Build.0 = Debug|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|Any CPU.ActiveCfg = Release|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|Mixed Platforms.Build.0 = Release|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.ActiveCfg = Release|x86 {3DCA7B58-B8B3-49AC-9D9E-56F4A0460976}.Release|x86.Build.0 = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|Mixed Platforms.Build.0 = Debug|x86 {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.ActiveCfg = Debug|x86 {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Debug|x86.Build.0 = Debug|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|Any CPU.ActiveCfg = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|Mixed Platforms.Build.0 = Release|x86 {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.ActiveCfg = Release|x86 {D18A5DEB-5102-4775-A1AF-B75DAAA8907B}.Release|x86.Build.0 = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|Mixed Platforms.Build.0 = Debug|x86 {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|x86.ActiveCfg = Debug|x86 {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Debug|x86.Build.0 = Debug|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|Any CPU.ActiveCfg = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|Mixed Platforms.Build.0 = Release|x86 {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|x86.ActiveCfg = Release|x86 {F6FC6BE7-0847-4817-A1ED-223DC647C3D7}.Release|x86.Build.0 = Release|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|Any CPU.ActiveCfg = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|Mixed Platforms.Build.0 = Debug|x86 {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|x86.ActiveCfg = Debug|x86 {CBF6B8B0-A015-413A-8C86-01238BB45770}.Debug|x86.Build.0 = Debug|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|Any CPU.ActiveCfg = Release|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|Mixed Platforms.Build.0 = Release|x86 {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|x86.ActiveCfg = Release|x86 {CBF6B8B0-A015-413A-8C86-01238BB45770}.Release|x86.Build.0 = Release|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|Mixed Platforms.Build.0 = Debug|x86 {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|x86.ActiveCfg = Debug|x86 {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Debug|x86.Build.0 = Debug|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|Any CPU.ActiveCfg = Release|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|Mixed Platforms.Build.0 = Release|x86 {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|x86.ActiveCfg = Release|x86 {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB}.Release|x86.Build.0 = Release|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Debug|Any CPU.ActiveCfg = Debug|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Debug|Mixed Platforms.Build.0 = Debug|x86 {B1784698-592E-4132-BDFA-9817409E3A96}.Debug|x86.ActiveCfg = Debug|x86 {B1784698-592E-4132-BDFA-9817409E3A96}.Debug|x86.Build.0 = Debug|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Release|Any CPU.ActiveCfg = Release|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {B1784698-592E-4132-BDFA-9817409E3A96}.Release|Mixed Platforms.Build.0 = Release|x86 {B1784698-592E-4132-BDFA-9817409E3A96}.Release|x86.ActiveCfg = Release|x86 {B1784698-592E-4132-BDFA-9817409E3A96}.Release|x86.Build.0 = Release|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|Any CPU.ActiveCfg = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|Mixed Platforms.Build.0 = Debug|x86 {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|x86.ActiveCfg = Debug|x86 {95C11A9E-56ED-456A-8447-2C89C1139266}.Debug|x86.Build.0 = Debug|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|Any CPU.ActiveCfg = Release|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|Mixed Platforms.Build.0 = Release|x86 {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|x86.ActiveCfg = Release|x86 {95C11A9E-56ED-456A-8447-2C89C1139266}.Release|x86.Build.0 = Release|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|Any CPU.ActiveCfg = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|Mixed Platforms.Build.0 = Debug|x86 {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|x86.ActiveCfg = Debug|x86 {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Debug|x86.Build.0 = Debug|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|Any CPU.ActiveCfg = Release|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|Mixed Platforms.Build.0 = Release|x86 {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|x86.ActiveCfg = Release|x86 {7C2CC69F-5CA0-4E5C-85CB-983F9F6C3B36}.Release|x86.Build.0 = Release|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|Any CPU.ActiveCfg = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|Mixed Platforms.Build.0 = Debug|x86 {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|x86.ActiveCfg = Debug|x86 {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Debug|x86.Build.0 = Debug|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|Any CPU.ActiveCfg = Release|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|Mixed Platforms.Build.0 = Release|x86 {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|x86.ActiveCfg = Release|x86 {CC26800D-F67E-464B-88DE-8EB1A0C227A3}.Release|x86.Build.0 = Release|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|Mixed Platforms.Build.0 = Debug|x86 {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|x86.ActiveCfg = Debug|x86 {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Debug|x86.Build.0 = Debug|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Any CPU.ActiveCfg = Release|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|Mixed Platforms.Build.0 = Release|x86 {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|x86.ActiveCfg = Release|x86 {1B9A82C4-BCA1-4834-A33E-226F17BE070B}.Release|x86.Build.0 = Release|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Debug|Any CPU.ActiveCfg = Debug|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Debug|Mixed Platforms.Build.0 = Debug|x86 {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Debug|x86.ActiveCfg = Debug|x86 {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Debug|x86.Build.0 = Debug|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Release|Any CPU.ActiveCfg = Release|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Release|Mixed Platforms.Build.0 = Release|x86 {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Release|x86.ActiveCfg = Release|x86 {2B8C6DAD-4D85-41B1-83FD-248D9F347522}.Release|x86.Build.0 = Release|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|x86.ActiveCfg = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Debug|x86.Build.0 = Debug|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|Any CPU.Build.0 = Release|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|x86.ActiveCfg = Release|x86 + {15AD7579-A314-4626-B556-663F51D97CD1}.Release|x86.Build.0 = Release|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|x86.ActiveCfg = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Debug|x86.Build.0 = Debug|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|Any CPU.Build.0 = Release|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|x86.ActiveCfg = Release|x86 + {911284D3-F130-459E-836C-2430B6FBF21D}.Release|x86.Build.0 = Release|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|x86.ActiveCfg = Debug|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Debug|x86.Build.0 = Debug|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|Any CPU.Build.0 = Release|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|x86.ActiveCfg = Release|x86 + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA}.Release|x86.Build.0 = Release|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|x86.ActiveCfg = Debug|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Debug|x86.Build.0 = Debug|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|Any CPU.Build.0 = Release|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|x86.ActiveCfg = Release|x86 + {40D72824-7D02-4A77-9106-8FE0EEA2B997}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,6 +390,7 @@ Global {CBF6B8B0-A015-413A-8C86-01238BB45770} = {57A04B72-8088-4F75-A582-1158CF8291F7} {8CEFECD0-A6C2-498F-98B1-3FBE5820F9AB} = {57A04B72-8088-4F75-A582-1158CF8291F7} {CC26800D-F67E-464B-88DE-8EB1A0C227A3} = {57A04B72-8088-4F75-A582-1158CF8291F7} + {4EACDBBC-BCD7-4765-A57B-3E08331E4749} = {57A04B72-8088-4F75-A582-1158CF8291F7} {FAFB5948-A222-4CF6-AD14-026BE7564802} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} {CADDFCE0-7509-4430-8364-2074E1EEFCA2} = {47697CDB-27B6-4B05-B4F8-0CBE6F6EDF97} {6BCE712F-846D-4846-9D1B-A66B858DA755} = {F9E67978-5CD6-4A5F-827B-4249711C0B02} @@ -192,6 +401,10 @@ Global {1B9A82C4-BCA1-4834-A33E-226F17BE070B} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} {2B8C6DAD-4D85-41B1-83FD-248D9F347522} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} {F6FC6BE7-0847-4817-A1ED-223DC647C3D7} = {F6E3A728-AE77-4D02-BAC8-82FBC1402DDA} + {911284D3-F130-459E-836C-2430B6FBF21D} = {0F0D4998-8F5D-4467-A909-BB192C4B3B4B} + {15AD7579-A314-4626-B556-663F51D97CD1} = {0F0D4998-8F5D-4467-A909-BB192C4B3B4B} + {80B51429-7A0E-46D6-BEE3-C80DCB1C4EAA} = {4EACDBBC-BCD7-4765-A57B-3E08331E4749} + {40D72824-7D02-4A77-9106-8FE0EEA2B997} = {4EACDBBC-BCD7-4765-A57B-3E08331E4749} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35;packages\Unity.2.1.505.2\lib\NET35 diff --git a/src/NzbDrone.sln.DotSettings b/src/NzbDrone.sln.DotSettings index e67821bf5..fdd2a0b42 100644 --- a/src/NzbDrone.sln.DotSettings +++ b/src/NzbDrone.sln.DotSettings @@ -61,6 +61,7 @@ True 2 False + True True True True diff --git a/src/UI/Calendar/CalendarView.js b/src/UI/Calendar/CalendarView.js index 471c64ea1..c21e0d488 100644 --- a/src/UI/Calendar/CalendarView.js +++ b/src/UI/Calendar/CalendarView.js @@ -9,7 +9,8 @@ define( 'System/StatusModel', 'History/Queue/QueueCollection', 'Mixins/backbone.signalr.mixin', - 'fullcalendar' + 'fullcalendar', + 'jquery.easypiechart' ], function (vent, Marionette, moment, CalendarCollection, StatusModel, QueueCollection) { var _instance; @@ -18,6 +19,7 @@ define( initialize: function () { this.collection = new CalendarCollection().bindSignalR({ updateOnly: true }); this.listenTo(this.collection, 'change', this._reloadCalendarEvents); + this.listenTo(QueueCollection, 'sync', this._reloadCalendarEvents); }, render : function () { @@ -43,6 +45,20 @@ define( eventRender : function (event, element) { self.$(element).addClass(event.statusLevel); self.$(element).children('.fc-event-inner').addClass(event.statusLevel); + + if (event.progress > 0) { + self.$(element).find('.fc-event-time') + .after(''.format(event.progress)); + + self.$(element).find('.chart').easyPieChart({ + barColor : '#ffffff', + trackColor: false, + scaleColor: false, + lineWidth : 2, + size : 14, + animate : false + }); + } }, eventClick : function (event) { vent.trigger(vent.Commands.ShowEpisodeDetails, {episode: event.model}); @@ -85,6 +101,7 @@ define( end : end, allDay : false, statusLevel : _instance._getStatusLevel(model, end), + progress : _instance._getDownloadProgress(model), model : model }; @@ -107,7 +124,7 @@ define( statusLevel = 'success'; } - if (downloading) { + else if (downloading) { statusLevel = 'purple'; } @@ -129,6 +146,16 @@ define( _reloadCalendarEvents: function () { this.$el.fullCalendar('removeEvents'); this._setEventData(this.collection); + }, + + _getDownloadProgress: function (element) { + var downloading = QueueCollection.findEpisode(element.get('id')); + + if (!downloading) { + return 0; + } + + return 100 - (downloading.get('sizeleft') / downloading.get('size') * 100); } }); }); diff --git a/src/UI/Calendar/calendar.less b/src/UI/Calendar/calendar.less index 50c84e0b2..39a5e284a 100644 --- a/src/UI/Calendar/calendar.less +++ b/src/UI/Calendar/calendar.less @@ -2,6 +2,7 @@ @import "../Content/Bootstrap/variables"; @import "../Content/Bootstrap/buttons"; @import "../Shared/Styles/clickable"; +@import "../Content/variables"; .calendar { th, td { @@ -100,7 +101,7 @@ } .purple { - border-color : #7932ea; + border-color : @nzbdronePurple; } .episode-title { @@ -148,7 +149,12 @@ } .purple { - border-color : #7932ea; - background-color : #7932ea; + border-color : @nzbdronePurple; + background-color : @nzbdronePurple; + } + + .chart { + margin-top : 2px; + margin-right: 2px; } } diff --git a/src/UI/Cells/EpisodeStatusCell.js b/src/UI/Cells/EpisodeStatusCell.js index 8a7fc89ac..d8ab15259 100644 --- a/src/UI/Cells/EpisodeStatusCell.js +++ b/src/UI/Cells/EpisodeStatusCell.js @@ -57,7 +57,15 @@ define( var model = this.model; var downloading = QueueCollection.findEpisode(model.get('id')); - if (downloading || this.model.get('downloading')) { + if (downloading) { + var progress = 100 - (downloading.get('sizeleft') / downloading.get('size') * 100); + + this.$el.html('
'.format(progress.toFixed(1)) + + '
'.format(progress)); + return; + } + + else if (this.model.get('downloading')) { icon = 'icon-nd-downloading'; tooltip = 'Episode is downloading'; } diff --git a/src/UI/Cells/cells.less b/src/UI/Cells/cells.less index b2ba4d140..8869f0779 100644 --- a/src/UI/Cells/cells.less +++ b/src/UI/Cells/cells.less @@ -51,6 +51,12 @@ td.episode-status-cell, td.quality-cell { .badge { font-size: 9px; } + + .progress { + height : 10px; + margin-top : 5px; + margin-bottom : 0px; + } } .history-details-cell { diff --git a/src/UI/favicon.ico b/src/UI/Content/Images/favicon.ico similarity index 100% rename from src/UI/favicon.ico rename to src/UI/Content/Images/favicon.ico diff --git a/src/UI/Content/progress-bars.less b/src/UI/Content/progress-bars.less new file mode 100644 index 000000000..20b69c063 --- /dev/null +++ b/src/UI/Content/progress-bars.less @@ -0,0 +1,36 @@ +@import "Bootstrap/mixins"; +@import "Bootstrap/variables"; +@import "variables"; + +.progress.episode-progress { + width : 125px; + position : relative; + margin-bottom : 2px; + + .progressbar-back-text, .progressbar-front-text { + font-size : 11.844px; + font-weight : bold; + text-align : center; + cursor : default; + } + + .progressbar-back-text { + position : absolute; + width : 100%; + height : 100%; + } + + .progressbar-front-text { + display : block; + width : 125px; + } + + .bar { + position : absolute; + overflow : hidden; + } +} + +.progress-purple .bar, .progress .bar-purple { + #gradient > .vertical(@purple, @nzbdronePurple); +} diff --git a/src/UI/Content/theme.less b/src/UI/Content/theme.less index 4e72e020b..e5916eb0c 100644 --- a/src/UI/Content/theme.less +++ b/src/UI/Content/theme.less @@ -10,52 +10,46 @@ @import "checkbox-button"; @import "spinner"; @import "legend"; +@import "progress-bars"; @import "../Shared/Styles/clickable"; @import "../Shared/Styles/card"; @import "../Rename/rename"; -.progress.episode-progress { - width : 125px; - position : relative; - margin-bottom : 2px; +.toolbar { - .progressbar-back-text, .progressbar-front-text { - font-size : 11.844px; - font-weight : bold; - text-align : center; - cursor : default; + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; } - .progressbar-back-text { - position : absolute; - width : 100%; - height : 100%; - } + .page-toolbar { + margin-top : 10px; + margin-bottom : 30px; - .progressbar-front-text { - display : block; - width : 125px; - } + .toolbar-group { + display: inline-block; + } - .bar { - position : absolute; - overflow : hidden; + .sorting-buttons { + .sorting-title { + display: inline-block; + width: 110px; + } + } } } -.page-toolbar { - margin-top : 10px; +.toolbars { + margin-top : 5px; margin-bottom : 30px; - .toolbar-group { - display: inline-block; - } - - .sorting-buttons { - .sorting-title { - display: inline-block; - width: 110px; - } + .page-toolbar { + margin-top : 5px; + margin-bottom : 0px; } } diff --git a/src/UI/Content/variables.less b/src/UI/Content/variables.less index 8a29e0a50..0495a3c19 100644 --- a/src/UI/Content/variables.less +++ b/src/UI/Content/variables.less @@ -1 +1,2 @@ -@nzbdroneRed: #C4273C; +@nzbdroneRed: #c4273c; +@nzbdronePurple: #7932ea; \ No newline at end of file diff --git a/src/UI/Form/CheckboxTemplate.html b/src/UI/Form/CheckboxTemplate.html index 94c7dde4c..68a6fdb26 100644 --- a/src/UI/Form/CheckboxTemplate.html +++ b/src/UI/Form/CheckboxTemplate.html @@ -14,7 +14,7 @@ {{#if helpText}} - + {{/if}} diff --git a/src/UI/Form/FormHelpPartial.html b/src/UI/Form/FormHelpPartial.html index cdf295852..53a2a495b 100644 --- a/src/UI/Form/FormHelpPartial.html +++ b/src/UI/Form/FormHelpPartial.html @@ -1,6 +1,6 @@ {{#if helpText}} - + {{/if}} diff --git a/src/UI/Form/PasswordTemplate.html b/src/UI/Form/PasswordTemplate.html index 9f8c4a9a0..c03abbaed 100644 --- a/src/UI/Form/PasswordTemplate.html +++ b/src/UI/Form/PasswordTemplate.html @@ -5,7 +5,7 @@ {{#if helpText}} - + {{/if}} diff --git a/src/UI/Form/SelectTemplate.html b/src/UI/Form/SelectTemplate.html index 62feb61af..89e5065ce 100644 --- a/src/UI/Form/SelectTemplate.html +++ b/src/UI/Form/SelectTemplate.html @@ -9,7 +9,7 @@ {{#if helpText}} - + {{/if}} diff --git a/src/UI/Handlebars/Helpers/System.js b/src/UI/Handlebars/Helpers/System.js index f5517db84..13cead2f7 100644 --- a/src/UI/Handlebars/Helpers/System.js +++ b/src/UI/Handlebars/Helpers/System.js @@ -19,7 +19,7 @@ define( if (StatusModel.get('isLinux')) { return options.fn(this); - } + } return options.inverse(this); }); diff --git a/src/UI/History/Blacklist/BlacklistActionsCell.js b/src/UI/History/Blacklist/BlacklistActionsCell.js new file mode 100644 index 000000000..3f6e9a766 --- /dev/null +++ b/src/UI/History/Blacklist/BlacklistActionsCell.js @@ -0,0 +1,26 @@ +'use strict'; + +define( + [ + 'Cells/NzbDroneCell' + ], function (NzbDroneCell) { + return NzbDroneCell.extend({ + + className: 'blacklist-controls-cell', + + events: { + 'click': '_delete' + }, + + render: function () { + this.$el.empty(); + this.$el.html(''); + + return this; + }, + + _delete: function () { + this.model.destroy(); + } + }); + }); diff --git a/src/UI/History/Blacklist/BlacklistCollection.js b/src/UI/History/Blacklist/BlacklistCollection.js new file mode 100644 index 000000000..3dcdb7cab --- /dev/null +++ b/src/UI/History/Blacklist/BlacklistCollection.js @@ -0,0 +1,44 @@ +'use strict'; +define( + [ + 'History/Blacklist/BlacklistModel', + 'backbone.pageable', + 'Mixins/AsPersistedStateCollection' + ], function (BlacklistModel, PageableCollection, AsPersistedStateCollection) { + var collection = PageableCollection.extend({ + url : window.NzbDrone.ApiRoot + '/blacklist', + model: BlacklistModel, + + state: { + pageSize: 15, + sortKey : 'date', + order : 1 + }, + + queryParams: { + totalPages : null, + totalRecords: null, + pageSize : 'pageSize', + sortKey : 'sortKey', + order : 'sortDir', + directions : { + '-1': 'asc', + '1' : 'desc' + } + }, + + parseState: function (resp) { + return { totalRecords: resp.totalRecords }; + }, + + parseRecords: function (resp) { + if (resp) { + return resp.records; + } + + return resp; + } + }); + + return AsPersistedStateCollection.apply(collection); + }); diff --git a/src/UI/History/Blacklist/BlacklistLayout.js b/src/UI/History/Blacklist/BlacklistLayout.js new file mode 100644 index 000000000..8a6a74487 --- /dev/null +++ b/src/UI/History/Blacklist/BlacklistLayout.js @@ -0,0 +1,132 @@ +'use strict'; +define( + [ + 'vent', + 'marionette', + 'backgrid', + 'History/Blacklist/BlacklistCollection', + 'Cells/SeriesTitleCell', + 'Cells/QualityCell', + 'Cells/RelativeDateCell', + 'History/Blacklist/BlacklistActionsCell', + 'Shared/Grid/Pager', + 'Shared/LoadingView', + 'Shared/Toolbar/ToolbarLayout' + ], function (vent, + Marionette, + Backgrid, + BlacklistCollection, + SeriesTitleCell, + QualityCell, + RelativeDateCell, + BlacklistActionsCell, + GridPager, + LoadingView, + ToolbarLayout) { + return Marionette.Layout.extend({ + template: 'History/Blacklist/BlacklistLayoutTemplate', + + regions: { + blacklist : '#x-blacklist', + toolbar : '#x-toolbar', + pager : '#x-pager' + }, + + columns: + [ + { + name : 'series', + label: 'Series', + cell : SeriesTitleCell, + sortValue: 'series.title' + }, + { + name : 'sourceTitle', + label: 'Source Title', + cell : 'string', + sortValue: 'sourceTitle' + }, + { + name : 'quality', + label : 'Quality', + cell : QualityCell, + sortable: false + }, + { + name : 'date', + label: 'Date', + cell : RelativeDateCell + }, + { + name : 'this', + label : '', + cell : BlacklistActionsCell, + sortable: false + } + ], + + initialize: function () { + this.collection = new BlacklistCollection({ tableName: 'blacklist' }); + this.listenTo(this.collection, 'sync', this._showTable); + vent.on(vent.Events.CommandComplete, this._commandComplete, this); + }, + + onShow: function () { + this.blacklist.show(new LoadingView()); + this._showToolbar(); + this.collection.fetch(); + }, + + _showTable: function (collection) { + + this.blacklist.show(new Backgrid.Grid({ + columns : this.columns, + collection: collection, + className : 'table table-hover' + })); + + this.pager.show(new GridPager({ + columns : this.columns, + collection: collection + })); + }, + + _showToolbar: function () { + var leftSideButtons = { + type : 'default', + storeState: false, + items : + [ + { + title : 'Clear Blacklist', + icon : 'icon-trash', + command : 'clearBlacklist' + } + ] + }; + + this.toolbar.show(new ToolbarLayout({ + left : + [ + leftSideButtons + ], + context: this + })); + }, + + _refreshTable: function (buttonContext) { + this.collection.state.currentPage = 1; + var promise = this.collection.fetch({ reset: true }); + + if (buttonContext) { + buttonContext.ui.icon.spinForPromise(promise); + } + }, + + _commandComplete: function (options) { + if (options.command.get('name') === 'clearblacklist') { + this._refreshTable(); + } + } + }); + }); diff --git a/src/UI/History/Blacklist/BlacklistLayoutTemplate.html b/src/UI/History/Blacklist/BlacklistLayoutTemplate.html new file mode 100644 index 000000000..f90d55c39 --- /dev/null +++ b/src/UI/History/Blacklist/BlacklistLayoutTemplate.html @@ -0,0 +1,11 @@ +
+
+
+
+
+
+
+
+
+
+
diff --git a/src/UI/History/Blacklist/BlacklistModel.js b/src/UI/History/Blacklist/BlacklistModel.js new file mode 100644 index 000000000..f8bf927aa --- /dev/null +++ b/src/UI/History/Blacklist/BlacklistModel.js @@ -0,0 +1,21 @@ +'use strict'; +define( + [ + 'backbone', + 'Series/SeriesCollection' + ], function (Backbone, SeriesCollection) { + return Backbone.Model.extend({ + + //Hack to deal with Backbone 1.0's bug + initialize: function () { + this.url = function () { + return this.collection.url + '/' + this.get('id'); + }; + }, + + parse: function (model) { + model.series = SeriesCollection.get(model.seriesId); + return model; + } + }); + }); diff --git a/src/UI/History/Details/HistoryDetailsViewTemplate.html b/src/UI/History/Details/HistoryDetailsViewTemplate.html index 9e2a1433e..9c313a9ae 100644 --- a/src/UI/History/Details/HistoryDetailsViewTemplate.html +++ b/src/UI/History/Details/HistoryDetailsViewTemplate.html @@ -36,6 +36,9 @@ {{/if_eq}} {{#if_eq eventType compare="downloadFailed"}}
+
Source Title
+
{{sourceTitle}}
+ {{#with data}}
Message
{{message}}
diff --git a/src/UI/History/HistoryLayout.js b/src/UI/History/HistoryLayout.js index 04f5bc12f..fc13cd2fe 100644 --- a/src/UI/History/HistoryLayout.js +++ b/src/UI/History/HistoryLayout.js @@ -5,24 +5,28 @@ define( 'backbone', 'backgrid', 'History/Table/HistoryTableLayout', + 'History/Blacklist/BlacklistLayout', 'History/Queue/QueueLayout' - ], function (Marionette, Backbone, Backgrid, HistoryTableLayout, QueueLayout) { + ], function (Marionette, Backbone, Backgrid, HistoryTableLayout, BlacklistLayout, QueueLayout) { return Marionette.Layout.extend({ template: 'History/HistoryLayoutTemplate', regions: { history : '#history', + blacklist : '#blacklist', queueRegion: '#queue' }, ui: { historyTab: '.x-history-tab', + blacklistTab: '.x-blacklist-tab', queueTab : '.x-queue-tab' }, events: { - 'click .x-history-tab': '_showHistory', - 'click .x-queue-tab' : '_showQueue' + 'click .x-history-tab' : '_showHistory', + 'click .x-blacklist-tab' : '_showBlacklist', + 'click .x-queue-tab' : '_showQueue' }, initialize: function (options) { @@ -55,6 +59,16 @@ define( this._navigate('/history'); }, + _showBlacklist: function (e) { + if (e) { + e.preventDefault(); + } + + this.blacklist.show(new BlacklistLayout()); + this.ui.blacklistTab.tab('show'); + this._navigate('/history/blacklist'); + }, + _showQueue: function (e) { if (e) { e.preventDefault(); diff --git a/src/UI/History/HistoryLayoutTemplate.html b/src/UI/History/HistoryLayoutTemplate.html index 50c981bf0..4faa2d28b 100644 --- a/src/UI/History/HistoryLayoutTemplate.html +++ b/src/UI/History/HistoryLayoutTemplate.html @@ -1,9 +1,11 @@ 
+
\ No newline at end of file diff --git a/src/UI/JsLibraries/backbone.js b/src/UI/JsLibraries/backbone.js index 3512d42fb..70a854d31 100644 --- a/src/UI/JsLibraries/backbone.js +++ b/src/UI/JsLibraries/backbone.js @@ -259,7 +259,7 @@ }; // A list of options to be attached directly to the model, if provided. - var modelOptions = ['url', 'urlRoot', 'collection']; + var modelOptions = ['urlRoot', 'collection']; // Attach all inheritable methods to the Model prototype. _.extend(Model.prototype, Events, { diff --git a/src/UI/JsLibraries/jquery.easypiechart.js b/src/UI/JsLibraries/jquery.easypiechart.js new file mode 100644 index 000000000..c600fb85f --- /dev/null +++ b/src/UI/JsLibraries/jquery.easypiechart.js @@ -0,0 +1,357 @@ +/**! + * easyPieChart + * Lightweight plugin to render simple, animated and retina optimized pie charts + * + * @license + * @author Robert Fleischmann (http://robert-fleischmann.de) + * @version 2.1.3 + **/ + +(function(root, factory) { + if(typeof exports === 'object') { + module.exports = factory(require('jquery')); + } + else if(typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } + else { + factory(root.jQuery); + } +}(this, function($) { +/** + * Renderer to render the chart on a canvas object + * @param {DOMElement} el DOM element to host the canvas (root of the plugin) + * @param {object} options options object of the plugin + */ +var CanvasRenderer = function(el, options) { + var cachedBackground; + var canvas = document.createElement('canvas'); + + el.appendChild(canvas); + + if (typeof(G_vmlCanvasManager) !== 'undefined') { + G_vmlCanvasManager.initElement(canvas); + } + + var ctx = canvas.getContext('2d'); + + canvas.width = canvas.height = options.size; + + // canvas on retina devices + var scaleBy = 1; + if (window.devicePixelRatio > 1) { + scaleBy = window.devicePixelRatio; + canvas.style.width = canvas.style.height = [options.size, 'px'].join(''); + canvas.width = canvas.height = options.size * scaleBy; + ctx.scale(scaleBy, scaleBy); + } + + // move 0,0 coordinates to the center + ctx.translate(options.size / 2, options.size / 2); + + // rotate canvas -90deg + ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); + + var radius = (options.size - options.lineWidth) / 2; + if (options.scaleColor && options.scaleLength) { + radius -= options.scaleLength + 2; // 2 is the distance between scale and bar + } + + // IE polyfill for Date + Date.now = Date.now || function() { + return +(new Date()); + }; + + /** + * Draw a circle around the center of the canvas + * @param {strong} color Valid CSS color string + * @param {number} lineWidth Width of the line in px + * @param {number} percent Percentage to draw (float between -1 and 1) + */ + var drawCircle = function(color, lineWidth, percent) { + percent = Math.min(Math.max(-1, percent || 0), 1); + var isNegative = percent <= 0 ? true : false; + + ctx.beginPath(); + ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative); + + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + + ctx.stroke(); + }; + + /** + * Draw the scale of the chart + */ + var drawScale = function() { + var offset; + var length; + + ctx.lineWidth = 1; + ctx.fillStyle = options.scaleColor; + + ctx.save(); + for (var i = 24; i > 0; --i) { + if (i % 6 === 0) { + length = options.scaleLength; + offset = 0; + } else { + length = options.scaleLength * 0.6; + offset = options.scaleLength - length; + } + ctx.fillRect(-options.size/2 + offset, 0, length, 1); + ctx.rotate(Math.PI / 12); + } + ctx.restore(); + }; + + /** + * Request animation frame wrapper with polyfill + * @return {function} Request animation frame method or timeout fallback + */ + var reqAnimationFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + function(callback) { + window.setTimeout(callback, 1000 / 60); + }; + }()); + + /** + * Draw the background of the plugin including the scale and the track + */ + var drawBackground = function() { + if(options.scaleColor) drawScale(); + if(options.trackColor) drawCircle(options.trackColor, options.lineWidth, 1); + }; + + /** + * Canvas accessor + */ + this.getCanvas = function() { + return canvas; + }; + + /** + * Canvas 2D context 'ctx' accessor + */ + this.getCtx = function() { + return ctx; + }; + + /** + * Clear the complete canvas + */ + this.clear = function() { + ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size); + }; + + /** + * Draw the complete chart + * @param {number} percent Percent shown by the chart between -100 and 100 + */ + this.draw = function(percent) { + // do we need to render a background + if (!!options.scaleColor || !!options.trackColor) { + // getImageData and putImageData are supported + if (ctx.getImageData && ctx.putImageData) { + if (!cachedBackground) { + drawBackground(); + cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy); + } else { + ctx.putImageData(cachedBackground, 0, 0); + } + } else { + this.clear(); + drawBackground(); + } + } else { + this.clear(); + } + + ctx.lineCap = options.lineCap; + + // if barcolor is a function execute it and pass the percent as a value + var color; + if (typeof(options.barColor) === 'function') { + color = options.barColor(percent); + } else { + color = options.barColor; + } + + // draw bar + drawCircle(color, options.lineWidth, percent / 100); + }.bind(this); + + /** + * Animate from some percent to some other percentage + * @param {number} from Starting percentage + * @param {number} to Final percentage + */ + this.animate = function(from, to) { + var startTime = Date.now(); + options.onStart(from, to); + var animation = function() { + var process = Math.min(Date.now() - startTime, options.animate.duration); + var currentValue = options.easing(this, process, from, to - from, options.animate.duration); + this.draw(currentValue); + options.onStep(from, to, currentValue); + if (process >= options.animate.duration) { + options.onStop(from, to); + } else { + reqAnimationFrame(animation); + } + }.bind(this); + + reqAnimationFrame(animation); + }.bind(this); +}; + +var EasyPieChart = function(el, opts) { + var defaultOptions = { + barColor: '#ef1e25', + trackColor: '#f9f9f9', + scaleColor: '#dfe0e0', + scaleLength: 5, + lineCap: 'round', + lineWidth: 3, + size: 110, + rotate: 0, + animate: { + duration: 1000, + enabled: true + }, + easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/ + t = t / (d/2); + if (t < 1) { + return c / 2 * t * t + b; + } + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + onStart: function(from, to) { + return; + }, + onStep: function(from, to, currentValue) { + return; + }, + onStop: function(from, to) { + return; + } + }; + + // detect present renderer + if (typeof(CanvasRenderer) !== 'undefined') { + defaultOptions.renderer = CanvasRenderer; + } else if (typeof(SVGRenderer) !== 'undefined') { + defaultOptions.renderer = SVGRenderer; + } else { + throw new Error('Please load either the SVG- or the CanvasRenderer'); + } + + var options = {}; + var currentValue = 0; + + /** + * Initialize the plugin by creating the options object and initialize rendering + */ + var init = function() { + this.el = el; + this.options = options; + + // merge user options into default options + for (var i in defaultOptions) { + if (defaultOptions.hasOwnProperty(i)) { + options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i]; + if (typeof(options[i]) === 'function') { + options[i] = options[i].bind(this); + } + } + } + + // check for jQuery easing + if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) { + options.easing = jQuery.easing[options.easing]; + } else { + options.easing = defaultOptions.easing; + } + + // process earlier animate option to avoid bc breaks + if (typeof(options.animate) === 'number') { + options.animate = { + duration: options.animate, + enabled: true + }; + } + + if (typeof(options.animate) === 'boolean' && !options.animate) { + options.animate = { + duration: 1000, + enabled: options.animate + }; + } + + // create renderer + this.renderer = new options.renderer(el, options); + + // initial draw + this.renderer.draw(currentValue); + + // initial update + if (el.dataset && el.dataset.percent) { + this.update(parseFloat(el.dataset.percent)); + } else if (el.getAttribute && el.getAttribute('data-percent')) { + this.update(parseFloat(el.getAttribute('data-percent'))); + } + }.bind(this); + + /** + * Update the value of the chart + * @param {number} newValue Number between 0 and 100 + * @return {object} Instance of the plugin for method chaining + */ + this.update = function(newValue) { + newValue = parseFloat(newValue); + if (options.animate.enabled) { + this.renderer.animate(currentValue, newValue); + } else { + this.renderer.draw(newValue); + } + currentValue = newValue; + return this; + }.bind(this); + + /** + * Disable animation + * @return {object} Instance of the plugin for method chaining + */ + this.disableAnimation = function() { + options.animate.enabled = false; + return this; + }; + + /** + * Enable animation + * @return {object} Instance of the plugin for method chaining + */ + this.enableAnimation = function() { + options.animate.enabled = true; + return this; + }; + + init(); +}; + +$.fn.easyPieChart = function(options) { + return this.each(function() { + var instanceOptions; + + if (!$.data(this, 'easyPieChart')) { + instanceOptions = $.extend({}, options, $(this).data()); + $.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions)); + } + }); +}; + +})); diff --git a/src/UI/Mixins/AsFilteredCollection.js b/src/UI/Mixins/AsFilteredCollection.js new file mode 100644 index 000000000..447f60edb --- /dev/null +++ b/src/UI/Mixins/AsFilteredCollection.js @@ -0,0 +1,78 @@ +'use strict'; + +define( + [ + 'underscore', + 'backbone'], + function (_, Backbone) { + + return function () { + + this.prototype.setFilter = function(filter, options) { + options = _.extend({ reset: true }, options || {}); + + this.state.filterKey = filter[0]; + this.state.filterValue = filter[1]; + + if (options.reset) { + if (this.mode != 'server') { + this.fullCollection.resetFiltered(); + } else { + return this.fetch(); + } + } + }; + + this.prototype.setFilterMode = function(mode, options) { + this.setFilter(this.filterModes[mode], options); + }; + + var originalMakeFullCollection = this.prototype._makeFullCollection; + + this.prototype._makeFullCollection = function (models, options) { + var self = this; + + self.shadowCollection = originalMakeFullCollection.apply(this, [models, options]); + + var filterModel = function(model) { + if (!self.state.filterKey || !self.state.filterValue) + return true; + else + return model.get(self.state.filterKey) === self.state.filterValue; + }; + + self.shadowCollection.filtered = function() { + return this.filter(filterModel); + }; + + var filteredModels = self.shadowCollection.filtered(); + + var fullCollection = originalMakeFullCollection.apply(this, [filteredModels, options]); + + + fullCollection.resetFiltered = function(options) { + Backbone.Collection.prototype.reset.apply(this, [self.shadowCollection.filtered(), options]); + }; + + fullCollection.reset = function (models, options) { + self.shadowCollection.reset(models, options); + self.fullCollection.resetFiltered(); + }; + + return fullCollection; + }; + + _.extend(this.prototype.state, { + filterKey : null, + filterValue : null + }); + + _.extend(this.prototype.queryParams, { + filterKey : 'filterKey', + filterValue : 'filterValue' + }); + + return this; + }; + } +); \ No newline at end of file diff --git a/src/UI/Mixins/AsPersistedStateCollection.js b/src/UI/Mixins/AsPersistedStateCollection.js index 879c05427..d4177f1a4 100644 --- a/src/UI/Mixins/AsPersistedStateCollection.js +++ b/src/UI/Mixins/AsPersistedStateCollection.js @@ -62,23 +62,20 @@ define( return '1'; }; + + var originalMakeComparator = this.prototype._makeComparator; + this.prototype._makeComparator = function (sortKey, order, sortValue) { + var state = this.state; - _.extend(this.prototype, { - initialSort: function () { - var key = this.state.sortKey; - var order = this.state.order; + sortKey = sortKey || state.sortKey; + order = order || state.order; - if (this[key] && this.mode === 'client') { - var sortValue = this[key]; - - this.setSorting(key, order, { sortValue: sortValue }); - - var comparator = this._makeComparator(key, order, sortValue); - this.fullCollection.comparator = comparator; - this.fullCollection.sort(); - } - } - }); + if (!sortKey || !order) return; + + if (!sortValue && this[sortKey]) sortValue = this[sortKey]; + + return originalMakeComparator.call(this, sortKey, order, sortValue); + }; return this; }; diff --git a/src/UI/SeasonPass/SeriesLayoutTemplate.html b/src/UI/SeasonPass/SeriesLayoutTemplate.html index 8601d6453..be084a498 100644 --- a/src/UI/SeasonPass/SeriesLayoutTemplate.html +++ b/src/UI/SeasonPass/SeriesLayoutTemplate.html @@ -22,7 +22,7 @@ - + diff --git a/src/UI/Series/Delete/DeleteSeriesTemplate.html b/src/UI/Series/Delete/DeleteSeriesTemplate.html index ac262f604..e54fc750d 100644 --- a/src/UI/Series/Delete/DeleteSeriesTemplate.html +++ b/src/UI/Series/Delete/DeleteSeriesTemplate.html @@ -27,7 +27,7 @@ - +
diff --git a/src/UI/Series/Edit/EditSeriesViewTemplate.html b/src/UI/Series/Edit/EditSeriesViewTemplate.html index 7fe6660b9..4476abad0 100644 --- a/src/UI/Series/Edit/EditSeriesViewTemplate.html +++ b/src/UI/Series/Edit/EditSeriesViewTemplate.html @@ -26,7 +26,7 @@ - +
@@ -46,7 +46,7 @@ - + @@ -62,7 +62,7 @@ {{/each}} - + @@ -73,7 +73,7 @@
- +
diff --git a/src/UI/Series/EpisodeModel.js b/src/UI/Series/EpisodeModel.js index 624019b50..9a040715d 100644 --- a/src/UI/Series/EpisodeModel.js +++ b/src/UI/Series/EpisodeModel.js @@ -8,6 +8,18 @@ define( defaults: { seasonNumber: 0, status : 0 + }, + + methodUrls: { + 'update': window.NzbDrone.ApiRoot + '/episodes' + }, + + sync: function(method, model, options) { + if (model.methodUrls && model.methodUrls[method.toLowerCase()]) { + options = options || {}; + options.url = model.methodUrls[method.toLowerCase()]; + } + return Backbone.sync(method, model, options); } }); }); diff --git a/src/UI/Series/Index/SeriesIndexLayout.js b/src/UI/Series/Index/SeriesIndexLayout.js index 416d1ec1a..3313bca83 100644 --- a/src/UI/Series/Index/SeriesIndexLayout.js +++ b/src/UI/Series/Index/SeriesIndexLayout.js @@ -41,6 +41,7 @@ define( regions: { seriesRegion : '#x-series', toolbar : '#x-toolbar', + toolbar2 : '#x-toolbar2', footer : '#x-series-footer' }, @@ -127,46 +128,84 @@ define( ] }, - sortingOptions: { - type : 'sorting', - storeState : false, - viewCollection: SeriesCollection, - items : - [ - { - title: 'Title', - name : 'title' - }, - { - title: 'Seasons', - name : 'seasonCount' - }, - { - title: 'Quality', - name : 'qualityProfileId' - }, - { - title: 'Network', - name : 'network' - }, - { - title : 'Next Airing', - name : 'nextAiring', - sortValue : SeriesCollection.nextAiring - }, - { - title: 'Episodes', - name : 'percentOfEpisodes' - } - ] - }, - initialize: function () { - this.seriesCollection = SeriesCollection; + this.seriesCollection = SeriesCollection.clone(); this.listenTo(SeriesCollection, 'sync', this._renderView); this.listenTo(SeriesCollection, 'remove', this._renderView); + this.sortingOptions = { + type : 'sorting', + storeState : false, + viewCollection: this.seriesCollection, + items : + [ + { + title: 'Title', + name : 'title' + }, + { + title: 'Seasons', + name : 'seasonCount' + }, + { + title: 'Quality', + name : 'qualityProfileId' + }, + { + title: 'Network', + name : 'network' + }, + { + title : 'Next Airing', + name : 'nextAiring', + sortValue : SeriesCollection.nextAiring + }, + { + title: 'Episodes', + name : 'percentOfEpisodes' + } + ] + }; + + this.filteringOptions = { + type : 'radio', + storeState : true, + menuKey : 'series.filterMode', + defaultAction: 'all', + items : + [ + { + key : 'all', + title : '', + tooltip : 'All', + icon : 'icon-circle-blank', + callback: this._setFilter + }, + { + key : 'monitored', + title : '', + tooltip : 'Monitored Only', + icon : 'icon-nd-monitored', + callback: this._setFilter + }, + { + key : 'continuing', + title : '', + tooltip : 'Continuing Only', + icon : 'icon-play', + callback: this._setFilter + }, + { + key : 'ended', + title : '', + tooltip : 'Ended Only', + icon : 'icon-stop', + callback: this._setFilter + } + ] + }; + this.viewButtons = { type : 'radio', storeState : true, @@ -199,33 +238,44 @@ define( }; }, + onShow: function () { + this._showToolbar(); + this._renderView(); + this._fetchCollection(); + }, + _showTable: function () { this.currentView = new Backgrid.Grid({ - collection: SeriesCollection, + collection: this.seriesCollection, columns : this.columns, className : 'table table-hover' }); - this._fetchCollection(); + this._renderView(); }, _showList: function () { - this.currentView = new ListCollectionView({ collection: SeriesCollection }); + this.currentView = new ListCollectionView({ + collection: this.seriesCollection + }); - this._fetchCollection(); + this._renderView(); }, _showPosters: function () { - this.currentView = new PosterCollectionView({ collection: SeriesCollection }); + this.currentView = new PosterCollectionView({ + collection: this.seriesCollection + }); - this._fetchCollection(); + this._renderView(); }, - + _renderView: function () { if (SeriesCollection.length === 0) { this.seriesRegion.show(new EmptyView()); this.toolbar.close(); + this.toolbar2.close(); } else { this.seriesRegion.show(this.currentView); @@ -235,13 +285,14 @@ define( } }, - onShow: function () { - this._showToolbar(); - this._renderView(); + _fetchCollection: function () { + this.seriesCollection.fetch(); }, - _fetchCollection: function () { - SeriesCollection.fetch(); + _setFilter: function(buttonContext) { + var mode = buttonContext.model.get('key'); + + this.seriesCollection.setFilterMode(mode); }, _showToolbar: function () { @@ -250,20 +301,26 @@ define( return; } - var rightButtons = [ - this.viewButtons - ]; - - rightButtons.splice(0, 0, this.sortingOptions); - this.toolbar.show(new ToolbarLayout({ - right : rightButtons, + right : + [ + this.sortingOptions, + this.viewButtons + ], left : [ this.leftSideButtons ], context: this })); + + this.toolbar2.show(new ToolbarLayout({ + right : + [ + this.filteringOptions + ], + context: this + })); }, _showFooter: function () { diff --git a/src/UI/Series/Index/SeriesIndexLayoutTemplate.html b/src/UI/Series/Index/SeriesIndexLayoutTemplate.html index 40124822f..08353e5c1 100644 --- a/src/UI/Series/Index/SeriesIndexLayoutTemplate.html +++ b/src/UI/Series/Index/SeriesIndexLayoutTemplate.html @@ -1,4 +1,7 @@ -
+
+
+
+
diff --git a/src/UI/Series/SeriesCollection.js b/src/UI/Series/SeriesCollection.js index 629ed799e..4f00e6c42 100644 --- a/src/UI/Series/SeriesCollection.js +++ b/src/UI/Series/SeriesCollection.js @@ -6,9 +6,10 @@ define( 'backbone.pageable', 'Series/SeriesModel', 'api!series', + 'Mixins/AsFilteredCollection', 'Mixins/AsPersistedStateCollection', 'moment' - ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsPersistedStateCollection, Moment) { + ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsPersistedStateCollection, Moment) { var Collection = PageableCollection.extend({ url : window.NzbDrone.ApiRoot + '/series', model: SeriesModel, @@ -47,6 +48,14 @@ define( return proxy.save(); }, + // Filter Modes + filterModes: { + 'all' : [null, null], + 'continuing' : ['status', 'continuing'], + 'ended' : ['status', 'ended'], + 'monitored' : ['monitored', true] + }, + //Sorters nextAiring: function (model, attr) { var nextAiring = model.get(attr); @@ -59,9 +68,9 @@ define( } }); - var MixedIn = AsPersistedStateCollection.call(Collection); - var collection = new MixedIn(SeriesData); - collection.initialSort(); + var FilteredCollection = AsFilteredCollection.call(Collection); + var MixedIn = AsPersistedStateCollection.call(FilteredCollection); + var collection = new MixedIn(SeriesData, { full: true }); return collection; }); diff --git a/src/UI/Settings/DownloadClient/SabViewTemplate.html b/src/UI/Settings/DownloadClient/SabViewTemplate.html index 39e194aa0..9b997ae07 100644 --- a/src/UI/Settings/DownloadClient/SabViewTemplate.html +++ b/src/UI/Settings/DownloadClient/SabViewTemplate.html @@ -7,7 +7,7 @@
-
diff --git a/src/UI/Settings/Indexers/EditTemplate.html b/src/UI/Settings/Indexers/EditTemplate.html index f9c3779ca..0bf5bdc06 100644 --- a/src/UI/Settings/Indexers/EditTemplate.html +++ b/src/UI/Settings/Indexers/EditTemplate.html @@ -1,5 +1,5 @@  @@ -36,7 +36,7 @@ - +
@@ -71,7 +71,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -112,7 +112,7 @@ - + diff --git a/src/UI/Settings/MediaManagement/MediaManagementLayout.js b/src/UI/Settings/MediaManagement/MediaManagementLayout.js index 56b34c814..3b5ac123e 100644 --- a/src/UI/Settings/MediaManagement/MediaManagementLayout.js +++ b/src/UI/Settings/MediaManagement/MediaManagementLayout.js @@ -5,15 +5,17 @@ define( 'marionette', 'Settings/MediaManagement/Naming/NamingView', 'Settings/MediaManagement/Sorting/View', - 'Settings/MediaManagement/FileManagement/FileManagementView' - ], function (Marionette, NamingView, SortingView, FileManagementView) { + 'Settings/MediaManagement/FileManagement/FileManagementView', + 'Settings/MediaManagement/Permissions/PermissionsView' + ], function (Marionette, NamingView, SortingView, FileManagementView, PermissionsView) { return Marionette.Layout.extend({ template: 'Settings/MediaManagement/MediaManagementLayoutTemplate', regions: { episodeNaming : '#episode-naming', sorting : '#sorting', - fileManagement : '#file-management' + fileManagement : '#file-management', + permissions : '#permissions' }, initialize: function (options) { @@ -25,6 +27,7 @@ define( this.episodeNaming.show(new NamingView({ model: this.namingSettings })); this.sorting.show(new SortingView({ model: this.settings })); this.fileManagement.show(new FileManagementView({ model: this.settings })); + this.permissions.show(new PermissionsView({ model: this.settings })); } }); }); diff --git a/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html b/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html index 4720aa606..05a416998 100644 --- a/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html +++ b/src/UI/Settings/MediaManagement/MediaManagementLayoutTemplate.html @@ -2,4 +2,5 @@
+
\ No newline at end of file diff --git a/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js b/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js new file mode 100644 index 000000000..e1a098106 --- /dev/null +++ b/src/UI/Settings/MediaManagement/Permissions/PermissionsView.js @@ -0,0 +1,39 @@ +'use strict'; +define( + [ + 'marionette', + 'Mixins/AsModelBoundView', + 'Mixins/AutoComplete' + ], function (Marionette, AsModelBoundView) { + + var view = Marionette.ItemView.extend({ + template: 'Settings/MediaManagement/Permissions/PermissionsViewTemplate', + + ui: { + recyclingBin : '.x-path', + failedDownloadHandlingCheckbox: '.x-failed-download-handling', + failedDownloadOptions : '.x-failed-download-options' + }, + + events: { + 'change .x-failed-download-handling': '_setFailedDownloadOptionsVisibility' + }, + + onShow: function () { + this.ui.recyclingBin.autoComplete('/directories'); + }, + + _setFailedDownloadOptionsVisibility: function () { + var checked = this.ui.failedDownloadHandlingCheckbox.prop('checked'); + if (checked) { + this.ui.failedDownloadOptions.slideDown(); + } + + else { + this.ui.failedDownloadOptions.slideUp(); + } + } + }); + + return AsModelBoundView.call(view); + }); diff --git a/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html b/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html new file mode 100644 index 000000000..ca0a685a7 --- /dev/null +++ b/src/UI/Settings/MediaManagement/Permissions/PermissionsViewTemplate.html @@ -0,0 +1,70 @@ +{{#if_linux}} +
+ Permissions + +
+ + +
+
+ +
+ + +
+ + + + +
+
+ +
+ + +
+ + + + +
+
+ +
+ + +
+ + + + +
+
+ +
+ + +
+ + + + +
+
+
+{{/if_linux}} \ No newline at end of file diff --git a/src/UI/Settings/MediaManagement/Sorting/ViewTemplate.html b/src/UI/Settings/MediaManagement/Sorting/ViewTemplate.html index dde9a2d84..76f25867a 100644 --- a/src/UI/Settings/MediaManagement/Sorting/ViewTemplate.html +++ b/src/UI/Settings/MediaManagement/Sorting/ViewTemplate.html @@ -17,7 +17,7 @@ - + diff --git a/src/UI/Settings/Notifications/NotificationEditViewTemplate.html b/src/UI/Settings/Notifications/NotificationEditViewTemplate.html index 9c1fff961..c785fe9c1 100644 --- a/src/UI/Settings/Notifications/NotificationEditViewTemplate.html +++ b/src/UI/Settings/Notifications/NotificationEditViewTemplate.html @@ -31,7 +31,7 @@ - + @@ -51,7 +51,7 @@ - + diff --git a/src/UI/Settings/Quality/Profile/EditQualityProfileTemplate.html b/src/UI/Settings/Quality/Profile/EditQualityProfileTemplate.html index f45c97dda..5f65e44b5 100644 --- a/src/UI/Settings/Quality/Profile/EditQualityProfileTemplate.html +++ b/src/UI/Settings/Quality/Profile/EditQualityProfileTemplate.html @@ -23,7 +23,7 @@ {{/each}} - + diff --git a/src/UI/Settings/SettingsModelBase.js b/src/UI/Settings/SettingsModelBase.js index 5b2b5bec3..834f10469 100644 --- a/src/UI/Settings/SettingsModelBase.js +++ b/src/UI/Settings/SettingsModelBase.js @@ -10,6 +10,7 @@ define( initialize: function () { this.listenTo(vent, vent.Commands.SaveSettings, this.saveSettings); + this.listenTo(this, 'destroy', this._stopListening); }, saveSettings: function () { @@ -28,8 +29,11 @@ define( } return undefined; - } + }, + _stopListening: function () { + this.stopListening(vent, vent.Commands.SaveSettings); + } }); return AsChangeTrackingModel.call(model); diff --git a/src/UI/Shared/Toolbar/Radio/RadioButtonView.js b/src/UI/Shared/Toolbar/Radio/RadioButtonView.js index 1fb788250..baa67a5da 100644 --- a/src/UI/Shared/Toolbar/Radio/RadioButtonView.js +++ b/src/UI/Shared/Toolbar/Radio/RadioButtonView.js @@ -9,6 +9,10 @@ define( template : 'Shared/Toolbar/ButtonTemplate', className: 'btn', + ui: { + icon: 'i' + }, + events: { 'click': 'onClick' }, @@ -49,7 +53,7 @@ define( var callback = this.model.get('callback'); if (callback) { - callback.call(this.model.ownerContext); + callback.call(this.model.ownerContext, this); } } }); diff --git a/src/UI/Shared/Toolbar/ToolbarLayout.js b/src/UI/Shared/Toolbar/ToolbarLayout.js index 8a907dad6..b1e2ee148 100644 --- a/src/UI/Shared/Toolbar/ToolbarLayout.js +++ b/src/UI/Shared/Toolbar/ToolbarLayout.js @@ -10,13 +10,12 @@ define( 'underscore' ], function (Marionette, ButtonCollection, ButtonModel, RadioButtonCollectionView, ButtonCollectionView, SortingButtonCollectionView, _) { return Marionette.Layout.extend({ - template: 'Shared/Toolbar/ToolbarLayoutTemplate', + template : 'Shared/Toolbar/ToolbarLayoutTemplate', + className: 'toolbar', - regions: { - left_1 : '.x-toolbar-left-1', - left_2 : '.x-toolbar-left-2', - right_1: '.x-toolbar-right-1', - right_2: '.x-toolbar-right-2' + ui: { + left_x : '.x-toolbar-left', + right_x: '.x-toolbar-right' }, initialize: function (options) { @@ -97,8 +96,17 @@ define( break; } } - - this[position + '_' + (index + 1).toString()].show(buttonGroupView); + + var regionId = position + "_" + (index + 1); + var region = this[regionId]; + + if (!region) { + var regionClassName = "x-toolbar-" + position + "-" + (index + 1); + this.ui[position + '_x'].append('
\r\n'); + region = this.addRegion(regionId, "." + regionClassName); + } + + region.show(buttonGroupView); } }); }); diff --git a/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html b/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html index b4cd4dcda..533f83bf9 100644 --- a/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html +++ b/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html @@ -1,8 +1,2 @@ -
-
-
-
-
-
-
-
+
+
diff --git a/src/UI/System/Logs/Files/LogFileLayout.js b/src/UI/System/Logs/Files/LogFileLayout.js index af8de87a9..8cffc029e 100644 --- a/src/UI/System/Logs/Files/LogFileLayout.js +++ b/src/UI/System/Logs/Files/LogFileLayout.js @@ -72,7 +72,7 @@ define( _showToolbar: function () { - var rightSideButtons = { + var leftSideButtons = { type : 'default', storeState: false, items : @@ -81,7 +81,7 @@ define( title : 'Refresh', icon : 'icon-refresh', ownerContext : this, - callback : this._refreshLogs + callback : this._refreshTable }, { @@ -95,9 +95,9 @@ define( }; this.toolbar.show(new ToolbarLayout({ - right : + left : [ - rightSideButtons + leftSideButtons ], context: this })); @@ -140,7 +140,7 @@ define( this.contents.show(new ContentsView({ model: model })); }, - _refreshLogs: function (buttonContext) { + _refreshTable: function (buttonContext) { this.contents.close(); var promise = this.collection.fetch(); @@ -152,7 +152,7 @@ define( _commandComplete: function (options) { if (options.command.get('name') === 'deletelogfiles') { - this._refreshLogs(); + this._refreshTable(); } } }); diff --git a/src/UI/System/Logs/LogsCollection.js b/src/UI/System/Logs/LogsCollection.js index 350ed1522..045675796 100644 --- a/src/UI/System/Logs/LogsCollection.js +++ b/src/UI/System/Logs/LogsCollection.js @@ -4,9 +4,10 @@ define( [ 'backbone.pageable', 'System/Logs/LogsModel', + 'Mixins/AsFilteredCollection', 'Mixins/AsPersistedStateCollection' ], - function (PagableCollection, LogsModel, AsPersistedStateCollection) { + function (PagableCollection, LogsModel, AsFilteredCollection, AsPersistedStateCollection) { var collection = PagableCollection.extend({ url : window.NzbDrone.ApiRoot + '/log', model: LogsModel, @@ -30,6 +31,14 @@ define( } }, + // Filter Modes + filterModes: { + 'all' : [null, null], + 'info' : ['level', 'Info'], + 'warn' : ['level', 'Warn'], + 'error' : ['level', 'Error'] + }, + parseState: function (resp, queryParams, state) { return {totalRecords: resp.totalRecords}; }, @@ -43,5 +52,7 @@ define( } }); - return AsPersistedStateCollection.call(collection); + collection = AsFilteredCollection.apply(collection); + + return AsPersistedStateCollection.apply(collection); }); diff --git a/src/UI/System/Logs/Table/LogsTableLayout.js b/src/UI/System/Logs/Table/LogsTableLayout.js index 219ebfc1b..841a5a92b 100644 --- a/src/UI/System/Logs/Table/LogsTableLayout.js +++ b/src/UI/System/Logs/Table/LogsTableLayout.js @@ -66,7 +66,6 @@ define( onRender: function () { this.grid.show(new LoadingView()); - this.collection.fetch(); }, onShow: function () { @@ -88,7 +87,45 @@ define( }, _showToolbar: function () { - var rightSideButtons = { + var filterButtons = { + type : 'radio', + storeState : true, + menuKey : 'logs.filterMode', + defaultAction: 'all', + items : + [ + { + key : 'all', + title : '', + tooltip : 'All', + icon : 'icon-circle-blank', + callback : this._setFilter + }, + { + key : 'info', + title : '', + tooltip : 'Info', + icon : 'icon-info', + callback : this._setFilter + }, + { + key : 'warn', + title : '', + tooltip : 'Warn', + icon : 'icon-warn', + callback : this._setFilter + }, + { + key : 'error', + title : '', + tooltip : 'Error', + icon : 'icon-error', + callback : this._setFilter + } + ] + }; + + var leftSideButtons = { type : 'default', storeState: false, items : @@ -97,7 +134,7 @@ define( title : 'Refresh', icon : 'icon-refresh', ownerContext : this, - callback : this._refreshLogs + callback : this._refreshTable }, { @@ -109,15 +146,19 @@ define( }; this.toolbar.show(new ToolbarLayout({ - right : + left : [ - rightSideButtons + leftSideButtons + ], + right : + [ + filterButtons ], context: this })); }, - _refreshLogs: function (buttonContext) { + _refreshTable: function (buttonContext) { this.collection.state.currentPage = 1; var promise = this.collection.fetch({ reset: true }); @@ -125,10 +166,23 @@ define( buttonContext.ui.icon.spinForPromise(promise); } }, + + _setFilter: function(buttonContext) { + var mode = buttonContext.model.get('key'); + + this.collection.setFilterMode(mode, { reset: false }); + + this.collection.state.currentPage = 1; + var promise = this.collection.fetch({ reset: true }); + + if (buttonContext) { + buttonContext.ui.icon.spinForPromise(promise); + } + }, _commandComplete: function (options) { if (options.command.get('name') === 'clearlog') { - this._refreshLogs(); + this._refreshTable(); } } }); diff --git a/src/UI/app.js b/src/UI/app.js index 736bd875a..d8dde2b5a 100644 --- a/src/UI/app.js +++ b/src/UI/app.js @@ -21,6 +21,7 @@ require.config({ 'marionette' : 'JsLibraries/backbone.marionette', 'signalR' : 'JsLibraries/jquery.signalR', 'jquery.knob' : 'JsLibraries/jquery.knob', + 'jquery.easypiechart' : 'JsLibraries/jquery.easypiechart', 'jquery.dotdotdot' : 'JsLibraries/jquery.dotdotdot', 'messenger' : 'JsLibraries/messenger', 'jquery' : 'JsLibraries/jquery', @@ -111,6 +112,12 @@ require.config({ 'jquery' ] }, + 'jquery.easypiechart' : { + deps: + [ + 'jquery' + ] + }, 'jquery.dotdotdot' : { deps: [ diff --git a/src/UI/index.html b/src/UI/index.html index f2f720d15..c6911fc0f 100644 --- a/src/UI/index.html +++ b/src/UI/index.html @@ -22,6 +22,7 @@ +