Add cancel
This commit is contained in:
@@ -17,8 +17,8 @@ namespace LeafWeb.Core.Tests.Remote
|
|||||||
new PiscalLeafInput
|
new PiscalLeafInput
|
||||||
{
|
{
|
||||||
LeafInputId = 1,
|
LeafInputId = 1,
|
||||||
PiscalDirectoryName = "TestDirectory3",
|
PiscalDirectoryName = "TestDirectory",
|
||||||
PhotosyntheticType = "C4_photosynthesis_leafweb",
|
PhotosyntheticType = "C3_photosynthesis_leafweb",
|
||||||
InputFiles = new[]
|
InputFiles = new[]
|
||||||
{
|
{
|
||||||
new PiscalLeafInputFile
|
new PiscalLeafInputFile
|
||||||
@@ -72,5 +72,12 @@ namespace LeafWeb.Core.Tests.Remote
|
|||||||
var client = GetTestClient();
|
var client = GetTestClient();
|
||||||
client.CleanupLeafProcess(_testInput);
|
client.CleanupLeafProcess(_testInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void KillLeafProcess()
|
||||||
|
{
|
||||||
|
var client = GetTestClient();
|
||||||
|
client.KillLeafProcess(_testInput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,26 @@ namespace LeafWeb.Core.Entities
|
|||||||
public LeafInputStatusType CurrentStatus { get; set; }
|
public LeafInputStatusType CurrentStatus { get; set; }
|
||||||
public virtual ICollection<LeafInputStatus> StatusHistory { get; set; }
|
public virtual ICollection<LeafInputStatus> StatusHistory { get; set; }
|
||||||
|
|
||||||
public bool IsInProgress => CurrentStatus == LeafInputStatusType.Starting
|
|
||||||
|| CurrentStatus == LeafInputStatusType.Running
|
|
||||||
|| CurrentStatus == LeafInputStatusType.Finishing;
|
|
||||||
|
|
||||||
public bool IsComplete => CurrentStatus == LeafInputStatusType.Complete;
|
|
||||||
public bool IsDeletable => !IsInProgress;
|
|
||||||
public bool IsPending => CurrentStatus == LeafInputStatusType.Pending;
|
public bool IsPending => CurrentStatus == LeafInputStatusType.Pending;
|
||||||
|
public bool IsStarting => CurrentStatus == LeafInputStatusType.Starting;
|
||||||
public bool IsRunning => CurrentStatus == LeafInputStatusType.Running;
|
public bool IsRunning => CurrentStatus == LeafInputStatusType.Running;
|
||||||
|
public bool IsFinishing => CurrentStatus == LeafInputStatusType.Finishing;
|
||||||
|
public bool IsComplete => CurrentStatus == LeafInputStatusType.Complete;
|
||||||
|
public bool IsException => CurrentStatus == LeafInputStatusType.Exception;
|
||||||
|
public bool IsCancelPending => CurrentStatus == LeafInputStatusType.CancelPending;
|
||||||
|
public bool IsCancelling => CurrentStatus == LeafInputStatusType.Cancelling;
|
||||||
|
public bool IsCancelled => CurrentStatus == LeafInputStatusType.Cancelled;
|
||||||
|
|
||||||
|
public bool IsInProgress => IsStarting
|
||||||
|
|| IsRunning
|
||||||
|
|| IsFinishing
|
||||||
|
|| IsCancelPending
|
||||||
|
|| IsCancelling;
|
||||||
|
public bool IsDeletable => !IsInProgress;
|
||||||
|
public bool HasOutputFiles => OutputFiles.Any();
|
||||||
|
public bool IsCancellable =>
|
||||||
|
IsRunning
|
||||||
|
|| IsPending;
|
||||||
|
|
||||||
[Required(ErrorMessage = "Name required")]
|
[Required(ErrorMessage = "Name required")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace LeafWeb.Core.Entities
|
|||||||
Running = 2,
|
Running = 2,
|
||||||
Finishing = 3,
|
Finishing = 3,
|
||||||
Complete = 4,
|
Complete = 4,
|
||||||
Exception = 5
|
Exception = 5,
|
||||||
|
CancelPending = 6,
|
||||||
|
Cancelling = 7,
|
||||||
|
Cancelled = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
void RunLeafInput(PiscalLeafInput leafInput);
|
void RunLeafInput(PiscalLeafInput leafInput);
|
||||||
PiscalStatus GetLeafInputStatus(PiscalLeafInput leafInput);
|
PiscalStatus GetLeafInputStatus(PiscalLeafInput leafInput);
|
||||||
IEnumerable<PiscalLeafOutputFile> RetrieveLeafOutput(PiscalLeafInput leafInput);
|
IEnumerable<PiscalLeafOutputFile> RetrieveLeafOutput(PiscalLeafInput leafInput);
|
||||||
|
void KillLeafProcess(PiscalLeafInput leafInput);
|
||||||
void CleanupLeafProcess(PiscalLeafInput leafInput);
|
void CleanupLeafProcess(PiscalLeafInput leafInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using LeafWeb.Core.Utility;
|
||||||
|
using Renci.SshNet;
|
||||||
|
|
||||||
namespace LeafWeb.Core.Remote
|
namespace LeafWeb.Core.Remote
|
||||||
{
|
{
|
||||||
public class PiscalClientException : Exception
|
public class PiscalClientException : Exception
|
||||||
{
|
{
|
||||||
public int LeafInputId { get; private set; }
|
public int LeafInputId { get; private set; }
|
||||||
|
public string CommandText { get; private set; }
|
||||||
|
|
||||||
public PiscalClientException(int leafInputId, string error) : base(error)
|
public PiscalClientException(int leafInputId, string error) : base(error)
|
||||||
{
|
{
|
||||||
LeafInputId = leafInputId;
|
LeafInputId = leafInputId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PiscalClientException(int leafInputId, SshCommand command) : base(
|
||||||
|
!string.IsNullOrEmpty(command.Error)
|
||||||
|
? command.Error.TrimEndNewLine()
|
||||||
|
: command.Result.TrimEndNewLine()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LeafInputId = leafInputId;
|
||||||
|
CommandText = command.CommandText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
Disconnect(leafInput, ssh);
|
Disconnect(leafInput, ssh);
|
||||||
|
|
||||||
if (command.ExitStatus != 0)
|
if (command.ExitStatus != 0)
|
||||||
throw new PiscalClientException(leafInput.LeafInputId, command.Error.TrimEndNewLine());
|
throw new PiscalClientException(leafInput.LeafInputId, command);
|
||||||
|
|
||||||
var result = command.Result.TrimEndNewLine();
|
var result = command.Result.TrimEndNewLine();
|
||||||
if (result == "started")
|
if (result == "started")
|
||||||
@@ -154,7 +154,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
Disconnect(leafInput, ssh);
|
Disconnect(leafInput, ssh);
|
||||||
|
|
||||||
if (command.ExitStatus != 0)
|
if (command.ExitStatus != 0)
|
||||||
throw new PiscalClientException(leafInput.LeafInputId, command.Error.TrimEndNewLine());
|
throw new PiscalClientException(leafInput.LeafInputId, command);
|
||||||
|
|
||||||
return command.Result
|
return command.Result
|
||||||
.SplitNewLine()
|
.SplitNewLine()
|
||||||
@@ -204,6 +204,21 @@ namespace LeafWeb.Core.Remote
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void KillLeafProcess(PiscalLeafInput leafInput)
|
||||||
|
{
|
||||||
|
using (var ssh = GetSshClient())
|
||||||
|
{
|
||||||
|
Connect(leafInput, ssh);
|
||||||
|
var commandText = $"{RemoteScriptPath} -d {leafInput.PiscalDirectoryName} -k";
|
||||||
|
var command = ssh.CreateCommand(commandText);
|
||||||
|
command.Execute();
|
||||||
|
Disconnect(leafInput, ssh);
|
||||||
|
|
||||||
|
if (command.ExitStatus != 0)
|
||||||
|
throw new PiscalClientException(leafInput.LeafInputId, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CleanupLeafProcess(PiscalLeafInput leafInput)
|
public void CleanupLeafProcess(PiscalLeafInput leafInput)
|
||||||
{
|
{
|
||||||
using (var ssh = GetSshClient())
|
using (var ssh = GetSshClient())
|
||||||
@@ -215,7 +230,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
Disconnect(leafInput, ssh);
|
Disconnect(leafInput, ssh);
|
||||||
|
|
||||||
if (command.ExitStatus != 0)
|
if (command.ExitStatus != 0)
|
||||||
throw new PiscalClientException(leafInput.LeafInputId, command.Error.TrimEndNewLine());
|
throw new PiscalClientException(leafInput.LeafInputId, command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace LeafWeb.WebCms.Tests.Models
|
|||||||
public void CanConstructFromLeafInputFile()
|
public void CanConstructFromLeafInputFile()
|
||||||
{
|
{
|
||||||
var leafInput = GetLeafInput();
|
var leafInput = GetLeafInput();
|
||||||
var viewModel = new ResultItemViewModel(leafInput);
|
var viewModel = new QueueItemViewModel(leafInput);
|
||||||
|
|
||||||
Assert.That(viewModel.CurrentStatus, Is.EqualTo(leafInput.CurrentStatus.ToString()));
|
Assert.That(viewModel.CurrentStatus, Is.EqualTo(leafInput.CurrentStatus.ToString()));
|
||||||
Assert.That(viewModel.LeafInputId, Is.EqualTo(leafInput.Id));
|
Assert.That(viewModel.LeafInputId, Is.EqualTo(leafInput.Id));
|
||||||
@@ -50,7 +50,7 @@ namespace LeafWeb.WebCms.Tests.Models
|
|||||||
var leafInput = GetLeafInput();
|
var leafInput = GetLeafInput();
|
||||||
leafInput.CurrentStatus = LeafInputStatusType.Running;
|
leafInput.CurrentStatus = LeafInputStatusType.Running;
|
||||||
leafInput.OutputFiles = new LeafOutputFile[0];
|
leafInput.OutputFiles = new LeafOutputFile[0];
|
||||||
var viewModel = new ResultItemViewModel(leafInput);
|
var viewModel = new QueueItemViewModel(leafInput);
|
||||||
|
|
||||||
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Running.ToString()));
|
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Running.ToString()));
|
||||||
//Assert.That(viewModel.LeafOutputFilenames, Has.Length.EqualTo(0));
|
//Assert.That(viewModel.LeafOutputFilenames, Has.Length.EqualTo(0));
|
||||||
@@ -71,7 +71,7 @@ namespace LeafWeb.WebCms.Tests.Models
|
|||||||
Status = LeafInputStatusType.Exception
|
Status = LeafInputStatusType.Exception
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var viewModel = new ResultItemViewModel(leafInput);
|
var viewModel = new QueueItemViewModel(leafInput);
|
||||||
|
|
||||||
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Exception.ToString()));
|
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Exception.ToString()));
|
||||||
//Assert.That(viewModel.ErrorMessages[0], Is.EqualTo(leafInput.StatusHistory.First().Description));
|
//Assert.That(viewModel.ErrorMessages[0], Is.EqualTo(leafInput.StatusHistory.First().Description));
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.rzzuwtuu.dll
|
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4._retrxtu.dll
|
||||||
@@ -90,6 +90,16 @@ a.banner-link:hover {
|
|||||||
content: "\e026"; }
|
content: "\e026"; }
|
||||||
.status.status-finishing:after {
|
.status.status-finishing:after {
|
||||||
content: "\e027"; }
|
content: "\e027"; }
|
||||||
|
.status.status-cancelpending, .status.status-cancelling {
|
||||||
|
color: #f0ad4e; }
|
||||||
|
.status.status-cancelled {
|
||||||
|
color: #ec971f; }
|
||||||
|
.status.status-cancelpending:after {
|
||||||
|
content: "\e090"; }
|
||||||
|
.status.status-cancelling:after {
|
||||||
|
content: "\e090"; }
|
||||||
|
.status.status-cancelled:after {
|
||||||
|
content: "\e090"; }
|
||||||
|
|
||||||
#chart {
|
#chart {
|
||||||
padding-top: 20px; }
|
padding-top: 20px; }
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
h1{padding:24px 0 12px 0;}p{padding:12px 0;}footer{margin-top:24px !important;}.row-no-padding [class*="col-"]{padding-left:0 !important;padding-right:0 !important;}.home .dark .row:first-child .column:first-child h1{padding-top:0;}.home .blogarchive{padding-top:20px;}.top-buffer{margin-top:20px;}.detail-actions>a,.detail-actions>form>button{margin-top:20px;float:left;clear:left;}.banner-link{white-space:normal;padding:20px;background:#000;background:rgba(0,0,0,.5);-moz-border-radius:10px;border-radius:10px;}.banner-link .glyphicon{color:#8cc641;}a.banner-link:hover{text-decoration:none;background:rgba(0,0,0,.6);}a.banner-link:hover .glyphicon{color:#a8ed4e;}.headline-icon h1:after{color:rgba(172,214,118,.8);font-family:"Glyphicons Halflings";font-size:.8em;padding-left:10px;}.headline-icon.headline-icon-file h1:after{content:"";}.headline-icon.headline-icon-leaf h1:after{content:"";}.headline-icon.headline-icon-question h1:after{content:"";}.headline-icon.headline-icon-stats h1:after{content:"";}.headline-icon.headline-icon-user h1:after{content:"";}.headline-icon.headline-icon-list h1:after{content:"";}.status{white-space:nowrap;}.status:after{font-family:"Glyphicons Halflings";font-size:.8em;padding-left:5px;}.status.status-pending{color:#f0ad4e;}.status.status-pending:after{content:"";}.status.status-complete{color:#337ab7;}.status.status-complete:after{content:"";}.status.status-exception{color:#a94442;}.status.status-exception:after{content:"";}.status.status-running,.status.status-starting,.status.status-finishing{color:#3c763d;}.status.status-running:after{content:"";}.status.status-starting:after{content:"";}.status.status-finishing:after{content:"";}#chart{padding-top:20px;}.btn-file{position:relative;overflow:hidden;}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block;}form .validation-summary-errors ul{list-style-type:none;}.autocomplete-suggestions{border:1px solid #999;background:#fff;overflow:auto;}.autocomplete-suggestion{padding:2px 5px;white-space:nowrap;overflow:hidden;}.autocomplete-selected{background:#f0f0f0;}.autocomplete-suggestions strong{font-weight:normal;color:#39f;}.autocomplete-group{padding:2px 5px;}.autocomplete-group strong{display:block;border-bottom:1px solid #000;}.toggle{width:15px;}.dropdown-menu li form .btn-link{display:block;color:#333;clear:both;float:left;font-size:1rem;font-weight:normal;line-height:1.42857;min-width:160px;padding:3px 20px;text-align:left;white-space:nowrap;}.dropdown-menu li form .btn-link:focus,.dropdown-menu li form .btn-link:hover{text-decoration:none;color:#262626;background-color:#f5f5f5;}.divider-right{border-right:1px dashed #333;}
|
h1{padding:24px 0 12px 0;}p{padding:12px 0;}footer{margin-top:24px !important;}.row-no-padding [class*="col-"]{padding-left:0 !important;padding-right:0 !important;}.home .dark .row:first-child .column:first-child h1{padding-top:0;}.home .blogarchive{padding-top:20px;}.top-buffer{margin-top:20px;}.detail-actions>a,.detail-actions>form>button{margin-top:20px;float:left;clear:left;}.banner-link{white-space:normal;padding:20px;background:#000;background:rgba(0,0,0,.5);-moz-border-radius:10px;border-radius:10px;}.banner-link .glyphicon{color:#8cc641;}a.banner-link:hover{text-decoration:none;background:rgba(0,0,0,.6);}a.banner-link:hover .glyphicon{color:#a8ed4e;}.headline-icon h1:after{color:rgba(172,214,118,.8);font-family:"Glyphicons Halflings";font-size:.8em;padding-left:10px;}.headline-icon.headline-icon-file h1:after{content:"";}.headline-icon.headline-icon-leaf h1:after{content:"";}.headline-icon.headline-icon-question h1:after{content:"";}.headline-icon.headline-icon-stats h1:after{content:"";}.headline-icon.headline-icon-user h1:after{content:"";}.headline-icon.headline-icon-list h1:after{content:"";}.status{white-space:nowrap;}.status:after{font-family:"Glyphicons Halflings";font-size:.8em;padding-left:5px;}.status.status-pending{color:#f0ad4e;}.status.status-pending:after{content:"";}.status.status-complete{color:#337ab7;}.status.status-complete:after{content:"";}.status.status-exception{color:#a94442;}.status.status-exception:after{content:"";}.status.status-running,.status.status-starting,.status.status-finishing{color:#3c763d;}.status.status-running:after{content:"";}.status.status-starting:after{content:"";}.status.status-finishing:after{content:"";}.status.status-cancelpending,.status.status-cancelling{color:#f0ad4e;}.status.status-cancelled{color:#ec971f;}.status.status-cancelpending:after{content:"";}.status.status-cancelling:after{content:"";}.status.status-cancelled:after{content:"";}#chart{padding-top:20px;}.btn-file{position:relative;overflow:hidden;}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block;}form .validation-summary-errors ul{list-style-type:none;}.autocomplete-suggestions{border:1px solid #999;background:#fff;overflow:auto;}.autocomplete-suggestion{padding:2px 5px;white-space:nowrap;overflow:hidden;}.autocomplete-selected{background:#f0f0f0;}.autocomplete-suggestions strong{font-weight:normal;color:#39f;}.autocomplete-group{padding:2px 5px;}.autocomplete-group strong{display:block;border-bottom:1px solid #000;}.toggle{width:15px;}.dropdown-menu li form .btn-link{display:block;color:#333;clear:both;float:left;font-size:1rem;font-weight:normal;line-height:1.42857;min-width:160px;padding:3px 20px;text-align:left;white-space:nowrap;}.dropdown-menu li form .btn-link:focus,.dropdown-menu li form .btn-link:hover{text-decoration:none;color:#262626;background-color:#f5f5f5;}.divider-right{border-right:1px dashed #333;}
|
||||||
@@ -112,6 +112,7 @@ a.banner-link:hover {
|
|||||||
content:"\e023";
|
content:"\e023";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.status-complete {
|
&.status-complete {
|
||||||
color: #337ab7;
|
color: #337ab7;
|
||||||
&:after {
|
&:after {
|
||||||
@@ -137,6 +138,22 @@ a.banner-link:hover {
|
|||||||
&.status-finishing:after {
|
&.status-finishing:after {
|
||||||
content:"\e027";
|
content:"\e027";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.status-cancelpending,&.status-cancelling {
|
||||||
|
color: #f0ad4e;
|
||||||
|
}
|
||||||
|
&.status-cancelled {
|
||||||
|
color: #ec971f;
|
||||||
|
}
|
||||||
|
&.status-cancelpending:after {
|
||||||
|
content:"\e090";
|
||||||
|
}
|
||||||
|
&.status-cancelling:after {
|
||||||
|
content:"\e090";
|
||||||
|
}
|
||||||
|
&.status-cancelled:after {
|
||||||
|
content:"\e090";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#chart {
|
#chart {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
using System.Web.Routing;
|
||||||
using log4net;
|
using log4net;
|
||||||
using LeafWeb.Core.DAL;
|
using LeafWeb.Core.DAL;
|
||||||
using Umbraco.Web.Mvc;
|
using Umbraco.Web.Mvc;
|
||||||
@@ -21,9 +22,7 @@ namespace LeafWeb.WebCms.Controllers
|
|||||||
{
|
{
|
||||||
if (filterContext?.Exception != null)
|
if (filterContext?.Exception != null)
|
||||||
{
|
{
|
||||||
var controller = filterContext.RouteData.Values["controller"].ToString();
|
var loggerName = LoggerName(filterContext.RouteData);
|
||||||
var action = filterContext.RouteData.Values["action"].ToString();
|
|
||||||
var loggerName = $"LeafWeb.WebCms.Controllers.{controller}Controller.{action}";
|
|
||||||
|
|
||||||
LogManager.GetLogger(loggerName).Error(filterContext.Exception);
|
LogManager.GetLogger(loggerName).Error(filterContext.Exception);
|
||||||
}
|
}
|
||||||
@@ -31,12 +30,14 @@ namespace LeafWeb.WebCms.Controllers
|
|||||||
base.OnException(filterContext);
|
base.OnException(filterContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool IsHttpParamActionMatch()
|
protected string LoggerName(RouteData routeData)
|
||||||
{
|
{
|
||||||
return ControllerContext.RouteData.Values["action"].ToString()
|
var controller = RouteData.Values["controller"].ToString();
|
||||||
.Equals("Action", StringComparison.InvariantCultureIgnoreCase);
|
var action = RouteData.Values["action"].ToString();
|
||||||
|
return $"LeafWeb.WebCms.Controllers.{controller}Controller.{action}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status messages to pages
|
||||||
protected enum StatusType
|
protected enum StatusType
|
||||||
{
|
{
|
||||||
Info,
|
Info,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
namespace LeafWeb.WebCms.Controllers
|
namespace LeafWeb.WebCms.Controllers
|
||||||
{
|
{
|
||||||
|
// Umbraco page IDs for LeafWeb application pages
|
||||||
public static class LeafWebPageIds
|
public static class LeafWebPageIds
|
||||||
{
|
{
|
||||||
public const int ManageQueue = 1107;
|
public const int ManageQueue = 1107;
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
|
using log4net;
|
||||||
using LeafWeb.Core.Entities;
|
using LeafWeb.Core.Entities;
|
||||||
using LeafWeb.Core.Utility;
|
using LeafWeb.Core.Utility;
|
||||||
|
using LeafWeb.WebCms.App_Start;
|
||||||
using LeafWeb.WebCms.Models;
|
using LeafWeb.WebCms.Models;
|
||||||
using LeafWeb.WebCms.Services;
|
using LeafWeb.WebCms.Services;
|
||||||
using LeafWeb.WebCms.Services.PiscalQueue;
|
using LeafWeb.WebCms.Services.PiscalQueue;
|
||||||
@@ -18,7 +20,7 @@ namespace LeafWeb.WebCms.Controllers
|
|||||||
DataService.GetLeafInputs()
|
DataService.GetLeafInputs()
|
||||||
.OrderByDescending(f => f.Id)
|
.OrderByDescending(f => f.Id)
|
||||||
.ToList()
|
.ToList()
|
||||||
.Select(leafInput => new ResultItemViewModel(leafInput));
|
.Select(leafInput => new QueueItemViewModel(leafInput));
|
||||||
|
|
||||||
string serviceDescription;
|
string serviceDescription;
|
||||||
try
|
try
|
||||||
@@ -121,6 +123,42 @@ namespace LeafWeb.WebCms.Controllers
|
|||||||
return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
|
return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ActionLog]
|
||||||
|
public ActionResult Cancel(int id)
|
||||||
|
{
|
||||||
|
var leafInput = DataService.GetLeafInput(id);
|
||||||
|
|
||||||
|
if (leafInput == null)
|
||||||
|
{
|
||||||
|
SetStatusMessage($"LeafInput '${id}' not found, may have been deleted?");
|
||||||
|
return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leafInput.IsPending)
|
||||||
|
{
|
||||||
|
LogManager.GetLogger(LoggerName(RouteData)).DebugFormat("LeafInput: {0}, Set Cancelled from Pending", leafInput.Id);
|
||||||
|
DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Cancelled,
|
||||||
|
"Emailing cancellation notification to user",
|
||||||
|
$"Email: \'{leafInput.Email}\'");
|
||||||
|
|
||||||
|
// send notification immediately
|
||||||
|
BackgroundJob.Enqueue<EmailNotificationService>(email => email.SendLeafWebCancelled(leafInput.Id));
|
||||||
|
SetStatusMessage($"Cancelling LeafInput '{leafInput.Identifier}'", StatusType.Success);
|
||||||
|
}
|
||||||
|
else if (leafInput.IsRunning)
|
||||||
|
{
|
||||||
|
DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.CancelPending);
|
||||||
|
SetStatusMessage($"Cancelling LeafInput '{leafInput.Identifier}'", StatusType.Success);
|
||||||
|
HangfireStartup.TriggerPiscalProcessQueue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// don't allow to be cancelled if it isn't currently running
|
||||||
|
SetStatusMessage($"LeafInput '{leafInput.Identifier}' is not currently running!", StatusType.Error);
|
||||||
|
}
|
||||||
|
return RedirectToCurrentUmbracoUrl();
|
||||||
|
}
|
||||||
|
|
||||||
[ActionLog]
|
[ActionLog]
|
||||||
public ActionResult SendUserDownloadLink(int id)
|
public ActionResult SendUserDownloadLink(int id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace LeafWeb.WebCms.Controllers
|
|||||||
orderby li.Id descending
|
orderby li.Id descending
|
||||||
select li
|
select li
|
||||||
).ToList()
|
).ToList()
|
||||||
.Select(leafInput => new ResultItemViewModel(leafInput));
|
.Select(leafInput => new QueueItemViewModel(leafInput));
|
||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,15 +47,15 @@ namespace LeafWeb.WebCms.Models
|
|||||||
[Display(Name = "Piscal Warning")]
|
[Display(Name = "Piscal Warning")]
|
||||||
public string OutputWarningMessage { get; set; }
|
public string OutputWarningMessage { get; set; }
|
||||||
|
|
||||||
//[UIHint("Status")]
|
|
||||||
//public string CurrentStatus { get; set; }
|
|
||||||
|
|
||||||
[UIHint("LeafInputStatusViewModels")]
|
[UIHint("LeafInputStatusViewModels")]
|
||||||
public List<LeafInputStatusViewModel> StatusHistory { get; set; }
|
public List<LeafInputStatusViewModel> StatusHistory { get; set; }
|
||||||
|
|
||||||
[HiddenInput(DisplayValue = false)]
|
[HiddenInput(DisplayValue = false)]
|
||||||
public bool HasLeafChart { get; set; }
|
public bool HasLeafChart { get; set; }
|
||||||
|
|
||||||
|
[HiddenInput(DisplayValue = false)]
|
||||||
|
public bool HasOutputFiles { get; set; }
|
||||||
|
|
||||||
[HiddenInput(DisplayValue = false)]
|
[HiddenInput(DisplayValue = false)]
|
||||||
public bool IsRunning { get; set; }
|
public bool IsRunning { get; set; }
|
||||||
|
|
||||||
@@ -65,6 +65,9 @@ namespace LeafWeb.WebCms.Models
|
|||||||
[HiddenInput(DisplayValue = false)]
|
[HiddenInput(DisplayValue = false)]
|
||||||
public bool IsDeletable { get; set; }
|
public bool IsDeletable { get; set; }
|
||||||
|
|
||||||
|
[HiddenInput(DisplayValue = false)]
|
||||||
|
public bool IsCancellable { get; set; }
|
||||||
|
|
||||||
static LeafInputDetails()
|
static LeafInputDetails()
|
||||||
{
|
{
|
||||||
Mapper.CreateMap<LeafInputFile, string>().ConvertUsing(file => file?.Contents.GetString());
|
Mapper.CreateMap<LeafInputFile, string>().ConvertUsing(file => file?.Contents.GetString());
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using LeafWeb.Core.Entities;
|
|||||||
|
|
||||||
namespace LeafWeb.WebCms.Models
|
namespace LeafWeb.WebCms.Models
|
||||||
{
|
{
|
||||||
public class ResultItemViewModel
|
public class QueueItemViewModel
|
||||||
{
|
{
|
||||||
public int LeafInputId { get; set; }
|
public int LeafInputId { get; set; }
|
||||||
public string LeafInputName { get; set; }
|
public string LeafInputName { get; set; }
|
||||||
@@ -15,16 +15,18 @@ namespace LeafWeb.WebCms.Models
|
|||||||
public bool IsRunning { get; set; }
|
public bool IsRunning { get; set; }
|
||||||
public bool IsComplete { get; set; }
|
public bool IsComplete { get; set; }
|
||||||
public bool IsDeletable { get; set; }
|
public bool IsDeletable { get; set; }
|
||||||
|
public bool IsCancellable { get; set; }
|
||||||
public bool IsPending { get; set; }
|
public bool IsPending { get; set; }
|
||||||
|
public bool HasOutputFiles { get; set; }
|
||||||
public string CurrentStatus { get; set; }
|
public string CurrentStatus { get; set; }
|
||||||
|
|
||||||
//public string[] ErrorMessages { get; set; }
|
//public string[] ErrorMessages { get; set; }
|
||||||
//public string[] LeafOutputFilenames { get; set; }
|
//public string[] LeafOutputFilenames { get; set; }
|
||||||
//public bool HasLeafChartOutputFile { get; set; }
|
//public bool HasLeafChartOutputFile { get; set; }
|
||||||
|
|
||||||
static ResultItemViewModel()
|
static QueueItemViewModel()
|
||||||
{
|
{
|
||||||
Mapper.CreateMap<LeafInput, ResultItemViewModel>()
|
Mapper.CreateMap<LeafInput, QueueItemViewModel>()
|
||||||
.ForMember(dest => dest.LeafInputId, opt => opt.MapFrom(src => src.Id))
|
.ForMember(dest => dest.LeafInputId, opt => opt.MapFrom(src => src.Id))
|
||||||
.ForMember(dest => dest.HasLeafChart, opt => opt.ResolveUsing(src => src.OutputFiles.Any(o => o.IsLeafChartFile)))
|
.ForMember(dest => dest.HasLeafChart, opt => opt.ResolveUsing(src => src.OutputFiles.Any(o => o.IsLeafChartFile)))
|
||||||
//.ForMember(dest => dest.LeafOutputFilenames,
|
//.ForMember(dest => dest.LeafOutputFilenames,
|
||||||
@@ -52,7 +54,7 @@ namespace LeafWeb.WebCms.Models
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultItemViewModel(LeafInput leafInput)
|
public QueueItemViewModel(LeafInput leafInput)
|
||||||
{
|
{
|
||||||
Mapper.Map(leafInput, this);
|
Mapper.Map(leafInput, this);
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ namespace LeafWeb.WebCms.Models
|
|||||||
{
|
{
|
||||||
public string ServerDescription { get; set; }
|
public string ServerDescription { get; set; }
|
||||||
public string ServerStatus { get; set; }
|
public string ServerStatus { get; set; }
|
||||||
public IEnumerable<ResultItemViewModel> Items { get; set; }
|
public IEnumerable<QueueItemViewModel> Items { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ namespace LeafWeb.WebCms.Services
|
|||||||
private const string EmailSuccessSubject = "LeafWeb results";
|
private const string EmailSuccessSubject = "LeafWeb results";
|
||||||
private const string EmailErrorSubject = "LeafWeb processing error";
|
private const string EmailErrorSubject = "LeafWeb processing error";
|
||||||
private const string EmailSystemErrorSubject = "LeafWeb system error";
|
private const string EmailSystemErrorSubject = "LeafWeb system error";
|
||||||
|
private const string EmailCancelledSubject = "LeafWeb cancelled";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comma separated values
|
/// Comma separated values
|
||||||
@@ -32,6 +33,11 @@ namespace LeafWeb.WebCms.Services
|
|||||||
|
|
||||||
private readonly DownloadUrlService _downloadUrlService;
|
private readonly DownloadUrlService _downloadUrlService;
|
||||||
|
|
||||||
|
private string FormatSubject(string subject, LeafInput leafInput)
|
||||||
|
{
|
||||||
|
return subject + $" - '{leafInput.Identifier}'";
|
||||||
|
}
|
||||||
|
|
||||||
public EmailNotificationService(DataService dataService)
|
public EmailNotificationService(DataService dataService)
|
||||||
{
|
{
|
||||||
_dataService = dataService;
|
_dataService = dataService;
|
||||||
@@ -60,8 +66,10 @@ namespace LeafWeb.WebCms.Services
|
|||||||
var leafInput = _dataService.GetLeafInput(leafInputId);
|
var leafInput = _dataService.GetLeafInput(leafInputId);
|
||||||
if (leafInput.CurrentStatus != LeafInputStatusType.Complete)
|
if (leafInput.CurrentStatus != LeafInputStatusType.Complete)
|
||||||
{
|
{
|
||||||
Logger.Error($"Attempting to SendLeafWebComplete when status is not complete for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}");
|
var notComplete = "Attempting to SendLeafWebComplete when status is not complete" +
|
||||||
throw new ArgumentException($"Attempting to SendLeafWebComplete when status is not complete for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}");
|
$" for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}";
|
||||||
|
Logger.Error(notComplete);
|
||||||
|
throw new ArgumentException(notComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputErrorMessage = leafInput.OutputErrorMessage;
|
var outputErrorMessage = leafInput.OutputErrorMessage;
|
||||||
@@ -71,6 +79,24 @@ namespace LeafWeb.WebCms.Services
|
|||||||
SendLeafWebSuccess(leafInput);
|
SendLeafWebSuccess(leafInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendLeafWebCancelled(int leafInputId)
|
||||||
|
{
|
||||||
|
var leafInput = _dataService.GetLeafInput(leafInputId);
|
||||||
|
if (leafInput.CurrentStatus != LeafInputStatusType.Cancelled)
|
||||||
|
{
|
||||||
|
var notComplete = "Attempting to SendLeafWebCancelled when status is not complete " +
|
||||||
|
$"for leafInput: {leafInput}, current status: {leafInput.CurrentStatus}";
|
||||||
|
Logger.Error(notComplete);
|
||||||
|
throw new ArgumentException(notComplete);
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = $"Your leaf analysis job, {leafInput.Identifier}, has been cancelled. " +
|
||||||
|
"Contact the administrator with any questions.";
|
||||||
|
|
||||||
|
var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailCancelledSubject, leafInput), body);
|
||||||
|
SendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
public void SendAdministratorMessage(string subject, string body)
|
public void SendAdministratorMessage(string subject, string body)
|
||||||
{
|
{
|
||||||
var message = new MailMessage(_emailFromAddress, _adminEmailAddresses, subject, body);
|
var message = new MailMessage(_emailFromAddress, _adminEmailAddresses, subject, body);
|
||||||
@@ -94,7 +120,7 @@ namespace LeafWeb.WebCms.Services
|
|||||||
+ Environment.NewLine + Environment.NewLine
|
+ Environment.NewLine + Environment.NewLine
|
||||||
+ downloadUrl;
|
+ downloadUrl;
|
||||||
|
|
||||||
var message = new MailMessage(_emailFromAddress, leafInput.Email, EmailSuccessSubject, body);
|
var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailSuccessSubject, leafInput), body);
|
||||||
SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -138,7 +164,7 @@ namespace LeafWeb.WebCms.Services
|
|||||||
|
|
||||||
body += FormatWarningMessage(leafInput);
|
body += FormatWarningMessage(leafInput);
|
||||||
|
|
||||||
var message = new MailMessage(_emailFromAddress, leafInput.Email, EmailErrorSubject, body);
|
var message = new MailMessage(_emailFromAddress, leafInput.Email, FormatSubject(EmailErrorSubject, leafInput), body);
|
||||||
SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,13 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
UpdateCancelling();
|
||||||
|
|
||||||
|
StartCancelPending();
|
||||||
|
|
||||||
UpdateRunning();
|
UpdateRunning();
|
||||||
|
|
||||||
StartNextPending();
|
StartNextPending();
|
||||||
|
|
||||||
// TODO: handle starting and finishing
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -38,18 +40,91 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: clear any stalled processes
|
private void StartCancelPending()
|
||||||
private void ClearStalled()
|
|
||||||
{
|
{
|
||||||
var leafInputs =
|
var cancelPendingLeafInputs =
|
||||||
DataService.GetLeafInputs(
|
DataService.GetLeafInputs(
|
||||||
LeafInputStatusType.Starting,
|
LeafInputStatusType.CancelPending
|
||||||
LeafInputStatusType.Finishing
|
).ToList();
|
||||||
)
|
|
||||||
.Where(li =>
|
foreach (var leafInput in cancelPendingLeafInputs)
|
||||||
li.StatusHistory.OrderBy(sh => sh.DateTime).First().DateTime
|
{
|
||||||
> DateTime.Now.Subtract(TimeSpan.FromHours(1)))
|
try
|
||||||
.ToList();
|
{
|
||||||
|
var status = PiscalService.GetStatus(leafInput);
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case PiscalStatus.Running:
|
||||||
|
Logger.DebugFormat("LeafInput: {0}, Set Cancelling", leafInput.Id);
|
||||||
|
DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Cancelling);
|
||||||
|
|
||||||
|
Logger.InfoFormat("LeafInput: {0}, Kill", leafInput.Id);
|
||||||
|
PiscalService.Kill(leafInput);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PiscalStatus.Complete:
|
||||||
|
Logger.DebugFormat("LeafInput: {0}, Piscal Complete after cancelled - " +
|
||||||
|
"setting to Running to copy output and notify user", leafInput.Id);
|
||||||
|
DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Running,
|
||||||
|
"Piscal Complete after cancelled - setting to Running to copy output and notify user");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PiscalClientException ex)
|
||||||
|
{
|
||||||
|
PiscalExceptionHandler(ex, leafInput);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var errorMessage = FormatException(ex);
|
||||||
|
Logger.Error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCancelling()
|
||||||
|
{
|
||||||
|
var cancellingLeafInputs =
|
||||||
|
DataService.GetLeafInputs(
|
||||||
|
LeafInputStatusType.Cancelling
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
foreach (var leafInput in cancellingLeafInputs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var status = PiscalService.GetStatus(leafInput);
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case PiscalStatus.Running:
|
||||||
|
Logger.InfoFormat("LeafInput: {0}, Piscal Running - still cancelling", leafInput.Id);
|
||||||
|
// continue running
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PiscalStatus.Complete:
|
||||||
|
Logger.DebugFormat("LeafInput: {0}, Set Cancelled", leafInput.Id);
|
||||||
|
DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Cancelled,
|
||||||
|
"Emailing cancellation notification to user and cleaning up files on Piscal",
|
||||||
|
$"Email: \'{leafInput.Email}\'");
|
||||||
|
|
||||||
|
BackgroundJobEnqueueRetry<EmailNotificationService>(email => email.SendLeafWebCancelled(leafInput.Id));
|
||||||
|
|
||||||
|
Logger.InfoFormat("LeafInput: {0}, Cleanup", leafInput.Id);
|
||||||
|
PiscalService.Cleanup(leafInput);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PiscalClientException ex)
|
||||||
|
{
|
||||||
|
PiscalExceptionHandler(ex, leafInput);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var errorMessage = FormatException(ex);
|
||||||
|
Logger.Error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartNextPending()
|
private void StartNextPending()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
|
|||||||
if (!string.IsNullOrEmpty(_notifyCompleteUrl))
|
if (!string.IsNullOrEmpty(_notifyCompleteUrl))
|
||||||
inputFile.NotifyCompleteUrl = _notifyCompleteUrl;
|
inputFile.NotifyCompleteUrl = _notifyCompleteUrl;
|
||||||
|
|
||||||
// TODO: remove this, just for testing
|
// NOTE: Assume that from this address we don't want to store it
|
||||||
if (string.Equals(leafInput.Email, "james.kolpack@gmail.com", StringComparison.InvariantCultureIgnoreCase))
|
if (string.Equals(leafInput.Email, "james.kolpack@gmail.com", StringComparison.InvariantCultureIgnoreCase))
|
||||||
inputFile.SuppressStorageCopy = true;
|
inputFile.SuppressStorageCopy = true;
|
||||||
_piscalClient.RunLeafInput(inputFile);
|
_piscalClient.RunLeafInput(inputFile);
|
||||||
@@ -64,5 +64,11 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
|
|||||||
var input = new PiscalLeafInput(leafInput);
|
var input = new PiscalLeafInput(leafInput);
|
||||||
_piscalClient.CleanupLeafProcess(input);
|
_piscalClient.CleanupLeafProcess(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Kill(LeafInput leafInput)
|
||||||
|
{
|
||||||
|
var input = new PiscalLeafInput(leafInput);
|
||||||
|
_piscalClient.KillLeafProcess(input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="@Url.Action("DownloadOutputToUser", "Queue", new {id = Model.LeafInputId})"
|
<a href="@Url.Action("DownloadOutputToUser", "Queue", new {id = Model.LeafInputId})"
|
||||||
class="btn btn-default@{if (!Model.IsComplete)
|
class="btn btn-default@{if (!Model.HasOutputFiles)
|
||||||
{<text> disabled</text>}}" role="button">
|
{<text> disabled</text>}}" role="button">
|
||||||
<span class="glyphicon glyphicon-download"></span> Download ToUser
|
<span class="glyphicon glyphicon-download"></span> Download ToUser
|
||||||
</a>
|
</a>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"SendUserDownloadLink", null, new { @class = "confirm", confirm_msg = "Confirm sending email to user" }))
|
"SendUserDownloadLink", null, new { @class = "confirm", confirm_msg = "Confirm sending email to user" }))
|
||||||
{
|
{
|
||||||
<input type="hidden" name="id" value="@Model.LeafInputId" />
|
<input type="hidden" name="id" value="@Model.LeafInputId" />
|
||||||
<button type="submit" class="btn btn-default" @{if (!Model.IsComplete) { <text> disabled="disabled" </text> }}>
|
<button type="submit" class="btn btn-default" @{if (!Model.HasOutputFiles) { <text> disabled="disabled" </text> }}>
|
||||||
<span class="glyphicon glyphicon-send"></span> Email User Download link
|
<span class="glyphicon glyphicon-send"></span> Email User Download link
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li>@DetailsLink(item)</li>
|
<li>@DetailsLink(item)</li>
|
||||||
<li @DisableItem(!item.HasLeafChart)>@ChartLink(item)</li>
|
<li @DisableItem(!item.HasLeafChart)>@ChartLink(item)</li>
|
||||||
|
@if (item.IsCancellable)
|
||||||
|
{
|
||||||
|
<li role="separator" class="divider"></li>
|
||||||
|
<li>@CancelLink(item)</li>
|
||||||
|
}
|
||||||
@*<li role="separator" class="divider"></li>
|
@*<li role="separator" class="divider"></li>
|
||||||
<li class="dropdown-header">Priority</li>
|
<li class="dropdown-header">Priority</li>
|
||||||
<li>@SetPriorityHigh(item, "Set High")</li>
|
<li>@SetPriorityHigh(item, "Set High")</li>
|
||||||
@@ -39,7 +44,7 @@
|
|||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li class="dropdown-header">Download</li>
|
<li class="dropdown-header">Download</li>
|
||||||
<li>@DownloadInput(item)</li>
|
<li>@DownloadInput(item)</li>
|
||||||
<li @DisableItem(!item.IsComplete)>@DownloadOutputToUser(item)</li>
|
<li @DisableItem(!item.HasOutputFiles)>@DownloadOutputToUser(item)</li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li @DisableItem(!item.IsDeletable)>@DeleteLink(item)</li>
|
<li @DisableItem(!item.IsDeletable)>@DeleteLink(item)</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -87,6 +92,11 @@
|
|||||||
@Html.Partial("DisplayTemplates/_DeleteForm", (Tuple<int, string, bool>)Tuple.Create(item.LeafInputId, item.LeafInputIdentifier, item.IsDeletable))
|
@Html.Partial("DisplayTemplates/_DeleteForm", (Tuple<int, string, bool>)Tuple.Create(item.LeafInputId, item.LeafInputIdentifier, item.IsDeletable))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@helper CancelLink(dynamic item)
|
||||||
|
{
|
||||||
|
@Html.Partial("DisplayTemplates/_CancelForm", (Tuple<int, string>)Tuple.Create(item.LeafInputId, item.LeafInputIdentifier))
|
||||||
|
}
|
||||||
|
|
||||||
@helper DisableItem(bool disabled)
|
@helper DisableItem(bool disabled)
|
||||||
{
|
{
|
||||||
if (disabled) {<text>class="disabled"</text>}
|
if (disabled) {<text>class="disabled"</text>}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@model IEnumerable<ResultItemViewModel>
|
@model IEnumerable<QueueItemViewModel>
|
||||||
|
|
||||||
@{
|
@{
|
||||||
var grid = new WebGrid(Model, rowsPerPage: 45);
|
var grid = new WebGrid(Model, rowsPerPage: 45);
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
@using LeafWeb.WebCms.Controllers
|
||||||
|
@model Tuple<int, string>
|
||||||
|
@{
|
||||||
|
var leafInputId = Model.Item1;
|
||||||
|
var identifier = Model.Item2;
|
||||||
|
}
|
||||||
|
@using (Html.BeginUmbracoForm<QueueController>("Cancel", null,
|
||||||
|
new { @class = "confirm", confirm_msg = "Cancelling cannot be undone! Confirm cancelling '" + identifier + "'." }))
|
||||||
|
{
|
||||||
|
<input type="hidden" name="id" value="@leafInputId"/>
|
||||||
|
<button type="submit" class="btn btn-link">
|
||||||
|
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
|
||||||
|
</button>
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
@model string
|
@using LeafWeb.Core.Utility
|
||||||
<span class="status status-@Model.ToLower()">@Model</span>
|
@model string
|
||||||
|
<span class="status status-@Model.ToLower()">@Model.SplitCamelCase()</span>
|
||||||
+12
-1
@@ -67,7 +67,7 @@
|
|||||||
<add key="SmtpUserName" value="" />
|
<add key="SmtpUserName" value="" />
|
||||||
<add key="SmtpPassword" value="" />
|
<add key="SmtpPassword" value="" />
|
||||||
<add key="LeafWebUrl" value="http://192.168.1.133:61755/" />
|
<add key="LeafWebUrl" value="http://192.168.1.133:61755/" />
|
||||||
<add key="PiscalNotifyCompleteUrlPath" value="LeafInput/NotifyComplete" />
|
<add key="PiscalNotifyCompleteUrlPath" value="umbraco/surface/LeafInput/NotifyComplete" />
|
||||||
<add key="ResultsDownloadPath" value="Results/Download?token={0}" />
|
<add key="ResultsDownloadPath" value="Results/Download?token={0}" />
|
||||||
</appSettings>
|
</appSettings>
|
||||||
<connectionStrings>
|
<connectionStrings>
|
||||||
@@ -341,6 +341,17 @@
|
|||||||
<requestLimits maxAllowedContentLength="1000000000" />
|
<requestLimits maxAllowedContentLength="1000000000" />
|
||||||
</requestFiltering>
|
</requestFiltering>
|
||||||
</security>
|
</security>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<rule name="Redirect leafweb.ornl.gov to www.leafweb.org" stopProcessing="true">
|
||||||
|
<match url=".*" />
|
||||||
|
<conditions>
|
||||||
|
<add input="{HTTP_HOST}" pattern="^leafweb.ornl.gov$" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Redirect" url="http://www.leafweb.org/" redirectType="Permanent" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
<runtime>
|
<runtime>
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
|||||||
@@ -887,6 +887,7 @@
|
|||||||
<Content Include="Views\EmptyPage.cshtml" />
|
<Content Include="Views\EmptyPage.cshtml" />
|
||||||
<Content Include="Views\Shared\EditorTemplates\TermsOfService.cshtml" />
|
<Content Include="Views\Shared\EditorTemplates\TermsOfService.cshtml" />
|
||||||
<Content Include="Views\Shared\DisplayTemplates\_DeleteForm.cshtml" />
|
<Content Include="Views\Shared\DisplayTemplates\_DeleteForm.cshtml" />
|
||||||
|
<Content Include="Views\Shared\DisplayTemplates\_CancelForm.cshtml" />
|
||||||
<None Include="Web.Debug.config">
|
<None Include="Web.Debug.config">
|
||||||
<DependentUpon>Web.config</DependentUpon>
|
<DependentUpon>Web.config</DependentUpon>
|
||||||
</None>
|
</None>
|
||||||
@@ -923,7 +924,7 @@
|
|||||||
<Compile Include="Models\LeafInputDetails.cs" />
|
<Compile Include="Models\LeafInputDetails.cs" />
|
||||||
<Compile Include="Models\LeafInputCreate.cs" />
|
<Compile Include="Models\LeafInputCreate.cs" />
|
||||||
<Compile Include="Models\LeafInputStatusViewModel.cs" />
|
<Compile Include="Models\LeafInputStatusViewModel.cs" />
|
||||||
<Compile Include="Models\ResultItemViewModel.cs" />
|
<Compile Include="Models\QueueItemViewModel.cs" />
|
||||||
<Compile Include="Models\QueueViewModel.cs" />
|
<Compile Include="Models\QueueViewModel.cs" />
|
||||||
<Compile Include="Models\SelectListViewModel.cs" />
|
<Compile Include="Models\SelectListViewModel.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
$("form#create").data("validator").settings.submitHandler =
|
$("form#create").data("validator").settings.submitHandler =
|
||||||
function (form) {
|
function (form) {
|
||||||
var identifier = $(form).find("input[name='Identifier']").val();
|
var identifier = $(form).find("input[name='Identifier']").val();
|
||||||
$("<div>" + "Confirm submitting " + identifier + "</div>")
|
$("<div id='confirmCreate'>" + "Please confirm submitting '" + identifier + "'</div>")
|
||||||
.dialog({
|
.dialog({
|
||||||
buttons: {
|
buttons: {
|
||||||
"Confirm": function () {
|
"Confirm": function () {
|
||||||
|
$("#confirmCreate")
|
||||||
|
.next(".ui-dialog-buttonpane button:contains('Confirm')")
|
||||||
|
.attr("disabled", true);
|
||||||
form.submit();
|
form.submit();
|
||||||
},
|
},
|
||||||
"Cancel": function () {
|
"Cancel": function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user