Add priority

This commit is contained in:
2017-02-01 09:41:08 -05:00
parent 0711ae0ac8
commit e3779a323c
19 changed files with 365 additions and 83 deletions
+8
View File
@@ -87,6 +87,7 @@
<Compile Include="Entities\LeafGasComparisonPhotosyntheticInfo.cs" />
<Compile Include="Entities\LeafGasComparisonFittingInfo.cs" />
<Compile Include="Entities\LeafGasComparison.cs" />
<Compile Include="Entities\Priority.cs" />
<Compile Include="Entities\LeafInputStatusType.cs" />
<Compile Include="Entities\LeafOutputFile.cs" />
<Compile Include="Entities\LeafOutputFileContents.cs" />
@@ -112,6 +113,10 @@
<Compile Include="Migrations\201605210257006_LeafOutputFileContents.Designer.cs">
<DependentUpon>201605210257006_LeafOutputFileContents.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\201701311417095_PendingPriority.cs" />
<Compile Include="Migrations\201701311417095_PendingPriority.Designer.cs">
<DependentUpon>201701311417095_PendingPriority.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Parsers\LeafGasComparisonParser.cs" />
<Compile Include="Remote\IPiscalClient.cs" />
@@ -172,6 +177,9 @@
<EmbeddedResource Include="Migrations\201605210257006_LeafOutputFileContents.resx">
<DependentUpon>201605210257006_LeafOutputFileContents.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Migrations\201701311417095_PendingPriority.resx">
<DependentUpon>201701311417095_PendingPriority.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
+8
View File
@@ -54,6 +54,14 @@ namespace LeafWeb.Core.DAL
return _db.LeafInputs;
}
public IQueryable<LeafInput> GetLeafInputsOrdered()
{
return _db.LeafInputs
.OrderByDescending(li => li.CurrentStatus == LeafInputStatusType.Pending)
.ThenByDescending(li => li.PendingPriority)
.ThenByDescending(li => li.Id);
}
public LeafInput GetLeafInput(int id)
{
return _db.LeafInputs.FirstOrDefault(li => li.Id == id);
+42 -39
View File
@@ -8,17 +8,53 @@ using System.Linq;
namespace LeafWeb.Core.Entities
{
public abstract class LeafInputBase
public class LeafInput
{
public int Id { get; set; }
public virtual ICollection<LeafInputFile> InputFiles { get; set; }
public virtual ICollection<LeafInputData> LeafInputData { get; set; }
public virtual ICollection<LeafOutputFile> OutputFiles { get; set; }
[Required(ErrorMessage = "Name required")]
public string Name { get; set; }
[Required(ErrorMessage = "An email address is required")]
public string Email { get; set; }
[Required(ErrorMessage = "A unique identifier is required")]
public string Identifier { get; set; }
[Required(ErrorMessage = "Site Id required")]
public string SiteId { get; set; }
[Required]
[Column(TypeName = "VARCHAR")]
[StringLength(12)]
[Index("IX_UniqueToken", 1, IsUnique = true)]
public string UniqueToken { get; set; }
// [Required(ErrorMessage = "PhotosynthesisType required")]
// http://stackoverflow.com/questions/6038541/ef-validation-failing-on-update-when-using-lazy-loaded-required-properties
public virtual PhotosynthesisType PhotosynthesisType { get; set; }
[DataType(DataType.Date)]
[Required]
public DateTime Added { get; set; }
public LeafInputStatusType CurrentStatus { get; set; }
public virtual ICollection<LeafInputStatus> StatusHistory { get; set; }
public Priority PendingPriority { get; set; }
#region Calculated properties
public LeafOutputFile OutputErrorMessage => OutputFiles?.FirstOrDefault(f => f.IsErrorMessage);
public LeafOutputFile OutputWarningMessage => OutputFiles?.FirstOrDefault(f => f.IsWarningMessage);
public bool HasOutputFiles => OutputFiles.Any();
public bool HasLeafChart => OutputFiles.Any(f => f.IsLeafChartFile);
public LeafInputStatusType CurrentStatus { get; set; }
public virtual ICollection<LeafInputStatus> StatusHistory { get; set; }
public bool IsPending => CurrentStatus == LeafInputStatusType.Pending;
public bool IsStarting => CurrentStatus == LeafInputStatusType.Starting;
public bool IsRunning => CurrentStatus == LeafInputStatusType.Running;
@@ -42,7 +78,6 @@ namespace LeafWeb.Core.Entities
public bool IsDeletable => !IsInProgress;
public bool IsAtEndState => IsComplete || IsException || IsCancelled;
public DateTime? StartTime
{
get
@@ -71,7 +106,7 @@ namespace LeafWeb.Core.Entities
}
}
public TimeSpan TotalInProgressTime
public TimeSpan TimeInProgress
{
get
{
@@ -90,40 +125,8 @@ namespace LeafWeb.Core.Entities
return end.Value - start.Value;
}
}
}
public class LeafInput : LeafInputBase
{
public int Id { get; set; }
public virtual ICollection<LeafInputFile> InputFiles { get; set; }
public virtual ICollection<LeafInputData> LeafInputData { get; set; }
[Required(ErrorMessage = "Name required")]
public string Name { get; set; }
[Required(ErrorMessage = "An email address is required")]
public string Email { get; set; }
[Required(ErrorMessage = "A unique identifier is required")]
public string Identifier { get; set; }
[Required(ErrorMessage = "Site Id required")]
public string SiteId { get; set; }
[Required]
[Column(TypeName = "VARCHAR")]
[StringLength(12)]
[Index("IX_UniqueToken", 1, IsUnique = true)]
public string UniqueToken { get; set; }
// [Required(ErrorMessage = "PhotosynthesisType required")]
// http://stackoverflow.com/questions/6038541/ef-validation-failing-on-update-when-using-lazy-loaded-required-properties
public virtual PhotosynthesisType PhotosynthesisType { get; set; }
[DataType(DataType.Date)]
[Required]
public DateTime Added { get; set; }
#endregion
public override string ToString()
{
+9
View File
@@ -0,0 +1,9 @@
namespace LeafWeb.Core.Entities
{
public enum Priority
{
Normal = 0,
Low = -1,
High = 1
}
}
@@ -0,0 +1,29 @@
// <auto-generated />
namespace LeafWeb.Core.Migrations
{
using System.CodeDom.Compiler;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
[GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")]
public sealed partial class PendingPriority : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(PendingPriority));
string IMigrationMetadata.Id
{
get { return "201701311417095_PendingPriority"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,18 @@
namespace LeafWeb.Core.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class PendingPriority : DbMigration
{
public override void Up()
{
AddColumn("dbo.LeafInput", "PendingPriority", c => c.Int(nullable: false));
}
public override void Down()
{
DropColumn("dbo.LeafInput", "PendingPriority");
}
}
}
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.tezx-cyz.dll
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.ewo9-3jr.dll
+31 -4
View File
@@ -16,9 +16,7 @@ namespace LeafWeb.WebCms.Controllers
{
public ActionResult Index()
{
var resultItems =
DataService.GetLeafInputs()
.OrderByDescending(f => f.Id);
var resultItems = DataService.GetLeafInputsOrdered();
string serviceDescription;
try
@@ -43,7 +41,10 @@ namespace LeafWeb.WebCms.Controllers
var leafInput = DataService.GetLeafInput(id);
if (leafInput == null)
{
SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
}
var viewModel = new LeafInputDetails(leafInput);
return View(viewModel);
@@ -150,7 +151,11 @@ namespace LeafWeb.WebCms.Controllers
public ActionResult SendUserDownloadLink(int id)
{
var leafInput = DataService.GetLeafInput(id);
if (!leafInput.IsComplete)
if (leafInput == null)
{
SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
}
else if (!leafInput.IsComplete)
{
SetStatusMessage($"LeafInput '{leafInput.Identifier}' is not complete!", StatusType.Error);
}
@@ -164,6 +169,28 @@ namespace LeafWeb.WebCms.Controllers
return RedirectToCurrentUmbracoUrl();
}
[ActionLog]
public ActionResult Priority(int id, Priority priority)
{
var leafInput = DataService.GetLeafInput(id);
if (leafInput == null)
{
SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
}
else if (!leafInput.IsPending)
{
SetStatusMessage($"LeafInput '{leafInput.Identifier}' is no longer pending");
}
else
{
leafInput.PendingPriority = priority;
DataService.UpdateLeafInput(leafInput);
SetStatusMessage($"LeafInput '{leafInput.Identifier}' priority set to '{leafInput.PendingPriority}'", StatusType.Success);
}
return RedirectToCurrentUmbracoUrl();
}
[ActionLog]
public ActionResult SendUserChartLink(int id)
{
+2 -6
View File
@@ -3,7 +3,6 @@ using System.Linq;
using System.Web.Mvc;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Utility;
using LeafWeb.WebCms.Models;
namespace LeafWeb.WebCms.Controllers
{
@@ -13,12 +12,9 @@ namespace LeafWeb.WebCms.Controllers
{
var dateThreshold = DateTime.Today.Subtract(TimeSpan.FromDays(90));
var viewModel =
(
from li in DataService.GetLeafInputs()
from li in DataService.GetLeafInputsOrdered()
where li.Added >= dateThreshold
orderby li.Id descending
select li
);
select li;
return View(viewModel);
}
+3
View File
@@ -47,6 +47,9 @@ namespace LeafWeb.WebCms.Models
[Display(Name = "Piscal Warning")]
public string OutputWarningMessage { get; set; }
[Display(Name = "Time In Progress")]
public TimeSpan TimeInProgress { get; set; }
[UIHint("LeafInputStatusViewModels")]
public List<LeafInputStatusViewModel> StatusHistory { get; set; }
@@ -14,12 +14,12 @@ by editing this MSBuild file. In order to learn more about this please visit htt
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<MSDeployServiceURL>leafwebumbraco.scm.azurewebsites.net:443</MSDeployServiceURL>
<!-- Skip the deletion of any file within the ErrorLog directory -->
<MsDeploySkipRules>
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>Media</AbsolutePath>
</MsDeploySkipRules>
<!-- Skip the deletion of any file within the ErrorLog directory -->
<MsDeploySkipRules>
<SkipAction>Delete</SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>Media</AbsolutePath>
</MsDeploySkipRules>
<DeployIisAppPath>LeafWebUmbraco</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
@@ -30,7 +30,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt
<_DestinationType>AzureWebSite</_DestinationType>
<PublishDatabaseSettings>
<Objects xmlns="">
<ObjectGroup Name="LeafWebContext" Order="1" Enabled="False">
<ObjectGroup Name="LeafWebContext" Order="1" Enabled="True">
<Destination Path="Data Source=tcp:leafweb.database.windows.net,1433;Initial Catalog=leafwebUmbraco;User ID=lwadmin@leafweb;Password=j4f1a2e!" />
<Object Type="DbCodeFirst">
<Source Path="DBMigration" DbContext="LeafWeb.Core.DAL.LeafWebContext, Core" MigrationConfiguration="LeafWeb.Core.Migrations.Configuration, Core" Origin="Configuration" />
@@ -49,9 +49,9 @@ by editing this MSBuild file. In order to learn more about this please visit htt
</Objects>
</PublishDatabaseSettings>
</PropertyGroup>
<PropertyGroup>
<UseMsDeployExe>true</UseMsDeployExe>
</PropertyGroup>
<PropertyGroup>
<UseMsDeployExe>true</UseMsDeployExe>
</PropertyGroup>
<ItemGroup>
<MSDeployParameterValue Include="$(DeployParameterPrefix)LeafWebContext-Web.config Connection String">
<ParameterValue>Data Source=tcp:leafweb.database.windows.net,1433;Initial Catalog=leafwebUmbraco;User ID=lwadmin@leafweb;Password=j4f1a2e!</ParameterValue>
@@ -185,9 +185,8 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
var pendingInput =
DataService
.GetLeafInputs(LeafInputStatusType.Pending)
.OrderBy(l => l.StatusHistory.Min(sh => sh.DateTime))
.FirstOrDefault();
.GetLeafInputsOrdered()
.FirstOrDefault(li => li.CurrentStatus == LeafInputStatusType.Pending);
if (pendingInput == null)
{
+23 -19
View File
@@ -1,4 +1,5 @@
@model QueueViewModel
@using LeafWeb.Core.Entities
@model QueueViewModel
@{
var grid = new WebGrid(Model.Items, rowsPerPage: 45);
@@ -15,7 +16,7 @@
grid.Column("SiteId", "Site Id"),
grid.Column("Name", "Submitted By"),
//grid.Column("FileCount", "Input files"),
grid.Column("TotalInProgressTime", "In-Progress Time", item => ((TimeSpan)item.TotalInProgressTime).ToRoundedReadableString()),
grid.Column("TimeInProgress", "Time In Progress", item => TimeInProgress(item.TimeInProgress)),
grid.Column("CurrentStatus", "Status", item => Html.Partial("DisplayTemplates/_LeafInputStatus", (string)item.CurrentStatus.ToString())),
grid.Column("Total Results: " + Model.Items.Count(), format: item => Btns(item))),
htmlAttributes: new { @class = "table table-striped table-bordered table-hover table-condensed" }
@@ -33,15 +34,19 @@
<ul class="dropdown-menu">
<li>@DetailsLink(item)</li>
<li @DisableItem(!item.HasLeafChart)>@ChartLink(item)</li>
@if (item.IsPending)
{
<li role="separator" class="divider"></li>
<li class="dropdown-header">Priority</li>
<li @DisableItem(item.PendingPriority == Priority.High)>@PriorityForm(item, Priority.High)</li>
<li @DisableItem(item.PendingPriority == Priority.Normal)>@PriorityForm(item, Priority.Normal)</li>
<li @DisableItem(item.PendingPriority == Priority.Low)>@PriorityForm(item, Priority.Low)</li>
}
@if (item.IsCancellable)
{
<li role="separator" class="divider"></li>
<li>@CancelLink(item)</li>
}
@*<li role="separator" class="divider"></li>
<li class="dropdown-header">Priority</li>
<li>@SetPriorityHigh(item, "Set High")</li>
<li>@SetPriorityLow(item, "Set Low")</li>*@
<li role="separator" class="divider"></li>
<li class="dropdown-header">Download</li>
<li>@DownloadInput(item)</li>
@@ -63,19 +68,6 @@
@Html.Partial("DisplayTemplates/_ChartLink", (int)item.Id)
}
@helper SetPriorityHigh(dynamic item, string label)
{
<a href="@Url.Action("SetPriorityHigh", "Queue", new {id = item.Id})">
<span class="glyphicon glyphicon-arrow-up"></span> @label
</a>
}
@helper SetPriorityLow(dynamic item, string label)
{
<a href="@Url.Action("SetPriorityLow", "Queue", new {id = item.Id})">
<span class="glyphicon glyphicon-arrow-down"></span> @label
</a>
}
@helper DownloadInput(dynamic item)
{
<a href="@Url.Action("DownloadInput", "Queue", new {id = item.Id})">
@@ -88,6 +80,13 @@
<span class="glyphicon glyphicon-download"></span> ToUser
</a>
}
@helper TimeInProgress(TimeSpan timeSpan)
{
if (timeSpan > TimeSpan.Zero)
{
@timeSpan.ToRoundedReadableString()
}
}
@helper DeleteLink(dynamic item)
{
@Html.Partial("DisplayTemplates/_DeleteForm", (Tuple<int, string, bool>)Tuple.Create(item.Id, item.Identifier, item.IsDeletable))
@@ -98,6 +97,11 @@
@Html.Partial("DisplayTemplates/_CancelForm", (Tuple<int, string>)Tuple.Create(item.Id, item.Identifier))
}
@helper PriorityForm(dynamic item, Priority priority)
{
@Html.Partial("DisplayTemplates/_PriorityForm", (Tuple<int, Priority, Priority>)Tuple.Create(item.Id, item.PendingPriority, priority))
}
@helper DisableItem(bool disabled)
{
if (disabled) {<text>class="disabled"</text>}
+1 -1
View File
@@ -1,4 +1,4 @@
@model IOrderedQueryable<LeafWeb.Core.Entities.LeafInput>
@model IQueryable<LeafWeb.Core.Entities.LeafInput>
@{
var grid = new WebGrid(Model, rowsPerPage: 45);
@@ -0,0 +1,12 @@
@using LeafWeb.Core.Entities
@model Priority
@{
switch (Model)
{
case Priority.Normal:<span class="glyphicon glyphicon-unchecked"></span>break;
case Priority.Low:<span class="glyphicon glyphicon-collapse-down"></span>break;
case Priority.High:<span class="glyphicon glyphicon-collapse-up"></span>break;
default:
throw new ArgumentOutOfRangeException();
}
}
@@ -0,0 +1,13 @@
@model TimeSpan?
@{
Layout = "~/Views/Shared/DisplayTemplates/_FieldLayout.cshtml";
var val =
Model.HasValue
?
ViewData.ModelMetadata.DisplayFormatString != null
? string.Format(ViewData.ModelMetadata.DisplayFormatString, Model)
: Model.Value.ToReadableString()
: string.Empty;
}
@(Model == null ? Html.Encode(ViewData.ModelMetadata.NullDisplayText) : Html.Encode(val))
@@ -0,0 +1,24 @@
@using LeafWeb.WebCms.Controllers
@model Tuple<int, LeafWeb.Core.Entities.Priority, LeafWeb.Core.Entities.Priority>
@{
var leafInputId = Model.Item1;
var currentPriority = Model.Item2;
var formPriority = Model.Item3;
}
@if (currentPriority != formPriority)
{
using (Html.BeginUmbracoForm<QueueController>("Priority", null, new {@class = "clearfix"}))
{
<input type="hidden" name="id" value="@leafInputId"/>
<input type="hidden" name="priority" value="@formPriority"/>
<button type="submit" class="btn btn-link">
@Html.Partial("DisplayTemplates/PriorityIcon", formPriority) Set @formPriority
</button>
}
}
else
{
<a href="#" class="alert-warning">
@Html.Partial("DisplayTemplates/PriorityIcon", formPriority) @formPriority
</a>
}
+3
View File
@@ -888,6 +888,9 @@
<Content Include="Views\Shared\EditorTemplates\TermsOfService.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\_DeleteForm.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\_CancelForm.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\TimeSpan.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\_PriorityForm.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\PriorityIcon.cshtml" />
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>