diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 0eb47a119..6507a24a8 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -138,9 +138,9 @@ False ..\Libraries\Migrator.NET\Migrator.Providers.dll - + False - ..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll + ..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll ..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser.cs index 0d983fd6b..dc4a7e441 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser.cs @@ -398,5 +398,16 @@ namespace NzbDrone.Core return info.FullName.Trim('/', '\\', ' '); } + + public static string UppercaseFirst(string s) + { + // Check for empty string. + if (string.IsNullOrEmpty(s)) + { + return string.Empty; + } + // Return char and concat substring. + return char.ToUpper(s[0]) + s.Substring(1); + } } } diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index a3284ed86..416def223 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -197,12 +197,12 @@ namespace NzbDrone.Core.Providers Logger.Trace("Updating info for [{0}] - S{1}E{2}", tvDbSeriesInfo.SeriesName, episode.SeasonNumber, episode.EpisodeNumber); //first check using tvdbId, this should cover cases when and episode number in a season is changed - var episodeToUpdate = seriesEpisodes.Where(e => e.TvDbEpisodeId == episode.Id).FirstOrDefault(); + var episodeToUpdate = seriesEpisodes.Where(e => e.TvDbEpisodeId == episode.Id).SingleOrDefault(); //not found, try using season/episode number if (episodeToUpdate == null) { - episodeToUpdate = seriesEpisodes.Where(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber).FirstOrDefault(); + episodeToUpdate = seriesEpisodes.Where(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber).SingleOrDefault(); } //Episode doesn't exist locally diff --git a/NzbDrone.Core/Providers/Jobs/JobProvider.cs b/NzbDrone.Core/Providers/Jobs/JobProvider.cs index 4c15457b1..549fbd6fa 100644 --- a/NzbDrone.Core/Providers/Jobs/JobProvider.cs +++ b/NzbDrone.Core/Providers/Jobs/JobProvider.cs @@ -171,31 +171,34 @@ namespace NzbDrone.Core.Providers.Jobs { Tuple job = null; - try + using (NestedDiagnosticsContext.Push(Guid.NewGuid().ToString())) { - lock (Queue) + try { - if (Queue.Count != 0) + lock (Queue) { - job = Queue.First(); + if (Queue.Count != 0) + { + job = Queue.First(); + } + } + + if (job != null) + { + Execute(job.Item1, job.Item2); } - } - if (job != null) + } + catch (Exception e) { - Execute(job.Item1, job.Item2); + Logger.FatalException("An error has occurred while processing queued job.", e); } - - } - catch (Exception e) - { - Logger.FatalException("An error has occurred while processing queued job.", e); - } - finally - { - if (job != null) + finally { - Queue.Remove(job); + if (job != null) + { + Queue.Remove(job); + } } } @@ -214,14 +217,14 @@ namespace NzbDrone.Core.Providers.Jobs /// to allow it to filter it's target of execution private void Execute(Type jobType, int targetId = 0) { - var jobImplementation = _jobs.Where(t => t.GetType() == jobType).FirstOrDefault(); + var jobImplementation = _jobs.Where(t => t.GetType() == jobType).Single(); if (jobImplementation == null) { Logger.Error("Unable to locate implementation for '{0}'. Make sure it is properly registered.", jobType); return; } - var settings = All().Where(j => j.TypeName == jobType.ToString()).FirstOrDefault(); + var settings = All().Where(j => j.TypeName == jobType.ToString()).Single(); using (_notification = new ProgressNotification(jobImplementation.Name)) { @@ -294,11 +297,7 @@ namespace NzbDrone.Core.Providers.Jobs /// DateTime of next scheduled job execution public virtual DateTime NextScheduledRun(Type jobType) { - var job = All().Where(t => t.TypeName == jobType.ToString()).FirstOrDefault(); - - if (job == null) - return DateTime.Now; - + var job = All().Where(t => t.TypeName == jobType.ToString()).Single(); return job.LastExecution.AddMinutes(job.Interval); } } diff --git a/NzbDrone.Core/Providers/RootDirProvider.cs b/NzbDrone.Core/Providers/RootDirProvider.cs index fcd574f05..a7111e353 100644 --- a/NzbDrone.Core/Providers/RootDirProvider.cs +++ b/NzbDrone.Core/Providers/RootDirProvider.cs @@ -74,7 +74,9 @@ namespace NzbDrone.Core.Providers var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName); if (!_seriesProvider.SeriesPathExists(cleanPath)) + { results.Add(cleanPath); + } } Logger.Debug("{0} unmapped folders detected.", results.Count); diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index ac908c260..8daeb1c89 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -130,7 +130,7 @@ namespace NzbDrone.Core.Providers var series = _database.Fetch(@"SELECT * FROM Series INNER JOIN QualityProfiles ON Series.QualityProfileId = QualityProfiles.QualityProfileId - WHERE CleanTitle = @0", normalizeTitle).FirstOrDefault(); + WHERE CleanTitle = @0", normalizeTitle).SingleOrDefault(); return series; } diff --git a/NzbDrone.Core/packages.config b/NzbDrone.Core/packages.config index 399a6aebb..462426294 100644 --- a/NzbDrone.Core/packages.config +++ b/NzbDrone.Core/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/NzbDrone.Web/Content/ActionButton.css b/NzbDrone.Web/Content/ActionButton.css index 83b4fd123..4727720a2 100644 --- a/NzbDrone.Web/Content/ActionButton.css +++ b/NzbDrone.Web/Content/ActionButton.css @@ -1,7 +1,7 @@ .actionButton { - margin: 5px 5px 5px 5px; - padding: 5px 10px 5px 10px; + margin: 5px; + padding: 2px 5px; background-repeat: no-repeat; background-position: 5px center; background-color: #cccccc; @@ -14,7 +14,7 @@ cursor: pointer; vertical-align: middle; position: relative; - bottom: 1px; + bottom: 3px; } .delete diff --git a/NzbDrone.Web/Content/Blueprint/screen.css b/NzbDrone.Web/Content/Blueprint/screen.css index a66a8f804..69f2d5ec0 100644 --- a/NzbDrone.Web/Content/Blueprint/screen.css +++ b/NzbDrone.Web/Content/Blueprint/screen.css @@ -46,7 +46,6 @@ table caption, th, td { text-align: left; - font-weight: normal; float: none !important; } table, th, td @@ -80,11 +79,9 @@ body font-size: 75%; color: #222; background: #fff; - font-family: "Helvetica Neue" , Arial, Helvetica, sans-serif; } h1, h2, h3, h4, h5, h6 { - font-weight: normal; color: #111; } h1 @@ -100,21 +97,19 @@ h2 } h3 { + margin-top: 0.75em; font-size: 1.5em; line-height: 1; - margin-bottom: 1em; } h4 { font-size: 1.2em; line-height: 1.25; - margin-bottom: 1.25em; } h5 { font-size: 1em; font-weight: bold; - margin-bottom: 1.5em; } h6 { @@ -162,10 +157,7 @@ blockquote color: #666; font-style: italic; } -strong, dfn -{ - font-weight: bold; -} + em, dfn { font-style: italic; @@ -192,11 +184,7 @@ pre margin: 1.5em 0; white-space: pre; } -pre, code, tt -{ - font: 1em 'andale mono' , 'lucida console' , monospace; - line-height: 1.5; -} + li ul, li ol { margin: 0; @@ -218,10 +206,7 @@ dl { margin: 0 0 1.5em 0; } -dl dt -{ - font-weight: bold; -} + dd { margin-left: 1.5em; @@ -231,10 +216,7 @@ table margin-bottom: 1.4em; width: 100%; } -th -{ - font-weight: bold; -} + thead th { background: #c3d9ff; @@ -323,7 +305,6 @@ fieldset } legend { - font-weight: bold; font-size: 1.2em; margin-top: -0.2em; margin-bottom: 1em; diff --git a/NzbDrone.Web/Content/NzbDrone.css b/NzbDrone.Web/Content/NzbDrone.css index 0d8a5822e..a24bb934a 100644 --- a/NzbDrone.Web/Content/NzbDrone.css +++ b/NzbDrone.Web/Content/NzbDrone.css @@ -1,17 +1,25 @@ -h1, h2, h3 + +* { - color: #000000; + font-family: "Segoe UI" , "Segoe UI Light" , Tahoma, Geneva, sans-serif; } body { background: #191919 url(images/img07.jpg) no-repeat right top; - font-family: "Segoe UI" , "Segoe UI Light" , Tahoma, Geneva, sans-serif !important; font-size: 13px; color: #3C3C3C; background-attachment: fixed; } +h1, h2, h3, h4, h5, h6 +{ + font-family: "Segoe UI Light" , "Segoe UI" , Tahoma, Geneva, sans-serif; + color: #3C3C3C; + font-weight: 300; +} + + fieldset { border-style: solid; @@ -60,7 +68,6 @@ hr text-align: center; text-transform: lowercase; font-size: 17px; - font-weight: normal; vertical-align: middle; height: 28px; } @@ -160,8 +167,6 @@ button, input[type="button"], input[type="submit"], input[type="reset"] background-color: #065EFE; border-style: solid; border-color: #065EFE; - padding: 5px 10px 5px 10px; - margin: 10px; } button:active, input[type="button"]:active, input[type="submit"]:active, input[type="reset"]:active @@ -171,17 +176,20 @@ button:active, input[type="button"]:active, input[type="submit"]:active, input[t input[type=text], select { - font-size: larger; - padding: 4px 2px; + font-size: small; + padding: 2px 2px; border: solid 1px #aacfe4; width: 200px; - margin: 2px 0 10px 10px; + margin: 2px 0 10px 0px; height: 20px; } -select + +select, button, input[type="button"], input[type="submit"], input[type="reset"] { - height: 30px; + height: 26px; + min-width: 50px; + margin-left: 10px; } .listButton @@ -229,4 +237,11 @@ select { margin-left: auto; margin-right: auto; +} + + +.qualitySelector +{ + min-width: 60px; + width: auto; } \ No newline at end of file diff --git a/NzbDrone.Web/Content/Overrides.css b/NzbDrone.Web/Content/Overrides.css index 36c187f82..39d6bc0bc 100644 --- a/NzbDrone.Web/Content/Overrides.css +++ b/NzbDrone.Web/Content/Overrides.css @@ -16,3 +16,8 @@ { font-weight: normal; } + +.t-combobox .t-input +{ + line-height: 25px; +} diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs index 4caf1d731..61ad6a275 100644 --- a/NzbDrone.Web/Controllers/AddSeriesController.cs +++ b/NzbDrone.Web/Controllers/AddSeriesController.cs @@ -67,70 +67,61 @@ namespace NzbDrone.Web.Controllers public ActionResult Index() { - var rootDirs = _rootFolderProvider.GetAll(); - - var profiles = _qualityProvider.All(); - var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); - var selectList = new SelectList(profiles, "QualityProfileId", "Name", defaultQuality); - ViewData["qualities"] = selectList; - ViewData["ShowRootDirs"] = false; - - //There are no RootDirs Show the RootDirs Panel - if (rootDirs.Count == 0) - ViewData["ShowRootDirs"] = true; - - return View(rootDirs); + return View(); } - public ActionResult AddExisting() + public ActionResult ExistingSeries() { - var rootDirs = _rootFolderProvider.GetAll(); + var result = new ExistingSeriesModel(); var unmappedList = new List(); - foreach (var folder in rootDirs) + foreach (var folder in _rootFolderProvider.GetAll()) { unmappedList.AddRange(_rootFolderProvider.GetUnmappedFolders(folder.Path)); } - return View(unmappedList); - } + result.ExistingSeries = new List>(); - public ActionResult RenderPartial(string path) - { - var suggestions = GetSuggestionList(new DirectoryInfo(path).Name); + foreach (var folder in unmappedList) + { + var foldername = new DirectoryInfo(folder).Name; + var tvdbResult = _tvDbProvider.SearchSeries(foldername).FirstOrDefault(); - ViewData["guid"] = Guid.NewGuid(); - ViewData["path"] = path; - ViewData["javaPath"] = path.Replace(Path.DirectorySeparatorChar, '|').Replace(Path.VolumeSeparatorChar, '^').Replace('\'', '`'); + var title = String.Empty; + if (tvdbResult != null) + { + title = tvdbResult.SeriesName; + } - var defaultQuality = _configProvider.DefaultQualityProfile; - var qualityProfiles = _qualityProvider.All(); + result.ExistingSeries.Add(new Tuple(folder, title)); + } - ViewData["quality"] = new SelectList( - qualityProfiles, - "QualityProfileId", - "Name", - defaultQuality); + var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); + result.Quality = new SelectList(_qualityProvider.All(), "QualityProfileId", "Name", defaultQuality); - return PartialView("AddSeriesItem", suggestions); + return View(result); + } + + [HttpPost] + public JsonResult AddNewSeries(string path, string seriesName, int qualityProfileId) + { + path = Path.Combine(path, MediaFileProvider.CleanFilename(seriesName)); + return AddExistingSeries(path, seriesName, qualityProfileId); } [HttpPost] - public JsonResult AddNewSeries(string rootPath, string seriesName, int seriesId, int qualityProfileId) + public JsonResult AddExistingSeries(string path, string seriesName, int qualityProfileId) { try { - var path = Path.Combine(rootPath.Replace('|', Path.DirectorySeparatorChar) - .Replace('^', Path.VolumeSeparatorChar) - .Replace('`', '\''), - MediaFileProvider.CleanFilename(seriesName)); - //Create the folder for the new series and then Add it _diskProvider.CreateDirectory(path); - _seriesProvider.AddSeries(path, seriesId, qualityProfileId); + var series = _tvDbProvider.SearchSeries(seriesName).Where(s => s.SeriesName == seriesName).Single(); + + _seriesProvider.AddSeries(path, series.Id, qualityProfileId); ScanNewSeries(); return new JsonResult { Data = "ok" }; } @@ -154,30 +145,6 @@ namespace NzbDrone.Web.Controllers return new JsonResult { Data = "ok" }; } - [HttpPost] - public ActionResult _textLookUp(string text, int? filterMode) - { - var suggestions = GetSuggestionList(text); - - return new JsonResult - { - JsonRequestBehavior = JsonRequestBehavior.AllowGet, - Data = suggestions - }; - } - - public SelectList GetSuggestionList(string searchString) - { - var dataVal = _tvDbProvider.SearchSeries(searchString); - - int selectId = 0; - if (dataVal.Count != 0) - { - selectId = dataVal[0].Id; - } - - return new SelectList(dataVal, "Id", "SeriesName", selectId); - } //Root Directory [HttpPost] @@ -202,36 +169,15 @@ namespace NzbDrone.Web.Controllers return new JsonResult { }; } - public PartialViewResult AddRootDir() - { - var model = new RootDirModel - { - Id = 0, - Path = "", - CleanPath = "", - SelectList = new SelectList(new List { "" }, "") - }; - - ViewData["guid"] = Guid.NewGuid(); - - return PartialView("RootDir", model); - } - - public ActionResult GetRootDirView(RootDir rootDir) + [HttpGet] + public JsonResult LookupSeries(string q) { - var model = new RootDirModel - { - Id = rootDir.Id, - Path = rootDir.Path, - SelectList = new SelectList(new List { rootDir.Path }, rootDir.Path) - }; - ViewData["guid"] = Guid.NewGuid(); + var dataVal = _tvDbProvider.SearchSeries(q); - return PartialView("RootDir", model); + return Json(dataVal.Select(c => new KeyValuePair(c.Id, c.SeriesName)), JsonRequestBehavior.AllowGet); } - public ActionResult RootList() { IEnumerable rootDir = _rootFolderProvider.GetAll().Select(c => c.Path).OrderBy(e => e); diff --git a/NzbDrone.Web/Controllers/HealthController.cs b/NzbDrone.Web/Controllers/HealthController.cs index 7d29862e4..9ae802294 100644 --- a/NzbDrone.Web/Controllers/HealthController.cs +++ b/NzbDrone.Web/Controllers/HealthController.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Web.Controllers [HttpGet] public JsonResult Index() { + MvcMiniProfiler.MiniProfiler.Stop(true); return Json("OK", JsonRequestBehavior.AllowGet); } diff --git a/NzbDrone.Web/Controllers/SeriesController.cs b/NzbDrone.Web/Controllers/SeriesController.cs index 61c1a53f9..c1d0835be 100644 --- a/NzbDrone.Web/Controllers/SeriesController.cs +++ b/NzbDrone.Web/Controllers/SeriesController.cs @@ -90,7 +90,6 @@ namespace NzbDrone.Web.Controllers public ActionResult _SaveAjaxSeriesEditing(int id, string path, bool monitored, bool seasonFolder, int qualityProfileId, List seasonEditor) { var oldSeries = _seriesProvider.GetSeries(id); - oldSeries.Path = path; oldSeries.Monitored = monitored; oldSeries.SeasonFolder = seasonFolder; oldSeries.QualityProfileId = qualityProfileId; diff --git a/NzbDrone.Web/Models/AddExistingManualModel.cs b/NzbDrone.Web/Models/AddExistingManualModel.cs deleted file mode 100644 index 5a529e219..000000000 --- a/NzbDrone.Web/Models/AddExistingManualModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel; -using System.Web.Mvc; - -namespace NzbDrone.Web.Models -{ - public class AddExistingManualModel - { - public string Path { get; set; } - public string FolderName { get; set; } - - [DisplayName("Quality Profile")] - public int QualityProfileId { get; set; } - - public SelectList QualitySelectList { get; set; } - } -} \ No newline at end of file diff --git a/NzbDrone.Web/Models/AddExistingSeriesModel.cs b/NzbDrone.Web/Models/AddExistingSeriesModel.cs deleted file mode 100644 index ef9fb98de..000000000 --- a/NzbDrone.Web/Models/AddExistingSeriesModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace NzbDrone.Web.Models -{ - public class AddExistingSeriesModel - { - public bool IsWanted { get; set; } - public string Path { get; set; } - public string PathEncoded { get; set; } - public int TvDbId { get; set; } - public string TvDbName { get; set; } - } -} \ No newline at end of file diff --git a/NzbDrone.Web/Models/ExistingSeriesModel.cs b/NzbDrone.Web/Models/ExistingSeriesModel.cs new file mode 100644 index 000000000..b6a391e42 --- /dev/null +++ b/NzbDrone.Web/Models/ExistingSeriesModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; + +namespace NzbDrone.Web.Models +{ + public class ExistingSeriesModel + { + public SelectList Quality { get; set; } + + public List> ExistingSeries { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index 2874ee488..e158a9177 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -51,9 +51,9 @@ ..\Libraries\MVC3\Microsoft.Web.Infrastructure.dll True - + False - ..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll + ..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll ..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll @@ -156,8 +156,7 @@ - - + @@ -251,6 +250,7 @@ + @@ -261,7 +261,6 @@ - Designer @@ -325,7 +324,7 @@ - + diff --git a/NzbDrone.Web/Scripts/AutoComplete.js b/NzbDrone.Web/Scripts/AutoComplete.js index fe6ba6d7c..01e689753 100644 --- a/NzbDrone.Web/Scripts/AutoComplete.js +++ b/NzbDrone.Web/Scripts/AutoComplete.js @@ -1,13 +1,48 @@ -function bindFolderAutoComplete(selector) { - YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { - Y.one('body').addClass('yui3-skin-sam'); - Y.one(selector).plug(Y.Plugin.AutoComplete, { +jQuery(document).ready(function () { + $.ajaxSetup({ + cache: false + }); + $('.folderLookup').livequery(function () { + bindFolderAutoComplete(".folderLookup"); + }); + + $('.seriesLookup').livequery(function () { + bindSeriesAutoComplete(".seriesLookup"); + }); - resultHighlighter: 'startsWith', - resultFilters: 'phraseMatch', - source: '/Directory/GetDirectories/?q={query}' + +}); + +function bindFolderAutoComplete(selector) { + + $(selector).each(function (index, element) { + + YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { + Y.one('body').addClass('yui3-skin-sam'); + Y.one(element).plug(Y.Plugin.AutoComplete, { + resultHighlighter: 'startsWith', + resultFilters: 'phraseMatch', + source: '/Directory/GetDirectories/?q={query}' + }); }); - }) + }); +} + +function bindSeriesAutoComplete(selector) { + + $(selector).each(function (index, element) { + YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { + Y.one('body').addClass('yui3-skin-sam'); + Y.one(element).plug(Y.Plugin.AutoComplete, { + resultHighlighter: 'startsWith', + resultFilters: 'phraseMatch', + resultTextLocator: 'Value', + minQueryLength: 3, + queryDelay: 500, + source: '/AddSeries/LookupSeries/?q={query}' + }); + }); + }); } \ No newline at end of file diff --git a/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js b/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js new file mode 100644 index 000000000..dde8ad8e3 --- /dev/null +++ b/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js @@ -0,0 +1,250 @@ +/*! Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Version: 1.0.3 + * Requires jQuery 1.1.3+ + * Docs: http://docs.jquery.com/Plugins/livequery + */ + +(function($) { + +$.extend($.fn, { + livequery: function(type, fn, fn2) { + var self = this, q; + + // Handle different call patterns + if ($.isFunction(type)) + fn2 = fn, fn = type, type = undefined; + + // See if Live Query already exists + $.each( $.livequery.queries, function(i, query) { + if ( self.selector == query.selector && self.context == query.context && + type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) ) + // Found the query, exit the each loop + return (q = query) && false; + }); + + // Create new Live Query if it wasn't found + q = q || new $.livequery(this.selector, this.context, type, fn, fn2); + + // Make sure it is running + q.stopped = false; + + // Run it immediately for the first time + q.run(); + + // Contnue the chain + return this; + }, + + expire: function(type, fn, fn2) { + var self = this; + + // Handle different call patterns + if ($.isFunction(type)) + fn2 = fn, fn = type, type = undefined; + + // Find the Live Query based on arguments and stop it + $.each( $.livequery.queries, function(i, query) { + if ( self.selector == query.selector && self.context == query.context && + (!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped ) + $.livequery.stop(query.id); + }); + + // Continue the chain + return this; + } +}); + +$.livequery = function(selector, context, type, fn, fn2) { + this.selector = selector; + this.context = context || document; + this.type = type; + this.fn = fn; + this.fn2 = fn2; + this.elements = []; + this.stopped = false; + + // The id is the index of the Live Query in $.livequery.queries + this.id = $.livequery.queries.push(this)-1; + + // Mark the functions for matching later on + fn.$lqguid = fn.$lqguid || $.livequery.guid++; + if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++; + + // Return the Live Query + return this; +}; + +$.livequery.prototype = { + stop: function() { + var query = this; + + if ( this.type ) + // Unbind all bound events + this.elements.unbind(this.type, this.fn); + else if (this.fn2) + // Call the second function for all matched elements + this.elements.each(function(i, el) { + query.fn2.apply(el); + }); + + // Clear out matched elements + this.elements = []; + + // Stop the Live Query from running until restarted + this.stopped = true; + }, + + run: function() { + // Short-circuit if stopped + if ( this.stopped ) return; + var query = this; + + var oEls = this.elements, + els = $(this.selector, this.context), + nEls = els.not(oEls); + + // Set elements to the latest set of matched elements + this.elements = els; + + if (this.type) { + // Bind events to newly matched elements + nEls.bind(this.type, this.fn); + + // Unbind events to elements no longer matched + if (oEls.length > 0) + $.each(oEls, function(i, el) { + if ( $.inArray(el, els) < 0 ) + $.event.remove(el, query.type, query.fn); + }); + } + else { + // Call the first function for newly matched elements + nEls.each(function() { + query.fn.apply(this); + }); + + // Call the second function for elements no longer matched + if ( this.fn2 && oEls.length > 0 ) + $.each(oEls, function(i, el) { + if ( $.inArray(el, els) < 0 ) + query.fn2.apply(el); + }); + } + } +}; + +$.extend($.livequery, { + guid: 0, + queries: [], + queue: [], + running: false, + timeout: null, + + checkQueue: function() { + if ( $.livequery.running && $.livequery.queue.length ) { + var length = $.livequery.queue.length; + // Run each Live Query currently in the queue + while ( length-- ) + $.livequery.queries[ $.livequery.queue.shift() ].run(); + } + }, + + pause: function() { + // Don't run anymore Live Queries until restarted + $.livequery.running = false; + }, + + play: function() { + // Restart Live Queries + $.livequery.running = true; + // Request a run of the Live Queries + $.livequery.run(); + }, + + registerPlugin: function() { + $.each( arguments, function(i,n) { + // Short-circuit if the method doesn't exist + if (!$.fn[n]) return; + + // Save a reference to the original method + var old = $.fn[n]; + + // Create a new method + $.fn[n] = function() { + // Call the original method + var r = old.apply(this, arguments); + + // Request a run of the Live Queries + $.livequery.run(); + + // Return the original methods result + return r; + } + }); + }, + + run: function(id) { + if (id != undefined) { + // Put the particular Live Query in the queue if it doesn't already exist + if ( $.inArray(id, $.livequery.queue) < 0 ) + $.livequery.queue.push( id ); + } + else + // Put each Live Query in the queue if it doesn't already exist + $.each( $.livequery.queries, function(id) { + if ( $.inArray(id, $.livequery.queue) < 0 ) + $.livequery.queue.push( id ); + }); + + // Clear timeout if it already exists + if ($.livequery.timeout) clearTimeout($.livequery.timeout); + // Create a timeout to check the queue and actually run the Live Queries + $.livequery.timeout = setTimeout($.livequery.checkQueue, 20); + }, + + stop: function(id) { + if (id != undefined) + // Stop are particular Live Query + $.livequery.queries[ id ].stop(); + else + // Stop all Live Queries + $.each( $.livequery.queries, function(id) { + $.livequery.queries[ id ].stop(); + }); + } +}); + +// Register core DOM manipulation methods +$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove'); + +// Run Live Queries when the Document is ready +$(function() { $.livequery.play(); }); + + +// Save a reference to the original init method +var init = $.prototype.init; + +// Create a new init method that exposes two new properties: selector and context +$.prototype.init = function(a,c) { + // Call the original init and save the result + var r = init.apply(this, arguments); + + // Copy over properties if they exist already + if (a && a.selector) + r.context = a.context, r.selector = a.selector; + + // Set properties + if ( typeof a == 'string' ) + r.context = c || document, r.selector = a; + + // Return the result + return r; +}; + +// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091) +$.prototype.init.prototype = $.prototype; + +})(jQuery); \ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml b/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml deleted file mode 100644 index 09f26f195..000000000 --- a/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml +++ /dev/null @@ -1,15 +0,0 @@ -@model IEnumerable - -@{ - Layout = null; -} - -@if (Model.Count() == 0) -{ - @Html.DisplayText("No Series to Add"); -} - -@foreach (var path in Model) -{ - Html.RenderAction("RenderPartial", "AddSeries", new {path}); -} \ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/AddNew.cshtml b/NzbDrone.Web/Views/AddSeries/AddNew.cshtml index 124afee72..cdb834363 100644 --- a/NzbDrone.Web/Views/AddSeries/AddNew.cshtml +++ b/NzbDrone.Web/Views/AddSeries/AddNew.cshtml @@ -2,56 +2,44 @@ @using NzbDrone.Web.Models @{ Layout = null; }
- @Html.Label("Root Directory") - @Html.DropDownList("rootDirList", new SelectList((IList)ViewData["RootDirs"])) - @Html.Label("Quality") - @Html.DropDownList("qualityList", new SelectList((IList)ViewData["QualityList"], "QualityProfileId", "Name")) -
-
-
- @{Html.Telerik().ComboBox() - .Name("seriesList_new") - .DataBinding(binding => binding.Ajax().Select("_textLookUp", "AddSeries").Delay(400)) - .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) - .HighlightFirstMatch(true) - .HtmlAttributes(new { style = "width: 300px;" }) - .Render();} - @Html.Telerik().DropDownList().Name("qualityList_new").BindTo((SelectList)ViewData["quality"]).HtmlAttributes(new { style = "width: 100px", @class = "qualityDropbox" }) -
-@section Scripts{ - -} + + + }); + }); + + + diff --git a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml deleted file mode 100644 index 32f84c960..000000000 --- a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml +++ /dev/null @@ -1,20 +0,0 @@ -@using NzbDrone.Core.Repository.Quality -@model SelectList -
-
- @ViewData["path"].ToString() -
- @{Html.Telerik().ComboBox() - .Name("seriesList_" + ViewData["guid"]) - .BindTo(Model) - .DataBinding(binding => binding.Ajax().Select("_textLookUp", "AddSeries").Delay(400)) - .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) - .HighlightFirstMatch(true) - .HtmlAttributes(new { style = "width: 300px;" }) - .Render();} - @Html.Telerik().DropDownList().Name("qualityList_" + ViewData["guid"]).BindTo((SelectList)ViewData["quality"]).HtmlAttributes(new { style = "width: 100px", @class = "qualityDropbox" }) - -
-
-
\ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml b/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml new file mode 100644 index 000000000..eaa88eea6 --- /dev/null +++ b/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml @@ -0,0 +1,96 @@ +@using System.Collections +@using NzbDrone.Web.Models +@using System.Web.Mvc.Html +@model ExistingSeriesModel +@{ + Layout = null; +} +@if (Model.ExistingSeries.Count == 0) +{ +

+ No series available. Try adding a new Root Folder. +

+} +else +{ +

+ Series Ready to be added. + @Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector masterQualitySelector" }) +

+
+ +
+ +} +@foreach (var series in Model.ExistingSeries) +{ + +
+ + @Html.Label(series.Item1) + +
+
+ + @Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector" }) + +
+
+} + + + diff --git a/NzbDrone.Web/Views/AddSeries/Index.cshtml b/NzbDrone.Web/Views/AddSeries/Index.cshtml index 7d4022af2..4912142ff 100644 --- a/NzbDrone.Web/Views/AddSeries/Index.cshtml +++ b/NzbDrone.Web/Views/AddSeries/Index.cshtml @@ -1,90 +1,18 @@ -@model List -@using NzbDrone.Core.Repository -@section HeaderContent -{ - -} +@using NzbDrone.Core.Repository @section TitleContent{ Add Series } @section MainContent{ -
- @{ Html.RenderAction("AddNew", "AddSeries"); } -
+

+ Add New Series

+ @{ Html.RenderAction("AddNew", "AddSeries"); } +

+ Add Series Already on Disk

+

+ Manage Root Folders +

@{Html.RenderAction("RootDir");}
-
- - @Html.Telerik().DropDownList().Name("masterDropbox").BindTo((SelectList)ViewData["qualities"]).HtmlAttributes( - new { style = "width: 100px; margin-left:224px;" }).ClientEvents(events => events.OnChange("masterChanged")) -
- @{ Html.RenderAction("AddExisting", "AddSeries"); } + @{ Html.RenderAction("ExistingSeries", "AddSeries"); }
} -@section Scripts -{ - -} diff --git a/NzbDrone.Web/Views/AddSeries/RootDir.cshtml b/NzbDrone.Web/Views/AddSeries/RootDir.cshtml index 0907941a5..2e566ab00 100644 --- a/NzbDrone.Web/Views/AddSeries/RootDir.cshtml +++ b/NzbDrone.Web/Views/AddSeries/RootDir.cshtml @@ -1,26 +1,18 @@  - + - - + @{Html.RenderAction("RootList");} + + diff --git a/NzbDrone.Web/packages.config b/NzbDrone.Web/packages.config index 00619dcd0..9dd660df6 100644 --- a/NzbDrone.Web/packages.config +++ b/NzbDrone.Web/packages.config @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/NzbDrone/Program.cs b/NzbDrone/Program.cs index deb6c13ab..697065fb7 100644 --- a/NzbDrone/Program.cs +++ b/NzbDrone/Program.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Net; using System.Threading; using System.Timers; using Exceptioneer.WindowsFormsClient; @@ -38,7 +39,18 @@ namespace NzbDrone Attach(); #endif - if (Environment.UserInteractive) + if (!Environment.UserInteractive) + { + try + { + new WebClient().DownloadString(IISController.AppUrl); + } + catch (Exception e) + { + Logger.ErrorException("Failed to load home page.", e); + } + } + else { try { diff --git a/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg b/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg deleted file mode 100644 index dcbc7f48e..000000000 Binary files a/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg and /dev/null differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb b/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb deleted file mode 100644 index 2c55ac7d7..000000000 Binary files a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb and /dev/null differ diff --git a/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg b/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg new file mode 100644 index 000000000..145e209e4 Binary files /dev/null and b/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll similarity index 51% rename from packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll rename to packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll index e35747310..db133f6a3 100644 Binary files a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll and b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll differ diff --git a/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb new file mode 100644 index 000000000..80f61f512 Binary files /dev/null and b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml similarity index 76% rename from packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml rename to packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml index 3cf07f964..30cd1ae7d 100644 --- a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml +++ b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml @@ -4,11 +4,6 @@ MvcMiniProfiler - - - Formats any SQL query with inline parameters, optionally including the value type - - Takes a SqlTiming and returns a formatted SQL string, for parameter replacement, etc. @@ -21,31 +16,54 @@ Formatted SQL - + - Creates a new Inline SQL Formatter, optionally including the parameter type info in comments beside the replaced value + A single MiniProfiler can be used to represent any number of steps/levels in a call-graph, via Step() - whether to include a comment after the value, indicating the type, e.g. /* @myParam DbType.Int32 */ + Totally baller. - + - Formats the SQL in a generic frieldly format, including the parameter type information in a comment if it was specified in the InlineFormatter constructor + A callback for ProfiledDbConnection and family - The SqlTiming to format - A formatted SQL string - + - Returns a string representation of the parameter's value, including the type + Called when a command starts executing - The parameter to get a value for - + + - + - A single MiniProfiler can be used to represent any number of steps/levels in a call-graph, via Step() + Called when a reader finishes executing + + + + + + + + Called when a command finishes executing + + + + + + + Called when a reader is done iterating through the data + + + + + + True if the profiler instance is active + + + + + Returns all currently open commands on this connection - Totally baller. @@ -98,6 +116,11 @@ be prematurely stopped and discarded. Useful for when a specific route does not need to be profiled. + + + Makes sure 'profiler' has a Name, pulling it from route data or url. + + Returns an that will time the code between its creation and disposal. Use this method when you @@ -169,6 +192,25 @@ All other s will be children of this one. + + + A string identifying the user/client that is profiling this request. Set + with an -implementing class to provide a custom value. + + + If this is not set manually at some point, the implementation will be used; + by default, this will be the current request's ip address. + + + + + Returns true when this MiniProfiler has been viewed by the that recorded it. + + + Allows POSTs that result in a redirect to be profiled. implementation + will keep a list of all profilers that haven't been fetched down. + + Contains information about queries executed during this profiling session. @@ -229,15 +271,47 @@ Various configuration properties. - + + + Excludes the specified assembly from the stack trace output. + + The short name of the assembly. AssemblyName.Name + + + + Excludes the specified type from the stack trace output. + + The System.Type name to exclude + + + + Excludes the specified method name from the stack trace output. + + The name of the method + + + + Make sure we can at least store profiler results to the http runtime cache. + + + + + Assemblies to exclude from the stack trace report. + + + + + Types to exclude from the stack trace report. + + + - Ensures that and objects are initialized. Null values will - be initialized to use the default strategy. + Methods to exclude from the stack trace report. - + - When true, link and script tags will be written to the response stream when MiniProfiler.Stop is called. + The max length of the stack string to report back; defaults to 120 chars. @@ -269,11 +343,17 @@ For a per-page override you can use .RenderIncludes(position: RenderPosition.Left/Right) - + + + By default, SqlTimings will grab a stack trace to help locate where queries are being executed. + When this setting is true, no stack trace will be collected, possibly improving profiler performance. + + + - When is called, if the current request url starts with this property, - no profiler will be instantiated and no results will be displayed. - Default value is { "/mini-profiler-includes.js", "/mini-profiler-includes.less", "/mini-profiler-results", "/content/", "/scripts/" }. + When is called, if the current request url contains any items in this property, + no profiler will be instantiated and no results will be displayed. + Default value is { "/mini-profiler-", "/content/", "/scripts/", "/favicon.ico" }. @@ -283,10 +363,10 @@ Any setting here should be in APP RELATIVE FORM, e.g. "~/myDirectory/" - + - Understands how to save and load MiniProfilers for a very limited time. Used for caching between when - a profiling session ends and results can be fetched to the client. + Understands how to save and load MiniProfilers. Used for caching between when + a profiling session ends and results can be fetched to the client, and for showing shared, full-page results. The normal profiling session life-cycle is as follows: @@ -294,21 +374,20 @@ 2) profiler is started 3) normal page/controller/request execution 4) profiler is stopped - 5) profiler is cached with 's implementation of + 5) profiler is cached with 's implementation of 6) request ends 7) page is displayed and profiling results are ajax-fetched down, pulling cached results from - 's implementation of + 's implementation of - + - Understands how to save and load MiniProfilers for an extended (even indefinite) time, allowing results to be - shared with other developers or even tracked over time. + The formatter applied to the SQL being rendered (used only for UI) - + - The formatter applied to the SQL being rendered (used only for UI) + Provides user identification for a given profiling request. @@ -326,70 +405,6 @@ Both the HttpRequest and MiniProfiler parameters that will be passed into this function should never be null. - - - Categorizes individual steps to allow filtering. - - - - - Default level given to Timings. - - - - - Useful when profiling many items in a loop, but you don't wish to always see this detail. - - - - - Dictates on which side of the page the profiler popup button is displayed; defaults to left. - - - - - Profiler popup button is displayed on the left. - - - - - Profiler popup button is displayed on the right. - - - - - Contains helper methods that ease working with null s. - - - - - Wraps in a call and executes it, returning its result. - - The current profiling session or null. - Method to execute and profile. - The step name used to label the profiler results. - - - - - Returns an that will time the code between its creation and disposal. - - The current profiling session or null. - A descriptive name for the code that is encapsulated by the resulting IDisposable's lifetime. - This step's visibility level; allows filtering when is called. - - - - Adds 's hierarchy to this profiler's current Timing step, - allowing other threads, remote calls, etc. to be profiled and joined into this profiling session. - - - - - Returns an html-encoded string with a text-representation of ; returns "" when profiler is null. - - The current profiling session or null. - Execute parameterized SQL @@ -439,50 +454,51 @@ Read the next grid of results - + - This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), - and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** - equality. The type is fully thread-safe. + Wraps a database connection, allowing sql execution timings to be collected when a session is started. - + - Provides saving and loading s to a storage medium. + Returns a new that wraps , + providing query execution profiling. + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - + - Stores under , which is also its . + Returns a new that wraps , + providing query execution profiling. - - The Guid that identifies the MiniProfiler; subsequent calls to - will pass this Guid. - - The results of a profiling session. - - Should be able to be called multiple times on the same profiler. - + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection + The currently started or null. - + - Returns a from storage based on . + Returns a new that wraps , + providing query execution profiling. If profiler is null, no profiling will occur. + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection + The currently started or null. - + - NOT IMPLEMENTED - will format statements with paramters in an Oracle friendly way + Connection factory used for EF Code First DbContext API - + - Does NOTHING, implement me! + Create a profiled connection factory + The underlying connection that needs to be profiled - + - Understands how to store a to a MSSQL database. + Create a wrapped connection for profiling purposes + + @@ -490,21 +506,55 @@ querying of slow results. + + + Provides saving and loading s to a storage medium. + + + + + Stores under its . + + The results of a profiling session. + + Should also ensure the profiler is stored as being unviewed by its profiling . + + + + + Returns a from storage based on , which should map to . + + + Should also update that the resulting profiler has been marked as viewed by its profiling . + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + Returns a new SqlServerDatabaseStorage object that will insert into the database identified by connectionString. - + - Saves 'profiler' to a database under 'id'. + Saves 'profiler' to a database under its . - + Returns the MiniProfiler identified by 'id' from the database or null when no MiniProfiler exists under that 'id'. + + + Returns a list of s that haven't been seen by . + + User identified by the current . + Returns a DbConnection for your specific provider. @@ -526,120 +576,295 @@ How we connect to the database used to save/load MiniProfiler results. - + - Creates needed tables. Run this once on your database. + Formats SQL server queries with a DECLARE up top for parameter values - - Works in sql server and sqlite (with documented removals). - TODO: add indexes - - + - Returns a new . + Formats the SQL in a SQL-Server friendly way, with DECLARE statements for the parameters up top. + The SqlTiming to format + A formatted SQL string - + - Stores 'profiler' to dbo.MiniProfilers under 'id'; stores all child Timings and SqlTimings to their respective tables. + Wrapper for a db provider factory to enable profiling - + - Saves parameter Timing to the dbo.MiniProfilerTimings table. + Every provider factory must have an Instance public field - + - Saves parameter SqlTiming to the dbo.MiniProfilerSqlTimings table. + Used for db provider apis internally - + - Saves any SqlTimingParameters used in the profiled SqlTiming to the dbo.MiniProfilerSqlTimingParameters table. + Allow to re-init the provider factory. + + - + - Loads the MiniProfiler identifed by 'id' from the database. + proxy + + - + - Returns a connection to Sql Server. + proxy - + - An individual profiling step that can contain child steps. + proxy - + - Rebuilds all the parent timings on deserialization calls + proxy - + - Offset from parent MiniProfiler's creation that this Timing was created. + proxy - + - Creates a new Timing named 'name' in the 'profiler's session, with 'parent' as this Timing's immediate ancestor. + proxy - + - Obsolete - used for serialization. + proxy - + - Returns this Timing's Name. + proxy - + - Adds arbitrary string 'value' under 'key', allowing custom properties to be stored in this Timing step. + proxy - + - Completes this Timing's duration and sets the MiniProfiler's Head up one level. + Extension mechanism for additional services; + requested service provider or null. - + - Add the parameter 'timing' to this Timing's Children collection. + proxy - - Used outside this assembly for custom deserialization when creating an implementation. - - + - Adds the parameter 'sqlTiming' to this Timing's SqlTimings collection. + Categorizes individual steps to allow filtering. - A sql statement profiling that was executed in this Timing step. - - Used outside this assembly for custom deserialization when creating an implementation. - - + - Unique identifer for this timing; set during construction. + Default level given to Timings. - + - Text displayed when this Timing is rendered. + Useful when profiling many items in a loop, but you don't wish to always see this detail. - + - How long this Timing step took in ms; includes any Timings' durations. + Dictates on which side of the page the profiler popup button is displayed; defaults to left. + + + + + Profiler popup button is displayed on the left. + + + + + Profiler popup button is displayed on the right. + + + + + Contains helper methods that ease working with null s. + + + + + Wraps in a call and executes it, returning its result. + + The current profiling session or null. + Method to execute and profile. + The step name used to label the profiler results. + + + + + Returns an that will time the code between its creation and disposal. + + The current profiling session or null. + A descriptive name for the code that is encapsulated by the resulting IDisposable's lifetime. + This step's visibility level; allows filtering when is called. + + + + Adds 's hierarchy to this profiler's current Timing step, + allowing other threads, remote calls, etc. to be profiled and joined into this profiling session. + + + + + Returns an html-encoded string with a text-representation of ; returns "" when profiler is null. + + The current profiling session or null. + + + + Gets part of a stack trace containing only methods we care about. + + + + + Gets the current formatted and filted stack trace. + + Space separated list of methods + + + + Understands how to store a to the with absolute expiration. + + + + + The string that prefixes all keys that MiniProfilers are saved under, e.g. + "mini-profiler-ecfb0050-7ce8-4bf1-bf82-2cb38e90e31e". + + + + + Returns a new HttpRuntimeCacheStorage class that will cache MiniProfilers for the specified duration. + + + + + Saves to the HttpRuntime.Cache under a key concated with + and the parameter's . + + + + + Returns the saved identified by . Also marks the resulting + profiler to true. + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + + + + Syncs access to runtime cache when adding a new list of ids for a user. + + + + + How long to cache each for (i.e. the absolute expiration parameter of + ) + + + + + Get DB command definition + + + + + + + An individual profiling step that can contain child steps. + + + + + Rebuilds all the parent timings on deserialization calls + + + + + Offset from parent MiniProfiler's creation that this Timing was created. + + + + + Creates a new Timing named 'name' in the 'profiler's session, with 'parent' as this Timing's immediate ancestor. + + + + + Obsolete - used for serialization. + + + + + Returns this Timing's Name. + + + + + Adds arbitrary string 'value' under 'key', allowing custom properties to be stored in this Timing step. + + + + + Completes this Timing's duration and sets the MiniProfiler's Head up one level. + + + + + Add the parameter 'timing' to this Timing's Children collection. + + + Used outside this assembly for custom deserialization when creating an implementation. + + + + + Adds the parameter 'sqlTiming' to this Timing's SqlTimings collection. + + A sql statement profiling that was executed in this Timing step. + + Used outside this assembly for custom deserialization when creating an implementation. + + + + + Unique identifer for this timing; set during construction. + + + + + Text displayed when this Timing is rendered. + + + + + How long this Timing step took in ms; includes any Timings' durations. @@ -734,375 +959,413 @@ How many sql non-query statements were executed in this Timing step. - + Categories of sql statements. - + Unknown - + DML statements that alter database state, e.g. INSERT, UPDATE - + Statements that return a single record - + Statements that iterate over a result set - + - Contains helper code to time sql statements. + Profiles a single sql execution. - + - Returns a new SqlProfiler to be used in the 'profiler' session. + Creates a new SqlTiming to profile 'command'. - + - Tracks when 'command' is started. + Obsolete - used for serialization. - + - Finishes profiling for 'command', recording durations. + Called when command execution is finished to determine this SqlTiming's duration. - + - Called when 'reader' finishes its iterations and is closed. + Called when database reader is closed, ending profiling for SqlTimings. - + - The profiling session this SqlProfiler is part of. + To help with display, put some space around sammiched commas - + - Helper methods that allow operation on SqlProfilers, regardless of their instantiation. + Unique identifier for this SqlTiming. - + - Tracks when 'command' is started. + Category of sql statement executed. - + - Finishes profiling for 'command', recording durations. + The sql that was executed. - + - Called when 'reader' finishes its iterations and is closed. + The sql that was executed. - + - Understands how to route and respond to MiniProfiler UI urls. + The command string with special formatting applied based on MiniProfiler.Settings.SqlFormatter - + - Returns this to handle . + Roughly where in the calling code that this sql was executed. - + - Returns either includes' css/javascript or results' html. + Offset from main MiniProfiler start that this sql began. - + - Handles rendering static content files. + How long this sql statement took to execute. - + - Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query. + When executing readers, how long it took to come back initially from the database, + before all records are fetched and reader is closed. - + - Embedded resource contents keyed by filename. + Stores any parameter names and values used by the profiled DbCommand. - + - Helper method that sets a proper 404 response code. + Id of the Timing this statement was executed in. + + + Needed for database deserialization. + + + + + The Timing step that this sql execution occurred in. - + - Try to keep everything static so we can easily be reused. + True when other identical sql statements have been executed during this MiniProfiler session. - + - Formats SQL server queries with a DECLARE up top for parameter values + If the underlying command supports BindByName, this sets/clears the underlying + implementation accordingly. This is required to support OracleCommand from dapper-dot-net - + - Formats the SQL in a SQL-Server friendly way, with DECLARE statements for the parameters up top. + Formats any SQL query with inline parameters, optionally including the value type + + + + + Creates a new Inline SQL Formatter, optionally including the parameter type info in comments beside the replaced value + + whether to include a comment after the value, indicating the type, e.g. /* @myParam DbType.Int32 */ + + + + Formats the SQL in a generic frieldly format, including the parameter type information in a comment if it was specified in the InlineFormatter constructor The SqlTiming to format A formatted SQL string - + - Common extension methods to use only in this project + Returns a string representation of the parameter's value, including the type + The parameter to get a value for + - + - Answers true if this String is either null or empty. + Identifies users based on ip address. - + - Answers true if this String is neither null or empty. + Provides functionality to identify which user is profiling a request. - + - Removes trailing / characters from a path and leaves just one + Returns a string to identify the user profiling the current 'request'. + The current HttpRequest being profiled. - + - Removes any leading / characters from a path + Returns the paramter HttpRequest's client ip address. - + - Removes any leading / characters from a path + This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), + and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** + equality. The type is fully thread-safe. - + - Extension mechanism for additional services; + NOT IMPLEMENTED - will format statements with paramters in an Oracle friendly way - requested service provider or null. - + - Wraps a database connection, allowing sql execution timings to be collected when a session is started. + Does NOTHING, implement me! - + - Returns a new that wraps , - providing query execution profiling. + Understands how to store a to a MSSQL database. - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - + - Returns a new that wraps , - providing query execution profiling. + Creates needed tables. Run this once on your database. - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - The currently started or null. + + Works in sql server and sqlite (with documented removals). + TODO: add indexes + - + - Returns a new that wraps , - providing query execution profiling. If profiler is null, no profiling will occur. + Returns a new . - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - The currently started or null. - + - Information about a DbParameter used in the sql statement profiled by SqlTiming. + Stores to dbo.MiniProfilers under its ; + stores all child Timings and SqlTimings to their respective tables. - + - Which SqlTiming this Parameter was executed with. + Saves parameter Timing to the dbo.MiniProfilerTimings table. - + - Parameter name, e.g. "@routeName" + Saves parameter SqlTiming to the dbo.MiniProfilerSqlTimings table. - + - The value submitted to the database. + Saves any SqlTimingParameters used in the profiled SqlTiming to the dbo.MiniProfilerSqlTimingParameters table. - + - System.Data.DbType, e.g. "String", "Bit" + Loads the MiniProfiler identifed by 'id' from the database. - + - How large the type is, e.g. for string, size could be 4000 + Returns a list of s that haven't been seen by . + User identified by the current . - + - Profiles a single sql execution. + Returns a connection to Sql Server. - + - Creates a new SqlTiming to profile 'command'. + Contains helper code to time sql statements. - + - Obsolete - used for serialization. + Returns a new SqlProfiler to be used in the 'profiler' session. - + - Called when command execution is finished to determine this SqlTiming's duration. + Tracks when 'command' is started. - + - Called when database reader is closed, ending profiling for SqlTimings. + Returns all currently open commands on this connection - + - To help with display, put some space around sammiched commas + Finishes profiling for 'command', recording durations. - + - Unique identifier for this SqlTiming. + Called when 'reader' finishes its iterations and is closed. - + - Category of sql statement executed. + The profiling session this SqlProfiler is part of. - + - The sql that was executed. + Helper methods that allow operation on SqlProfilers, regardless of their instantiation. - + - The sql that was executed. + Tracks when 'command' is started. - + - The command string with special formatting applied based on MiniProfiler.Settings.SqlFormatter + Finishes profiling for 'command', recording durations. - + - Roughly where in the calling code that this sql was executed. + Called when 'reader' finishes its iterations and is closed. - + - Offset from main MiniProfiler start that this sql began. + Information about a DbParameter used in the sql statement profiled by SqlTiming. - + - How long this sql statement took to execute. + Which SqlTiming this Parameter was executed with. - + - When executing readers, how long it took to come back initially from the database, - before all records are fetched and reader is closed. + Parameter name, e.g. "@routeName" - + - Stores any parameter names and values used by the profiled DbCommand. + The value submitted to the database. - + - Id of the Timing this statement was executed in. + System.Data.DbType, e.g. "String", "Bit" - - Needed for database deserialization. - - + - The Timing step that this sql execution occurred in. + How large the type is, e.g. for string, size could be 4000 - + - True when other identical sql statements have been executed during this MiniProfiler session. + Understands how to route and respond to MiniProfiler UI urls. - + - Gets part of a stack trace containing only methods we care about. + Returns this to handle . - + - Contains the default list of full type names we don't want in any stack trace snippets. + Returns either includes' css/javascript or results' html. - + - Understands how to store a to the with absolute expiration. + Handles rendering static content files. - + - The string that prefixes all keys that MiniProfilers are saved under, e.g. - "mini-profiler-ecfb0050-7ce8-4bf1-bf82-2cb38e90e31e". + Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query. - + - Returns a new HttpRuntimeCacheStorage class that will cache MiniProfilers for the specified duration. + Embedded resource contents keyed by filename. - + - Saves to the HttpRuntime.Cache under a key concated with - and . + Helper method that sets a proper 404 response code. - + - Returns the originally-stored + Try to keep everything static so we can easily be reused. - - - + - How long to cache each for (i.e. the absolute expiration parameter of - ) + Common extension methods to use only in this project - + - If the underlying command supports BindByName, this sets/clears the underlying - implementation accordingly. This is required to support OracleCommand from dapper-dot-net + Answers true if this String is either null or empty. + + + + + Answers true if this String is neither null or empty. + + + + + Removes trailing / characters from a path and leaves just one + + + + + Removes any leading / characters from a path + + + + + Removes any leading / characters from a path + + + + + Serializes to a json string.