Changelog is now available in the UI

New: Added changelog to UI
pull/4/head
Mark McDowall 11 years ago
parent 90001b1a3b
commit de556764bd

@ -73,6 +73,7 @@ module.exports = function (grunt) {
'UI/Cells/cells.less', 'UI/Cells/cells.less',
'UI/Logs/logs.less', 'UI/Logs/logs.less',
'UI/Settings/settings.less', 'UI/Settings/settings.less',
'UI/Update/update.less'
], ],
dest : outputRoot, dest : outputRoot,
ext: '.css' ext: '.css'

@ -10,25 +10,33 @@ namespace NzbDrone.Api.Update
public class UpdateModule : NzbDroneRestModule<UpdateResource> public class UpdateModule : NzbDroneRestModule<UpdateResource>
{ {
private readonly ICheckUpdateService _checkUpdateService; private readonly ICheckUpdateService _checkUpdateService;
private readonly IRecentUpdateProvider _recentUpdateProvider;
public UpdateModule(ICheckUpdateService checkUpdateService) public UpdateModule(ICheckUpdateService checkUpdateService,
IRecentUpdateProvider recentUpdateProvider)
{ {
_checkUpdateService = checkUpdateService; _checkUpdateService = checkUpdateService;
GetResourceAll = GetAvailableUpdate; _recentUpdateProvider = recentUpdateProvider;
GetResourceAll = GetRecentUpdates;
} }
private List<UpdateResource> GetAvailableUpdate() private UpdateResource GetAvailableUpdate()
{ {
var update = _checkUpdateService.AvailableUpdate(); var update = _checkUpdateService.AvailableUpdate();
var response = new List<UpdateResource>(); var response = new UpdateResource();
if (update != null) if (update != null)
{ {
response.Add(update.InjectTo<UpdateResource>()); return update.InjectTo<UpdateResource>();
} }
return response; return response;
} }
private List<UpdateResource> GetRecentUpdates()
{
return ToListResource(_recentUpdateProvider.GetRecentUpdatePackages);
}
} }
public class UpdateResource : RestResource public class UpdateResource : RestResource
@ -40,5 +48,7 @@ namespace NzbDrone.Api.Update
public DateTime ReleaseDate { get; set; } public DateTime ReleaseDate { get; set; }
public String FileName { get; set; } public String FileName { get; set; }
public String Url { get; set; } public String Url { get; set; }
public UpdateChanges Changes { get; set; }
} }
} }

@ -252,7 +252,7 @@
<Content Include="App_Data\Config.xml"> <Content Include="App_Data\Config.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Files\Indexers\Newznab\error.xml" /> <Content Include="Files\Indexers\Newznab\unauthorized.xml" />
<Content Include="Files\Media\H264_sample.mp4"> <Content Include="Files\Media\H264_sample.mp4">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>

@ -550,6 +550,8 @@
<Compile Include="Tv\RefreshSeriesService.cs" /> <Compile Include="Tv\RefreshSeriesService.cs" />
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" /> <Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
<Compile Include="Update\InstallUpdateService.cs" /> <Compile Include="Update\InstallUpdateService.cs" />
<Compile Include="Update\RecentUpdateProvider.cs" />
<Compile Include="Update\UpdateChanges.cs" />
<Compile Include="Update\UpdatePackageAvailable.cs" /> <Compile Include="Update\UpdatePackageAvailable.cs" />
<Compile Include="Update\UpdatePackageProvider.cs" /> <Compile Include="Update\UpdatePackageProvider.cs" />
<Compile Include="Update\UpdatePackage.cs" /> <Compile Include="Update\UpdatePackage.cs" />

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.Update
{
public interface IRecentUpdateProvider
{
List<UpdatePackage> GetRecentUpdatePackages();
}
public class RecentUpdateProvider : IRecentUpdateProvider
{
private readonly IConfigFileProvider _configFileProvider;
private readonly IUpdatePackageProvider _updatePackageProvider;
public RecentUpdateProvider(IConfigFileProvider configFileProvider,
IUpdatePackageProvider updatePackageProvider)
{
_configFileProvider = configFileProvider;
_updatePackageProvider = updatePackageProvider;
}
public List<UpdatePackage> GetRecentUpdatePackages()
{
var branch = _configFileProvider.Branch;
return _updatePackageProvider.GetRecentUpdates(branch);
}
}
}

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.Update
{
public class UpdateChanges
{
public List<String> New { get; set; }
public List<String> Fixed { get; set; }
public UpdateChanges()
{
New = new List<String>();
Fixed = new List<String>();
}
}
}

@ -13,5 +13,7 @@ namespace NzbDrone.Core.Update
public DateTime ReleaseDate { get; set; } public DateTime ReleaseDate { get; set; }
public String FileName { get; set; } public String FileName { get; set; }
public String Url { get; set; } public String Url { get; set; }
public UpdateChanges Changes { get; set; }
} }
} }

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using NzbDrone.Common; using NzbDrone.Common;
using RestSharp; using RestSharp;
using NzbDrone.Core.Rest; using NzbDrone.Core.Rest;
@ -8,6 +9,7 @@ namespace NzbDrone.Core.Update
public interface IUpdatePackageProvider public interface IUpdatePackageProvider
{ {
UpdatePackage GetLatestUpdate(string branch, Version currentVersion); UpdatePackage GetLatestUpdate(string branch, Version currentVersion);
List<UpdatePackage> GetRecentUpdates(string branch);
} }
public class UpdatePackageProvider : IUpdatePackageProvider public class UpdatePackageProvider : IUpdatePackageProvider
@ -27,5 +29,19 @@ namespace NzbDrone.Core.Update
return update.UpdatePackage; return update.UpdatePackage;
} }
public List<UpdatePackage> GetRecentUpdates(string branch)
{
var restClient = new RestClient(Services.RootUrl);
var request = new RestRequest("/v1/update/{branch}/all");
request.AddUrlSegment("branch", branch);
request.AddParameter("limit", 5);
var updates = restClient.ExecuteAndValidate<List<UpdatePackage>>(request);
return updates;
}
} }
} }

@ -1,25 +1,21 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug - Chrome" type="JavascriptDebugSession" factoryName="Remote" singleton="true"> <configuration default="false" name="Debug - Chrome" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" uri="http://localhost:8989">
<JSRemoteDebuggerConfigurationSettings> <mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
<option name="engineId" value="chrome" /> <mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" />
<option name="fileUrl" value="http://localhost:8989" /> <mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" /> <mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" /> <mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" /> <mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" /> <mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" />
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" /> <mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" /> <mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
<mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" /> <mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" /> <mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" /> <mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" /> <mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" /> <mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" /> <mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" /> <mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
</JSRemoteDebuggerConfigurationSettings>
<RunnerSettings RunnerId="JavascriptDebugRunner" /> <RunnerSettings RunnerId="JavascriptDebugRunner" />
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" /> <ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
<method /> <method />

@ -1,25 +1,21 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug - Firefox" type="JavascriptDebugSession" factoryName="Remote" singleton="true"> <configuration default="false" name="Debug - Firefox" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" engineId="firefox" uri="http://localhost:8989">
<JSRemoteDebuggerConfigurationSettings> <mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
<option name="engineId" value="firefox" /> <mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" />
<option name="fileUrl" value="http://localhost:8989" /> <mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" /> <mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" /> <mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" /> <mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" /> <mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" />
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" /> <mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" /> <mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
<mapping url="http://localhost:8989/Missing" local-file="$PROJECT_DIR$/Missing" /> <mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" /> <mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" /> <mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" /> <mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" /> <mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" /> <mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" /> <mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
</JSRemoteDebuggerConfigurationSettings>
<RunnerSettings RunnerId="JavascriptDebugRunner" /> <RunnerSettings RunnerId="JavascriptDebugRunner" />
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" /> <ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
<method /> <method />

@ -16,10 +16,11 @@ define(
'Release/Layout', 'Release/Layout',
'System/Layout', 'System/Layout',
'SeasonPass/SeasonPassLayout', 'SeasonPass/SeasonPassLayout',
'Update/UpdateLayout',
'Shared/NotFoundView', 'Shared/NotFoundView',
'Shared/Modal/Region' 'Shared/Modal/Region'
], function (App, Marionette, HistoryLayout, SettingsLayout, AddSeriesLayout, SeriesIndexLayout, SeriesDetailsLayout, SeriesCollection, MissingLayout, CalendarLayout, ], function (App, Marionette, HistoryLayout, SettingsLayout, AddSeriesLayout, SeriesIndexLayout, SeriesDetailsLayout, SeriesCollection, MissingLayout, CalendarLayout,
LogsLayout, LogFileLayout, ReleaseLayout, SystemLayout, SeasonPassLayout, NotFoundView) { LogsLayout, LogFileLayout, ReleaseLayout, SystemLayout, SeasonPassLayout, UpdateLayout, NotFoundView) {
return Marionette.Controller.extend({ return Marionette.Controller.extend({
series: function () { series: function () {
@ -94,6 +95,11 @@ define(
App.mainRegion.show(new SeasonPassLayout()); App.mainRegion.show(new SeasonPassLayout());
}, },
update: function () {
this._setTitle('Updates');
App.mainRegion.show(new UpdateLayout());
},
notFound: function () { notFound: function () {
this._setTitle('Not Found'); this._setTitle('Not Found');
App.mainRegion.show(new NotFoundView(this)); App.mainRegion.show(new NotFoundView(this));

@ -31,6 +31,7 @@ require(
'rss' : 'rss', 'rss' : 'rss',
'system' : 'system', 'system' : 'system',
'seasonpass' : 'seasonPass', 'seasonpass' : 'seasonPass',
'update' : 'update',
':whatever' : 'notFound' ':whatever' : 'notFound'
} }
}); });

@ -33,9 +33,9 @@ define(
route: 'logs' route: 'logs'
}, },
{ {
title : 'Check for Update', title : 'Updates',
icon : 'icon-nd-update', icon : 'icon-upload-alt',
command: 'applicationUpdate' route : 'update'
} }
] ]
}, },

@ -0,0 +1,11 @@
'use strict';
define(
[
'backbone',
'Update/UpdateModel'
], function (Backbone, UpdateModel) {
return Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/update',
model: UpdateModel
});
});

@ -0,0 +1,10 @@
'use strict';
define(
[
'marionette',
'Update/UpdateItemView'
], function (Marionette, UpdateItemView) {
return Marionette.CollectionView.extend({
itemView: UpdateItemView
});
});

@ -0,0 +1,11 @@
'use strict';
define(
[
'app',
'marionette'
], function (App, Marionette) {
return Marionette.ItemView.extend({
template: 'Update/UpdateItemViewTemplate'
});
});

@ -0,0 +1,23 @@
<div class="update">
<fieldset>
<legend>{{version}} <span class="date">- {{ShortDate releaseDate}}</span></legend>
{{#with changes}}
{{#each new}}
<div class="change">
<span class="label label-success">New</span> {{this}}
</div>
{{/each}}
{{#each fixed}}
<div class="change">
<span class="label label-info">Fixed</span> {{this}}
</div>
{{/each}}
{{/with}}
{{#unless changes}}
No notable changes
{{/unless}}
</fieldset>
</div>

@ -0,0 +1,58 @@
'use strict';
define(
[
'marionette',
'backgrid',
'Update/UpdateCollection',
'Update/UpdateCollectionView',
'Shared/Toolbar/ToolbarLayout',
'Shared/LoadingView'
], function (Marionette, Backgrid, UpdateCollection, UpdateCollectionView, ToolbarLayout, LoadingView) {
return Marionette.Layout.extend({
template: 'Update/UpdateLayoutTemplate',
regions: {
updates: '#x-updates',
toolbar: '#x-toolbar'
},
leftSideButtons: {
type : 'default',
storeState: false,
items :
[
{
title : 'Check for Update',
icon : 'icon-nd-update',
command: 'applicationUpdate'
}
]
},
initialize: function () {
this.updateCollection = new UpdateCollection();
},
onRender: function () {
this.updates.show(new LoadingView());
this._showToolbar();
var self = this;
var promise = this.updateCollection.fetch();
promise.done(function (){
self.updates.show(new UpdateCollectionView({ collection: self.updateCollection }));
});
},
_showToolbar: function () {
this.toolbar.show(new ToolbarLayout({
left :
[
this.leftSideButtons
],
context: this
}));
}
});
});

@ -0,0 +1,6 @@
<div id="x-toolbar"/>
<div class="row">
<div class="span12">
<div id="x-updates"/>
</div>
</div>

@ -0,0 +1,9 @@
'use strict';
define(
[
'backbone'
], function (Backbone) {
return Backbone.Model.extend({
});
});

@ -0,0 +1,25 @@
.update {
margin-bottom: 30px;
legend {
margin-bottom: 5px;
line-height: 30px;
.date {
font-size: 16px;
}
}
.changes-header {
font-size: 18px;
}
.label {
width: 40px;
text-align: center;
}
.change {
margin-bottom: 2px;
font-size: 13px;
}
}

@ -15,6 +15,7 @@
<link href="/Settings/settings.css" rel='stylesheet' type='text/css'/> <link href="/Settings/settings.css" rel='stylesheet' type='text/css'/>
<link href="/AddSeries/addSeries.css" rel='stylesheet' type='text/css'/> <link href="/AddSeries/addSeries.css" rel='stylesheet' type='text/css'/>
<link href="/Calendar/calendar.css" rel='stylesheet' type='text/css'/> <link href="/Calendar/calendar.css" rel='stylesheet' type='text/css'/>
<link href="/Update/update.css" rel='stylesheet' type='text/css'/>
<link href="/Content/overrides.css" rel='stylesheet' type='text/css'/> <link href="/Content/overrides.css" rel='stylesheet' type='text/css'/>
<link rel="apple-touch-icon" href="/Content/Images/touch/57.png"/> <link rel="apple-touch-icon" href="/Content/Images/touch/57.png"/>

Loading…
Cancel
Save