mirror of https://github.com/Sonarr/Sonarr
Log Grid added, using server side filtering, sorting and paging. Using DynamicQueryable.
This commit is contained in:
parent
ca5888160d
commit
9c24b5989b
|
@ -0,0 +1,15 @@
|
|||
using System.Web.Mvc;
|
||||
using System.Web.WebPages;
|
||||
using NzbDrone.Web.Helpers;
|
||||
using NzbDrone.Web.Models;
|
||||
|
||||
[assembly: WebActivator.PreApplicationStartMethod(typeof(NzbDrone.Web.App_Start.RegisterDatatablesModelBinder), "Start")]
|
||||
|
||||
namespace NzbDrone.Web.App_Start {
|
||||
public static class RegisterDatatablesModelBinder {
|
||||
public static void Start() {
|
||||
if (!ModelBinders.Binders.ContainsKey(typeof(DataTablesParams)))
|
||||
ModelBinders.Binders.Add(typeof(DataTablesParams), new DataTablesModelBinder());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using NzbDrone.Common;
|
||||
|
@ -26,6 +29,11 @@ namespace NzbDrone.Web.Controllers
|
|||
return View();
|
||||
}
|
||||
|
||||
public ActionResult IndexOld()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public FileContentResult File()
|
||||
{
|
||||
string log = string.Empty;
|
||||
|
@ -47,8 +55,56 @@ namespace NzbDrone.Web.Controllers
|
|||
return JsonNotificationResult.Info("Logs Cleared");
|
||||
}
|
||||
|
||||
public ActionResult AjaxBinding(DataTablesParams dataTablesParams)
|
||||
{
|
||||
var logs = _logProvider.GetAllLogs();
|
||||
var totalCount = logs.Count();
|
||||
|
||||
IQueryable<Log> q = logs;
|
||||
if (!string.IsNullOrEmpty(dataTablesParams.sSearch))
|
||||
{
|
||||
q = q.Where(b => b.Logger.Contains(dataTablesParams.sSearch)
|
||||
|| b.Exception.Contains(dataTablesParams.sSearch)
|
||||
|| b.Message.Contains(dataTablesParams.sSearch));
|
||||
}
|
||||
|
||||
int filteredCount = q.Count();
|
||||
|
||||
int sortCol = dataTablesParams.iSortCol.First();
|
||||
var sortColName = sortCol == 0 ? "Time" : sortCol == 1 ? "Level" : "Logger";
|
||||
var sortExpression = String.Format("{0} {1}", sortColName, dataTablesParams.sSortDir.First());
|
||||
|
||||
var sorted = q.OrderBy(sortExpression);
|
||||
|
||||
IQueryable<Log> filteredAndSorted = sorted;
|
||||
if (filteredCount > dataTablesParams.iDisplayLength)
|
||||
{
|
||||
filteredAndSorted = sorted.Skip(dataTablesParams.iDisplayStart).Take(dataTablesParams.iDisplayLength);
|
||||
}
|
||||
|
||||
var logModels = filteredAndSorted.ToList().Select(s => new LogModel
|
||||
{
|
||||
Time = s.Time.ToString(),
|
||||
Level = s.Level,
|
||||
Source = s.Logger,
|
||||
Message = s.Message,
|
||||
Method = s.Method,
|
||||
ExceptionType = s.ExceptionType,
|
||||
Exception = s.Exception
|
||||
});
|
||||
|
||||
return Json(new
|
||||
{
|
||||
sEcho = dataTablesParams.sEcho,
|
||||
iTotalRecords = totalCount,
|
||||
iTotalDisplayRecords = filteredCount,
|
||||
aaData = logModels
|
||||
},
|
||||
JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[GridAction]
|
||||
public ActionResult AjaxBinding()
|
||||
public ActionResult AjaxBindingOld()
|
||||
{
|
||||
return View(new GridModel(_logProvider.GetAllLogs()));
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using NzbDrone.Web.Models;
|
||||
|
||||
namespace NzbDrone.Web.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Model binder for datatables.js parameters a la http://geeksprogramando.blogspot.com/2011/02/jquery-datatables-plug-in-with-asp-mvc.html
|
||||
/// </summary>
|
||||
public class DataTablesModelBinder : IModelBinder
|
||||
{
|
||||
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
|
||||
{
|
||||
DataTablesParams obj = new DataTablesParams();
|
||||
var request = controllerContext.HttpContext.Request.Params;
|
||||
|
||||
obj.iDisplayStart = Convert.ToInt32(request["iDisplayStart"]);
|
||||
obj.iDisplayLength = Convert.ToInt32(request["iDisplayLength"]);
|
||||
obj.iColumns = Convert.ToInt32(request["iColumns"]);
|
||||
obj.sSearch = request["sSearch"];
|
||||
obj.bEscapeRegex = Convert.ToBoolean(request["bEscapeRegex"]);
|
||||
obj.iSortingCols = Convert.ToInt32(request["iSortingCols"]);
|
||||
obj.sEcho = int.Parse(request["sEcho"]);
|
||||
|
||||
for (int i = 0; i < obj.iColumns; i++)
|
||||
{
|
||||
obj.bSortable.Add(Convert.ToBoolean(request["bSortable_" + i]));
|
||||
obj.bSearchable.Add(Convert.ToBoolean(request["bSearchable_" + i]));
|
||||
obj.sSearchColumns.Add(request["sSearch_" + i]);
|
||||
obj.bEscapeRegexColumns.Add(Convert.ToBoolean(request["bEscapeRegex_" + i]));
|
||||
obj.iSortCol.Add(Convert.ToInt32(request["iSortCol_" + i]));
|
||||
obj.sSortDir.Add(request["sSortDir_" + i]);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace NzbDrone.Web.Models
|
||||
{
|
||||
public class DataTablesParams
|
||||
{
|
||||
public int iDisplayStart { get; set; }
|
||||
public int iDisplayLength { get; set; }
|
||||
public int iColumns { get; set; }
|
||||
public string sSearch { get; set; }
|
||||
public bool bEscapeRegex { get; set; }
|
||||
public int iSortingCols { get; set; }
|
||||
public int sEcho { get; set; }
|
||||
public List<bool> bSortable { get; set; }
|
||||
public List<bool> bSearchable { get; set; }
|
||||
public List<string> sSearchColumns { get; set; }
|
||||
public List<int> iSortCol { get; set; }
|
||||
public List<string> sSortDir { get; set; }
|
||||
public List<bool> bEscapeRegexColumns { get; set; }
|
||||
|
||||
public DataTablesParams()
|
||||
{
|
||||
bSortable = new List<bool>();
|
||||
bSearchable = new List<bool>();
|
||||
sSearchColumns = new List<string>();
|
||||
iSortCol = new List<int>();
|
||||
sSortDir = new List<string>();
|
||||
bEscapeRegexColumns = new List<bool>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace NzbDrone.Web.Models
|
||||
{
|
||||
public class LogModel
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public string Time { get; set; }
|
||||
public string Source { get; set; }
|
||||
public string Method { get; set; }
|
||||
public string Exception { get; set; }
|
||||
public string ExceptionType { get; set; }
|
||||
public string Level { get; set; }
|
||||
public string Details { get; set; }
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@
|
|||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Dynamic">
|
||||
<HintPath>..\packages\DynamicQuery.1.0\lib\35\Dynamic.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EntityFramework, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EntityFramework.4.2.0.0\lib\net40\EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -270,6 +273,7 @@
|
|||
<Compile Include="App_Start\EntityFramework.SqlServerCompact.cs" />
|
||||
<Compile Include="App_Start\Logging.cs" />
|
||||
<Compile Include="App_Start\MiniProfiler.cs" />
|
||||
<Compile Include="App_Start\RegisterDataTablesModelBinder.cs" />
|
||||
<Compile Include="Filters\JsonErrorFilter.cs" />
|
||||
<Compile Include="Controllers\CommandController.cs" />
|
||||
<Compile Include="Controllers\DirectoryController.cs" />
|
||||
|
@ -290,6 +294,7 @@
|
|||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Helpers\DataTablesModelBinder.cs" />
|
||||
<Compile Include="Helpers\HtmlIncludeExtentions.cs" />
|
||||
<Compile Include="Helpers\LinkHelper.cs" />
|
||||
<Compile Include="Helpers\ProfilerHelper.cs" />
|
||||
|
@ -297,6 +302,8 @@
|
|||
<Compile Include="Helpers\DescriptionExtension.cs" />
|
||||
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
|
||||
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
|
||||
<Compile Include="Models\DataTablesParams.cs" />
|
||||
<Compile Include="Models\LogModel.cs" />
|
||||
<Compile Include="Models\UpcomingEpisodesModel.cs" />
|
||||
<Compile Include="Models\SeasonModel.cs" />
|
||||
<Compile Include="Models\SeriesDetailsModel.cs" />
|
||||
|
@ -410,6 +417,7 @@
|
|||
<Content Include="Content\themes\base\minified\jquery.ui.slider.min.css" />
|
||||
<Content Include="Content\themes\base\minified\jquery.ui.tabs.min.css" />
|
||||
<Content Include="Content\themes\base\minified\jquery.ui.theme.min.css" />
|
||||
<Content Include="Dynamic Expressions.html" />
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Scripts\2011.3.1115\jquery-1.6.4.min.js" />
|
||||
|
@ -680,6 +688,7 @@
|
|||
<None Include="Scripts\DataTables-1.9.0\extras\FixedColumns\media\js\FixedColumns.min.js.gz" />
|
||||
<None Include="Scripts\DataTables-1.9.0\extras\Scroller\media\js\Scroller.min.js.gz" />
|
||||
<None Include="Scripts\DataTables-1.9.0\extras\TableTools\media\js\TableTools.min.js.gz" />
|
||||
<None Include="Views\Log\IndexOld.cshtml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
}
|
||||
|
||||
<div class="grid-container">
|
||||
<table id="historyGrid" class="hidden-grid">
|
||||
<table id="historyGrid" class="dataTablesGrid hidden-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
@ -33,10 +33,6 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@*@foreach(var history in Model)
|
||||
{
|
||||
Html.RenderPartial("History", history);
|
||||
}*@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -53,7 +49,7 @@
|
|||
$(document).ready(function () {
|
||||
$('#historyGrid').removeClass('hidden-grid');
|
||||
|
||||
oTable = $('#historyGrid').dataTable({
|
||||
oTable = $('.dataTablesGrid').dataTable({
|
||||
//"sAjaxSource": "History/AjaxBinding",
|
||||
//"bProcessing": true,
|
||||
"bShowAll": false,
|
||||
|
|
|
@ -2,26 +2,6 @@
|
|||
@using NzbDrone.Core.Instrumentation
|
||||
@using NzbDrone.Web.Helpers
|
||||
@model IEnumerable<NzbDrone.Core.Instrumentation.Log>
|
||||
@section Scripts{
|
||||
<script type="text/javascript">
|
||||
function onRowDataBound(e) {
|
||||
|
||||
e.row.style.boarder = "";
|
||||
|
||||
if (e.dataItem.Level == "Warn") {
|
||||
e.row.style.backgroundColor = "#FFD700";
|
||||
}
|
||||
else if (e.dataItem.Level == "Error") {
|
||||
e.row.style.backgroundColor = "#FF7500";
|
||||
}
|
||||
else if (e.dataItem.Level == "Fatal") {
|
||||
e.row.style.backgroundColor = "black";
|
||||
e.row.style.color = "red";
|
||||
}
|
||||
//e.row.style.color = 'blue';
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@{ ViewBag.Title = "Logs";}
|
||||
@section ActionMenu{
|
||||
<ul class="sub-menu">
|
||||
|
@ -29,37 +9,86 @@
|
|||
<li>@Html.ActionLink("File", "File", "Log")</li>
|
||||
</ul>
|
||||
}
|
||||
|
||||
@section HeaderContent{
|
||||
<style>
|
||||
#logGrid td {
|
||||
padding: 2px 8px 2px 8px;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<div class="infoBox">
|
||||
Log entries older than 30 days are automatically deleted.</div>
|
||||
@{Html.Telerik().Grid<Log>().Name("logsGrid")
|
||||
.TableHtmlAttributes(new { @class = "Grid" })
|
||||
.Columns(columns =>
|
||||
{
|
||||
columns.Bound(c => c.Time).Title("Time").Width(170);
|
||||
columns.Bound(c => c.Level).Title("Level").Width(70);
|
||||
columns.Bound(c => c.Logger).Title("Source");
|
||||
columns.Bound(c => c.Message);
|
||||
})
|
||||
.DetailView(detailView => detailView.ClientTemplate(
|
||||
"<div>Method: <#= Method #></div>" +
|
||||
"<div><#= ExceptionType #></div>" +
|
||||
"<div class='stackframe'><#= Exception #></div>"
|
||||
))
|
||||
.DataBinding(data => data.Ajax().Select("AjaxBinding", "Log").Enabled(true))
|
||||
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.Time).Descending()).Enabled(true))
|
||||
.Pageable(paging => paging.Style(GridPagerStyles.Status).PageOnScroll(true).PageSize(100))
|
||||
.Filterable()
|
||||
.ClientEvents(c => c.OnRowDataBound("onRowDataBound"))
|
||||
.Scrollable(c => c.Height(500))
|
||||
.ClientEvents(clientEvents =>
|
||||
{
|
||||
if (EnviromentProvider.IsProduction)
|
||||
clientEvents.OnError("grid_onError");
|
||||
})
|
||||
.Render();}
|
||||
|
||||
<div class="grid-container">
|
||||
<table id="logGrid" class="dataTablesGrid hidden-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Level</th>
|
||||
<th>Source</th>
|
||||
<th>Message</th>
|
||||
@*Details Column*@
|
||||
<th style="display: none;">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@section Scripts{
|
||||
<script type="text/javascript">
|
||||
function reloadGrid() {
|
||||
var grid = $('#logsGrid').data('tGrid');
|
||||
grid.rebind();
|
||||
$(document).ready(function() {
|
||||
$('.dataTablesGrid').removeClass('hidden-grid');
|
||||
|
||||
oTable = $('#logGrid').dataTable({
|
||||
"sAjaxSource": "Log/AjaxBinding",
|
||||
"bProcessing": true,
|
||||
"bServerSide": true,
|
||||
"bShowAll": false,
|
||||
"bPaginate": true,
|
||||
"bLengthChange": false,
|
||||
"bFilter": true,
|
||||
"bSort": true,
|
||||
"bInfo": true,
|
||||
"bAutoWidth": false,
|
||||
"iDisplayLength": 50,
|
||||
"sPaginationType": "four_button",
|
||||
"aoColumns": [
|
||||
{ sWidth: '150px', "mDataProp": "Time" }, //Time
|
||||
{ sWidth: '80px', "mDataProp": "Level" }, //Level
|
||||
{ sWidth: '240px', "mDataProp": "Source" }, //Source
|
||||
{ sWidth: 'auto', "mDataProp": "Message", "bSortable": false }, //Message
|
||||
{ sWidth: 'auto', "mDataProp": "Details", "bSortable": false, "bVisible": false, "fnRender": function (row) {
|
||||
var result = "<div>Method: " + row.aData["Method"] + "</div>" +
|
||||
"<div>Exception Type: " + row.aData["ExceptionType"] + "</div>" +
|
||||
"<div class=\"stackFrame\">Exception: " + row.aData["Exception"] + "</div>";
|
||||
return result;
|
||||
}
|
||||
} //Details
|
||||
],
|
||||
"aaSorting": [[0, 'desc']],
|
||||
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull) {
|
||||
fnRowCallback(nRow, aData);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function fnRowCallback(nRow, aData) {
|
||||
//e.row.style.boarder = "";
|
||||
|
||||
if (aData["Level"] == "Warn") {
|
||||
nRow.style.backgroundColor = "#FFD700";
|
||||
}
|
||||
else if (aData["Level"] == "Error") {
|
||||
nRow.style.backgroundColor = "#FF7500";
|
||||
}
|
||||
else if (aData["Level"] == "Fatal") {
|
||||
nRow.style.backgroundColor = "black";
|
||||
nRow.style.color = "red";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
@using NzbDrone.Common
|
||||
@using NzbDrone.Core.Instrumentation
|
||||
@using NzbDrone.Web.Helpers
|
||||
@model IEnumerable<NzbDrone.Core.Instrumentation.Log>
|
||||
@section Scripts{
|
||||
<script type="text/javascript">
|
||||
function onRowDataBound(e) {
|
||||
|
||||
e.row.style.boarder = "";
|
||||
|
||||
if (e.dataItem.Level == "Warn") {
|
||||
e.row.style.backgroundColor = "#FFD700";
|
||||
}
|
||||
else if (e.dataItem.Level == "Error") {
|
||||
e.row.style.backgroundColor = "#FF7500";
|
||||
}
|
||||
else if (e.dataItem.Level == "Fatal") {
|
||||
e.row.style.backgroundColor = "black";
|
||||
e.row.style.color = "red";
|
||||
}
|
||||
//e.row.style.color = 'blue';
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@{ ViewBag.Title = "Logs";}
|
||||
@section ActionMenu{
|
||||
<ul class="sub-menu">
|
||||
<li>@Ajax.ActionLink("Clear Logs", "Clear", "Log", new AjaxOptions { OnSuccess = "reloadGrid" })</li>
|
||||
<li>@Html.ActionLink("File", "File", "Log")</li>
|
||||
</ul>
|
||||
}
|
||||
<div class="infoBox">
|
||||
Log entries older than 30 days are automatically deleted.</div>
|
||||
@{Html.Telerik().Grid<Log>().Name("logsGrid")
|
||||
.TableHtmlAttributes(new { @class = "Grid" })
|
||||
.Columns(columns =>
|
||||
{
|
||||
columns.Bound(c => c.Time).Title("Time").Width(170);
|
||||
columns.Bound(c => c.Level).Title("Level").Width(70);
|
||||
columns.Bound(c => c.Logger).Title("Source");
|
||||
columns.Bound(c => c.Message);
|
||||
})
|
||||
.DetailView(detailView => detailView.ClientTemplate(
|
||||
"<div>Method: <#= Method #></div>" +
|
||||
"<div><#= ExceptionType #></div>" +
|
||||
"<div class='stackframe'><#= Exception #></div>"
|
||||
))
|
||||
.DataBinding(data => data.Ajax().Select("AjaxBindingOld", "Log").Enabled(true))
|
||||
.Sortable(rows => rows.OrderBy(epSort => epSort.Add(c => c.Time).Descending()).Enabled(true))
|
||||
.Pageable(paging => paging.Style(GridPagerStyles.Status).PageOnScroll(true).PageSize(100))
|
||||
.Filterable()
|
||||
.ClientEvents(c => c.OnRowDataBound("onRowDataBound"))
|
||||
.Scrollable(c => c.Height(500))
|
||||
.ClientEvents(clientEvents =>
|
||||
{
|
||||
if (EnviromentProvider.IsProduction)
|
||||
clientEvents.OnError("grid_onError");
|
||||
})
|
||||
.Render();}
|
||||
<script type="text/javascript">
|
||||
function reloadGrid() {
|
||||
var grid = $('#logsGrid').data('tGrid');
|
||||
grid.rebind();
|
||||
}
|
||||
</script>
|
|
@ -16,7 +16,7 @@
|
|||
}
|
||||
|
||||
<div class="grid-container">
|
||||
<table id="historyGrid" class="hidden-grid">
|
||||
<table id="missingGrid" class="dataTablesGrid hidden-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Series Title</th>
|
||||
|
@ -44,7 +44,7 @@
|
|||
$(document).ready(function () {
|
||||
$('#historyGrid').removeClass('hidden-grid');
|
||||
|
||||
oTable = $('#historyGrid').dataTable({
|
||||
oTable = $('.dataTablesGrid').dataTable({
|
||||
//"sAjaxSource": "History/AjaxBinding",
|
||||
//"bProcessing": true,
|
||||
"bShowAll": false,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="DynamicQuery" version="1.0" />
|
||||
<package id="EntityFramework" version="4.2.0.0" />
|
||||
<package id="EntityFramework.SqlServerCompact" version="4.1.8482.2" />
|
||||
<package id="jQuery" version="1.6.1" />
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in New Issue