Upcoming/Index now uses .ToBestDateString() for Dates, only showing on FutureForecast grid (instead of all grids). Status is shown on grid and option to search for episode.

Series/Details season grids won't be as tall now, due to reduced padding.
pull/7/merge
Mark McDowall 13 years ago
parent 6736afbeab
commit 9714a96437

@ -1,6 +1,7 @@
// ReSharper disable RedundantUsingDirective // ReSharper disable RedundantUsingDirective
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using AutoMoq; using AutoMoq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
@ -15,50 +16,27 @@ namespace NzbDrone.Core.Test
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class UpcomingEpisodesProviderTest : TestBase public class UpcomingEpisodesProviderTest : TestBase
{ {
private Episode yesterday; private IList<Episode> episodes;
private Episode today;
private Episode tomorrow;
private Episode twoDays;
private Episode sevenDays;
private Series series; private Series series;
[SetUp] [SetUp]
public new void Setup() public new void Setup()
{ {
yesterday = Builder<Episode>.CreateNew() episodes = Builder<Episode>.CreateListOfSize(6)
.With(c => c.AirDate = DateTime.Today.AddDays(-1)) .WhereAll()
.With(c => c.Title = "Yesterday") .Have(e => e.SeriesId = 1)
.With(c => c.SeriesId = 1) .WhereTheFirst(1)
.Build(); .Has(e => e.AirDate = DateTime.Today.AddDays(-1))
.AndTheNext(1)
today = Builder<Episode>.CreateNew() .Has(e => e.AirDate = DateTime.Today)
.With(c => c.AirDate = DateTime.Today) .AndTheNext(1)
.With(c => c.Title = "Today") .Has(e => e.AirDate = DateTime.Today.AddDays(1))
.With(c => c.SeriesId = 1) .AndTheNext(1)
.Build(); .Has(e => e.AirDate = DateTime.Today.AddDays(2))
.AndTheNext(1)
tomorrow = Builder<Episode>.CreateNew() .Has(e => e.AirDate = DateTime.Today.AddDays(7))
.With(c => c.AirDate = DateTime.Today.AddDays(1)) .AndTheNext(1)
.With(c => c.Title = "Tomorrow") .Has(e => e.AirDate = DateTime.Today.AddDays(9))
.With(c => c.SeriesId = 1)
.Build();
twoDays = Builder<Episode>.CreateNew()
.With(c => c.AirDate = DateTime.Today.AddDays(2))
.With(c => c.Title = "Two Days")
.With(c => c.SeriesId = 1)
.Build();
sevenDays = Builder<Episode>.CreateNew()
.With(c => c.AirDate = DateTime.Today.AddDays(7))
.With(c => c.Title = "Seven Days")
.With(c => c.SeriesId = 1)
.Build();
sevenDays = Builder<Episode>.CreateNew()
.With(c => c.AirDate = DateTime.Today.AddDays(8))
.With(c => c.Title = "Eight Days")
.With(c => c.SeriesId = 1)
.Build(); .Build();
series = Builder<Series>.CreateNew().With(s => s.SeriesId = 1).Build(); series = Builder<Series>.CreateNew().With(s => s.SeriesId = 1).Build();
@ -74,21 +52,17 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(database); mocker.SetConstant(database);
database.Insert(yesterday); database.InsertMany(episodes);
database.Insert(today);
database.Insert(tomorrow);
database.Insert(twoDays);
database.Insert(sevenDays);
database.Insert(series); database.Insert(series);
//Act //Act
var result = mocker.Resolve<UpcomingEpisodesProvider>().Yesterday(); var result = mocker.Resolve<UpcomingEpisodesProvider>().Yesterday();
//Assert //Assert
Assert.AreEqual(1, result.Count); result.Should().HaveCount(1);
Assert.AreEqual(yesterday.Title, result[0].Title); result.First().Title.Should().Be(episodes.Where(e => e.AirDate == DateTime.Today.AddDays(-1)).First().Title);
result[0].Series.Should().NotBeNull(); result.First().Series.Should().NotBeNull();
result[0].Series.SeriesId.Should().NotBe(0); result.First().Series.SeriesId.Should().NotBe(0);
} }
[Test] [Test]
@ -99,21 +73,17 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(database); mocker.SetConstant(database);
database.Insert(yesterday); database.InsertMany(episodes);
database.Insert(today);
database.Insert(tomorrow);
database.Insert(twoDays);
database.Insert(sevenDays);
database.Insert(series); database.Insert(series);
//Act //Act
var result = mocker.Resolve<UpcomingEpisodesProvider>().Today(); var result = mocker.Resolve<UpcomingEpisodesProvider>().Today();
//Assert //Assert
Assert.AreEqual(1, result.Count); result.Should().HaveCount(1);
Assert.AreEqual(today.Title, result[0].Title); result.First().Title.Should().Be(episodes.Where(e => e.AirDate == DateTime.Today).First().Title);
result[0].Series.Should().NotBeNull(); result.First().Series.Should().NotBeNull();
result[0].Series.SeriesId.Should().NotBe(0); result.First().Series.SeriesId.Should().NotBe(0);
} }
[Test] [Test]
@ -124,21 +94,17 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(database); mocker.SetConstant(database);
database.Insert(yesterday); database.InsertMany(episodes);
database.Insert(today);
database.Insert(tomorrow);
database.Insert(twoDays);
database.Insert(sevenDays);
database.Insert(series); database.Insert(series);
//Act //Act
var result = mocker.Resolve<UpcomingEpisodesProvider>().Tomorrow(); var result = mocker.Resolve<UpcomingEpisodesProvider>().Tomorrow();
//Assert //Assert
Assert.AreEqual(1, result.Count); result.Should().HaveCount(1);
Assert.AreEqual(tomorrow.Title, result[0].Title); result.First().Title.Should().Be(episodes.Where(e => e.AirDate == DateTime.Today.AddDays(1)).First().Title);
result[0].Series.Should().NotBeNull(); result.First().Series.Should().NotBeNull();
result[0].Series.SeriesId.Should().NotBe(0); result.First().Series.SeriesId.Should().NotBe(0);
} }
[Test] [Test]
@ -149,22 +115,18 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(database); mocker.SetConstant(database);
database.Insert(yesterday); database.InsertMany(episodes);
database.Insert(today);
database.Insert(tomorrow);
database.Insert(twoDays);
database.Insert(sevenDays);
database.Insert(series); database.Insert(series);
//Act //Act
var result = mocker.Resolve<UpcomingEpisodesProvider>().Week(); var result = mocker.Resolve<UpcomingEpisodesProvider>().Week();
//Assert //Assert
Assert.AreEqual(2, result.Count); result.Should().HaveCount(2);
result[0].Series.Should().NotBeNull(); result.First().Series.Should().NotBeNull();
result[0].Series.SeriesId.Should().NotBe(0); result.First().Series.SeriesId.Should().NotBe(0);
result[1].Series.Should().NotBeNull(); result.Last().Series.Should().NotBeNull();
result[1].Series.SeriesId.Should().NotBe(0); result.Last().Series.SeriesId.Should().NotBe(0);
} }
} }
} }

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using NzbDrone.Core;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Web.Models; using NzbDrone.Web.Models;
using Telerik.Web.Mvc; using Telerik.Web.Mvc;
@ -37,7 +38,10 @@ namespace NzbDrone.Web.Controllers
EpisodeNumber = u.EpisodeNumber, EpisodeNumber = u.EpisodeNumber,
Title = u.Title, Title = u.Title,
Overview = u.Overview, Overview = u.Overview,
AirDate = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) AirDateTime = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay),
AirDate = u.AirDate.Value.ToBestDateString(),
AirTime = Convert.ToDateTime(u.Series.AirTimes).ToShortTimeString(),
Status = u.Status.ToString()
}); });
return View(new GridModel(upcoming)); return View(new GridModel(upcoming));
@ -55,7 +59,10 @@ namespace NzbDrone.Web.Controllers
EpisodeNumber = u.EpisodeNumber, EpisodeNumber = u.EpisodeNumber,
Title = u.Title, Title = u.Title,
Overview = u.Overview, Overview = u.Overview,
AirDate = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) AirDateTime = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay),
AirDate = u.AirDate.Value.ToBestDateString(),
AirTime = Convert.ToDateTime(u.Series.AirTimes).ToShortTimeString(),
Status = u.Status.ToString()
}); });
return View(new GridModel(upcoming)); return View(new GridModel(upcoming));
@ -73,7 +80,10 @@ namespace NzbDrone.Web.Controllers
EpisodeNumber = u.EpisodeNumber, EpisodeNumber = u.EpisodeNumber,
Title = u.Title, Title = u.Title,
Overview = u.Overview, Overview = u.Overview,
AirDate = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) AirDateTime = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay),
AirDate = u.AirDate.Value.ToBestDateString(),
AirTime = Convert.ToDateTime(u.Series.AirTimes).ToShortTimeString(),
Status = u.Status.ToString()
}); });
return View(new GridModel(upcoming)); return View(new GridModel(upcoming));
@ -91,7 +101,10 @@ namespace NzbDrone.Web.Controllers
EpisodeNumber = u.EpisodeNumber, EpisodeNumber = u.EpisodeNumber,
Title = u.Title, Title = u.Title,
Overview = u.Overview, Overview = u.Overview,
AirDate = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) AirDateTime = u.AirDate.Value.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay),
AirDate = u.AirDate.Value.ToBestDateString(),
AirTime = Convert.ToDateTime(u.Series.AirTimes).ToShortTimeString(),
Status = u.Status.ToString()
}); });
return View(new GridModel(upcoming)); return View(new GridModel(upcoming));

@ -1,4 +1,5 @@
using System; using System;
using NzbDrone.Core.Model;
namespace NzbDrone.Web.Models namespace NzbDrone.Web.Models
{ {
@ -11,6 +12,9 @@ namespace NzbDrone.Web.Models
public int EpisodeNumber { get; set; } public int EpisodeNumber { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public DateTime AirDate { get; set; } public DateTime AirDateTime { get; set; }
public string AirDate { get; set; }
public string AirTime { get; set; }
public string Status { get; set; }
} }
} }

@ -69,14 +69,14 @@
padding: 0.3em 0.9em 1.0em 0.6em; padding: 0.3em 0.9em 1.0em 0.6em;
} }
.t-grid .t-alt .t-grid .t-detail-cell
{ {
/*background: #E5ECF9;*/ line-height: 1.5em;
} }
.t-grid .t-detail-cell .t-grid td
{ {
line-height: 1.5em; padding: 0 0.6em;
} }
#banner-container #banner-container

@ -3,6 +3,50 @@
@section TitleContent{ @section TitleContent{
Upcoming Upcoming
} }
<style>
.statusImage, .searchImage, .renameImage, .ignoreEpisode, .ignoreEpisodesMaster
{
width: 18px;
height: 18px;
padding: 1px;
margin: 2px;
border-width: 1px;
border-style: dashed;
border-color: lightgray;
}
.searchImage:hover, .renameImage:hover, .ignoreEpisode:hover, .ignoreEpisodesMaster:hover
{
background-color: #065EFE;
}
.t-grid td
{
line-height: 0.6em;
}
.t-grid .t-header
{
line-height: 1.8em;
}
.t-grid-header .t-header .t-link
{
padding: 0.3em 0.9em 1.0em 0.6em;
}
.t-grid .t-detail-cell
{
line-height: 1.5em;
}
.t-grid td
{
padding: 0 0.6em;
}
</style>
@section ActionMenu{ @section ActionMenu{
<ul class="sub-menu"> <ul class="sub-menu">
<li>@Ajax.ActionLink("Start RSS Sync", "RssSync", "Command", null, null)</li> <li>@Ajax.ActionLink("Start RSS Sync", "RssSync", "Command", null, null)</li>
@ -25,7 +69,13 @@ Upcoming
columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40); columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40);
columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40); columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40);
columns.Bound(c => c.Title).Title("Episode Title"); columns.Bound(c => c.Title).Title("Episode Title");
columns.Bound(c => c.AirDate).Title("Air Date").Width(160); columns.Bound(c => c.AirDateTime).Title("Air Time")
.ClientTemplate("<#= AirTime #>")
.Width(160);
columns.Bound(c => c.Status)
.ClientTemplate("<img src='../../Content/Images/<#= Status #>.png' alt='<#= Status #>' title='<#= Status #>' class='statusImage status-<#= Status #>' />" +
"<a href=\"../Episode/Season?episodeId=<#= EpisodeId #>\" onclick=\"searchForEpisode('<#= EpisodeId #>'); return false;\"><img src='../../Content/Images/Search.png' alt='Search' title='Search for episode' class='searchImage' /></a>"
);
}) })
.DetailView(detailView => detailView.ClientTemplate( .DetailView(detailView => detailView.ClientTemplate(
"<fieldset>" + "<fieldset>" +
@ -33,7 +83,7 @@ Upcoming
"</fieldset>" "</fieldset>"
)) ))
.DataBinding(data => data.Ajax().Select("_AjaxBindingYesterday", "Upcoming")) .DataBinding(data => data.Ajax().Select("_AjaxBindingYesterday", "Upcoming"))
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDate).Ascending()).Enabled(true)) .Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDateTime).Ascending()).Enabled(true))
//.Pageable(c => c.PageSize(20).Position(GridPagerPosition.Both).Style(GridPagerStyles.PageInput | GridPagerStyles.NextPreviousAndNumeric)) //.Pageable(c => c.PageSize(20).Position(GridPagerPosition.Both).Style(GridPagerStyles.PageInput | GridPagerStyles.NextPreviousAndNumeric))
//.Filterable() //.Filterable()
//.ClientEvents(c => c.OnRowDataBound("onRowDataBound")) //.ClientEvents(c => c.OnRowDataBound("onRowDataBound"))
@ -56,7 +106,13 @@ Upcoming
columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40); columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40);
columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40); columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40);
columns.Bound(c => c.Title).Title("Episode Title"); columns.Bound(c => c.Title).Title("Episode Title");
columns.Bound(c => c.AirDate).Title("Air Date").Width(160); columns.Bound(c => c.AirDateTime).Title("Air Time")
.ClientTemplate("<#= AirTime #>")
.Width(160);
columns.Bound(c => c.Status)
.ClientTemplate("<img src='../../Content/Images/<#= Status #>.png' alt='<#= Status #>' title='<#= Status #>' class='statusImage status-<#= Status #>' />" +
"<a href=\"../Episode/Season?episodeId=<#= EpisodeId #>\" onclick=\"searchForEpisode('<#= EpisodeId #>'); return false;\"><img src='../../Content/Images/Search.png' alt='Search' title='Search for episode' class='searchImage' /></a>"
);
}) })
.DetailView(detailView => detailView.ClientTemplate( .DetailView(detailView => detailView.ClientTemplate(
"<fieldset>" + "<fieldset>" +
@ -64,7 +120,7 @@ Upcoming
"</fieldset>" "</fieldset>"
)) ))
.DataBinding(data => data.Ajax().Select("_AjaxBindingToday", "Upcoming")) .DataBinding(data => data.Ajax().Select("_AjaxBindingToday", "Upcoming"))
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDate).Ascending()).Enabled(true)) .Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDateTime).Ascending()).Enabled(true))
.Render();} .Render();}
</div> </div>
</div> </div>
@ -85,7 +141,13 @@ Upcoming
columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40); columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40);
columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40); columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40);
columns.Bound(c => c.Title).Title("Episode Title"); columns.Bound(c => c.Title).Title("Episode Title");
columns.Bound(c => c.AirDate).Title("Air Date").Width(160); columns.Bound(c => c.AirDateTime).Title("Air Time")
.ClientTemplate("<#= AirTime #>")
.Width(160);
columns.Bound(c => c.Status)
.ClientTemplate("<img src='../../Content/Images/<#= Status #>.png' alt='<#= Status #>' title='<#= Status #>' class='statusImage status-<#= Status #>' />" +
"<a href=\"../Episode/Season?episodeId=<#= EpisodeId #>\" onclick=\"searchForEpisode('<#= EpisodeId #>'); return false;\"><img src='../../Content/Images/Search.png' alt='Search' title='Search for episode' class='searchImage' /></a>"
);
}) })
.DetailView(detailView => detailView.ClientTemplate( .DetailView(detailView => detailView.ClientTemplate(
"<fieldset>" + "<fieldset>" +
@ -94,7 +156,7 @@ Upcoming
)) ))
.DataBinding(data => data.Ajax().Select("_AjaxBindingTomorrow", "Upcoming")) .DataBinding(data => data.Ajax().Select("_AjaxBindingTomorrow", "Upcoming"))
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDate).Ascending()).Enabled(true)) .Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDateTime).Ascending()).Enabled(true))
.Render();} .Render();}
</div> </div>
</div> </div>
@ -115,7 +177,13 @@ Upcoming
columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40); columns.Bound(c => c.SeasonNumber).Title("Season #").Width(40);
columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40); columns.Bound(c => c.EpisodeNumber).Title("Episode #").Width(40);
columns.Bound(c => c.Title).Title("Episode Title"); columns.Bound(c => c.Title).Title("Episode Title");
columns.Bound(c => c.AirDate).Title("Air Date").Width(160); columns.Bound(c => c.AirDateTime).Title("Air Date/Time")
.ClientTemplate("<#= AirDate #> at <#= AirTime #>")
.Width(160);
columns.Bound(c => c.Status)
.ClientTemplate("<img src='../../Content/Images/<#= Status #>.png' alt='<#= Status #>' title='<#= Status #>' class='statusImage status-<#= Status #>' />" +
"<a href=\"../Episode/Season?episodeId=<#= EpisodeId #>\" onclick=\"searchForEpisode('<#= EpisodeId #>'); return false;\"><img src='../../Content/Images/Search.png' alt='Search' title='Search for episode' class='searchImage' /></a>"
);
}) })
.DetailView(detailView => detailView.ClientTemplate( .DetailView(detailView => detailView.ClientTemplate(
"<fieldset>" + "<fieldset>" +
@ -123,7 +191,7 @@ Upcoming
"</fieldset>" "</fieldset>"
)) ))
.DataBinding(data => data.Ajax().Select("_AjaxBindingWeek", "Upcoming")) .DataBinding(data => data.Ajax().Select("_AjaxBindingWeek", "Upcoming"))
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDate).Ascending()).Enabled(true)) .Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.AirDateTime).Ascending()).Enabled(true))
.Render();} .Render();}
</div> </div>
</div> </div>

Loading…
Cancel
Save