Update: SignalR 2.0.3 Migration; Noticeboards

Migrate all SignalR 1.x Persistent Connections to SignalR 2.x Hubs.
Abstracts ScheduledTaskStatus with core interface and adds a Mock for
optional status reporting. Noticeboards rewritten (with new theme) to be
more resilient and accurate.
This commit is contained in:
Gary Sharp
2014-06-01 23:27:07 +10:00
parent f6fae26bc7
commit 4cd57f4a90
116 changed files with 9874 additions and 6462 deletions
@@ -1,7 +1,6 @@
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.AspNet.SignalR;
using Disco.BI.Interop.SignalRHandlers;
namespace Disco.Web.Areas.API
{
@@ -17,15 +16,6 @@ namespace Disco.Web.Areas.API
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapConnection<LogNotifications>(
"API_Logging_Notifications", "API/Logging/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
context.Routes.MapConnection<ScheduledTasksStatusNotifications>(
"API_Logging_TaskStatusNotifications", "API/Logging/TaskStatusNotifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
context.Routes.MapConnection<RepositoryMonitorNotifications>(
"API_Repository_Notifications", "API/Repository/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
context.MapRoute(
"API_Update",
"API/{controller}/Update/{id}/{key}",
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Disco.BI;
using Disco.BI.Extensions;
using Disco.Services;
using System;
namespace Disco.Web.Areas.API.Models.Attachment
{
@@ -27,7 +23,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
ParentId = ua.UserId,
Id = ua.Id,
AuthorId = ua.TechUserId,
Author = ua.TechUser.ToString(),
Author = ua.TechUser.ToStringFriendly(),
Timestamp = ua.Timestamp,
Comments = ua.Comments,
Filename = ua.Filename,
@@ -41,7 +37,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
ParentId = ja.JobId.ToString(),
Id = ja.Id,
AuthorId = ja.TechUserId,
Author = ja.TechUser.ToString(),
Author = ja.TechUser.ToStringFriendly(),
Timestamp = ja.Timestamp,
Comments = ja.Comments,
Filename = ja.Filename,
@@ -55,7 +51,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
ParentId = da.DeviceSerialNumber,
Id = da.Id,
AuthorId = da.TechUserId,
Author = da.TechUser.ToString(),
Author = da.TechUser.ToStringFriendly(),
Timestamp = da.Timestamp,
Comments = da.Comments,
Filename = da.Filename,
@@ -1,4 +1,5 @@
using Disco.Models.UI.Config.Logging;
using Disco.Models.UI.Config.Shared;
using Disco.Services.Authorization;
using Disco.Services.Logging;
using Disco.Services.Logging.Models;
@@ -42,10 +43,10 @@ namespace Disco.Web.Areas.Config.Controllers
if (taskStatus == null)
return RedirectToAction(MVC.Config.Logging.Index());
var m = new Models.Logging.TaskStatusModel() { SessionId = taskStatus.SessionId };
var m = new Models.Shared.TaskStatusModel() { SessionId = taskStatus.SessionId };
// UI Extensions
UIExtensions.ExecuteExtensions<ConfigLoggingTaskStatusModel>(this.ControllerContext, m);
UIExtensions.ExecuteExtensions<ConfigSharedTaskStatusModel>(this.ControllerContext, m);
return View(m);
}
@@ -1,13 +0,0 @@
using Disco.Models.UI.Config.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.Config.Models.Logging
{
public class TaskStatusModel : ConfigLoggingTaskStatusModel
{
public string SessionId { get; set; }
}
}
@@ -0,0 +1,13 @@
using Disco.Models.UI.Config.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Disco.Web.Areas.Config.Models.Shared
{
public class TaskStatusModel : ConfigSharedTaskStatusModel
{
public string SessionId { get; set; }
}
}
@@ -1,255 +1,5 @@
@model Disco.Web.Areas.Config.Models.Logging.TaskStatusModel
@model Disco.Web.Areas.Config.Models.Shared.TaskStatusModel
@{
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Logging", MVC.Config.Logging.Index(), "Task Status");
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
}
<div style="min-height: 300px;">
<div id="scheduledTaskStatus" class="form" style="width: 520px;" data-bind="visible: Initialized">
<h2 data-bind="text: TaskName">&nbsp;</h2>
<table>
<tr data-bind="visible: IsRunning">
<th class="process" data-bind="text: CurrentProcess">&nbsp;
</th>
</tr>
<tr data-bind="visible: IsRunning">
<td class="description" data-bind="text: CurrentDescription">&nbsp;
</td>
</tr>
<tr data-bind="visible: IsRunning">
<td class="progress">
<div data-bind="progressValue: Progress">
</div>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp">
<td class="finishedTimestamp">
<h3>Finished: <span data-bind="text: FinishedTimestampFormatted"></span>
</h3>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp() && !TaskExceptionMessage()">
<td class="finishedMessage" data-bind="css: { finishedRedirect: FinishedUrl }">
<span data-bind="text: FinishedMessage"></span>
</td>
</tr>
<tr data-bind="visible: TaskExceptionMessage">
<td class="exception">Last Error:
<div class="code" data-bind="text: TaskExceptionMessage">
</div>
</td>
</tr>
<tr data-bind="visible: NextScheduledTimestamp">
<td class="nextScheduledTimestamp">Next Scheduled: <span data-bind="text: NextScheduledTimestampFormatted"></span>
</td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
ko.bindingHandlers.progressValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var $element = $(element);
if (!$element.is('.ui-progressbar'))
$element.progressbar();
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var v = ko.utils.unwrapObservable(valueAccessor());
var vInt = parseInt(v);
if (vInt >= 0) {
$(element).progressbar('option', 'value', vInt);
}
}
};
//* http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
return this;
}
</script>
<script type="text/javascript">
$(function () {
var sessionId = '@(Model.SessionId)';
var sessionStatusUrl = '@(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)))';
var view = $('#scheduledTaskStatus');
var vm = null;
var liveConnection = null;
var statusViewModel = function (sessionId) {
var self = this;
self.Initialized = ko.observable(false);
self.TimestampParse = function (timestamp) {
if (timestamp) {
if (timestamp.indexOf("\/Date(") == 0)
return new Date(parseInt(timestamp.substr(6)));
else
return (new Date()).setISO8601(timestamp);
}
return new Date();
}
self.TimestampFormat = function (timestamp) {
var addZero = function (v) { v = v + ''; if (v.length == 1) v = '0' + v; return v; }
return timestamp.getFullYear() + '/' + addZero((1 + timestamp.getMonth())) + '/' + addZero(timestamp.getDate()) + ' ' + addZero(timestamp.getHours()) + ':' + addZero(timestamp.getMinutes()) + ':' + addZero(timestamp.getSeconds());
}
self.SessionId = sessionId;
self.TaskName = ko.observable(null);
self.StatusVersion = -1;
self.Progress = ko.observable(0);
self.CurrentProcess = ko.observable(null);
self.CurrentDescription = ko.observable(null);
self.IsRunning = ko.observable(null);
self.TaskExceptionMessage = ko.observable(null);
self.FinishedTimestamp = ko.observable(null);
self.NextScheduledTimestamp = ko.observable(null)
self.NextScheduledTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));
});
self.FinishedTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.FinishedTimestamp()));
});
self.FinishedUrl = ko.observable(null);
self.FinishedMessage = ko.observable(null);
self.Finished = function () {
if (self.FinishedTimestamp()) {
if (self.FinishedUrl() && !self.TaskExceptionMessage()) {
if (self.FinishedMessage())
window.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);
else
window.location.href = self.FinishedUrl();
}
}
}
self.Initialize = function (taskStatus) {
self.TaskName(taskStatus.TaskName);
self.FinishedUrl(taskStatus.FinishedUrl);
self.Progress(taskStatus.Progress);
self.CurrentProcess(taskStatus.CurrentProcess);
self.CurrentDescription(taskStatus.CurrentDescription);
self.IsRunning(taskStatus.IsRunning);
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
self.FinishedMessage(taskStatus.FinishedMessage);
self.Initialized(true);
self.Finished();
}
self.Update = function (taskStatus) {
if (!self.Initialized())
return self.Initialize(taskStatus);
if (taskStatus.StatusVersion < self.StatusVersion)
return; // Have Newer Status Update
self.StatusVersion = taskStatus.StatusVersion;
if (taskStatus.ChangedProperties) {
for (var changedPropertyIndex = 0; changedPropertyIndex < taskStatus.ChangedProperties.length; changedPropertyIndex++) {
switch (taskStatus.ChangedProperties[changedPropertyIndex]) {
case 'Progress':
self.Progress(taskStatus.Progress);
break;
case 'CurrentProcess':
self.CurrentProcess(taskStatus.CurrentProcess);
break;
case 'CurrentDescription':
self.CurrentDescription(taskStatus.CurrentDescription);
break;
case 'IsRunning':
self.IsRunning(taskStatus.IsRunning);
break;
case 'TaskException':
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
break;
case 'NextScheduledTimestamp':
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
break;
case 'FinishedUrl':
self.FinishedUrl(taskStatus.FinishedUrl);
break;
case 'FinishedMessage':
self.FinishedMessage(taskStatus.FinishedMessage);
break;
case 'FinishedTimestamp':
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
window.setTimeout(self.Finished, 1);
break;
default:
// Ignore
}
}
}
}
}
vm = new statusViewModel(sessionId);
ko.applyBindings(vm, view[0]);
// Start Live Connection
updateWithLive();
function updateWithAjax(onSuccess) {
$.ajax({
url: sessionStatusUrl,
dataType: 'json',
type: 'POST',
traditional: true,
success: update_Received,
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to load Session: ' + errorThrown);
}
});
}
function updateWithLive() {
liveConnection = $.connection('@(Url.Content("~/API/Logging/TaskStatusNotifications"))', { addToGroups: sessionId });
liveConnection.received(update_Received);
liveConnection.error(function (e) { if (e.status != 200) alert('Live-Status Error: ' + e.statusText + ': ' + e.responseText); });
liveConnection.start(function () {
updateWithAjax();
});
}
function update_Received(taskStatus) {
vm.Update(taskStatus);
}
});
</script>
@Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId)
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -37,7 +37,7 @@ namespace Disco.Web.Areas.Config.Views.Logging
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Logging/TaskStatus.cshtml")]
public partial class TaskStatus : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Logging.TaskStatusModel>
public partial class TaskStatus : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Shared.TaskStatusModel>
{
public TaskStatus()
{
@@ -48,269 +48,19 @@ namespace Disco.Web.Areas.Config.Views.Logging
#line 2 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Logging", MVC.Config.Logging.Index(), "Task Status");
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" style=\"min-height: 300px;\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"scheduledTaskStatus\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 520px;\"");
WriteLiteral(" data-bind=\"visible: Initialized\"");
WriteLiteral(">\r\n <h2");
WriteLiteral(" data-bind=\"text: TaskName\"");
WriteLiteral(">&nbsp;</h2>\r\n <table>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <th");
WriteLiteral(" class=\"process\"");
WriteLiteral(" data-bind=\"text: CurrentProcess\"");
WriteLiteral(">&nbsp;\r\n </th>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"description\"");
WriteLiteral(" data-bind=\"text: CurrentDescription\"");
WriteLiteral(">&nbsp;\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"progress\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" data-bind=\"progressValue: Progress\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedTimestamp\"");
WriteLiteral(">\r\n <h3>Finished: <span");
WriteLiteral(" data-bind=\"text: FinishedTimestampFormatted\"");
WriteLiteral("></span>\r\n </h3>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp() && !TaskExceptionMessage()\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedMessage\"");
WriteLiteral(" data-bind=\"css: { finishedRedirect: FinishedUrl }\"");
WriteLiteral(">\r\n <span");
WriteLiteral(" data-bind=\"text: FinishedMessage\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: TaskExceptionMessage\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"exception\"");
WriteLiteral(">Last Error:\r\n <div");
WriteLiteral(" class=\"code\"");
WriteLiteral(" data-bind=\"text: TaskExceptionMessage\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: NextScheduledTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"nextScheduledTimestamp\"");
WriteLiteral(">Next Scheduled: <span");
WriteLiteral(" data-bind=\"text: NextScheduledTimestampFormatted\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r" +
"\n</div>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n ko.bindingHandlers.progressValue = {\r\n init: function (element, val" +
"ueAccessor, allBindingsAccessor, viewModel) {\r\n var $element = $(elem" +
"ent);\r\n if (!$element.is(\'.ui-progressbar\'))\r\n $elemen" +
"t.progressbar();\r\n },\r\n update: function (element, valueAccessor, " +
"allBindingsAccessor, viewModel) {\r\n var v = ko.utils.unwrapObservable" +
"(valueAccessor());\r\n var vInt = parseInt(v);\r\n if (vInt >=" +
" 0) {\r\n $(element).progressbar(\'option\', \'value\', vInt);\r\n " +
" }\r\n }\r\n };\r\n //* http://webcloud.se/log/JavaScript-and-ISO-860" +
"1/\r\n Date.prototype.setISO8601 = function (string) {\r\n var regexp = \"(" +
"[0-9]{4})(-([0-9]{2})(-([0-9]{2})\" +\r\n \"(T([0-9]{2}):([0-9]{2})(:([0-9]{2" +
"})(\\.([0-9]+))?)?\" +\r\n \"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?\";\r\n " +
" var d = string.match(new RegExp(regexp));\r\n\r\n var offset = 0;\r\n " +
" var date = new Date(d[1], 0, 1);\r\n\r\n if (d[3]) { date.setMonth(d[3] - 1)" +
"; }\r\n if (d[5]) { date.setDate(d[5]); }\r\n if (d[7]) { date.setHour" +
"s(d[7]); }\r\n if (d[8]) { date.setMinutes(d[8]); }\r\n if (d[10]) { d" +
"ate.setSeconds(d[10]); }\r\n if (d[12]) { date.setMilliseconds(Number(\"0.\" " +
"+ d[12]) * 1000); }\r\n if (d[14]) {\r\n offset = (Number(d[16]) *" +
" 60) + Number(d[17]);\r\n offset *= ((d[15] == \'-\') ? 1 : -1);\r\n " +
" }\r\n\r\n offset -= date.getTimezoneOffset();\r\n time = (Number(date) " +
"+ (offset * 60 * 1000));\r\n this.setTime(Number(time));\r\n return th" +
"is;\r\n }\r\n</script>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(function () {\r\n var sessionId = \'");
WriteLiteral("\r\n");
#line 93 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
Write(Model.SessionId);
#line 5 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
Write(Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId));
#line default
#line hidden
WriteLiteral("\';\r\n var sessionStatusUrl = \'");
#line 94 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
Write(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)));
#line default
#line hidden
WriteLiteral("\';\r\n\r\n var view = $(\'#scheduledTaskStatus\');\r\n var vm = null;\r\n\r\n " +
" var liveConnection = null;\r\n\r\n var statusViewModel = function (sess" +
"ionId) {\r\n var self = this;\r\n\r\n self.Initialized = ko.obse" +
"rvable(false);\r\n\r\n self.TimestampParse = function (timestamp) {\r\n " +
" if (timestamp) {\r\n if (timestamp.indexOf(\"\\/Date(" +
"\") == 0)\r\n return new Date(parseInt(timestamp.substr(6)))" +
";\r\n else\r\n return (new Date()).setISO8" +
"601(timestamp);\r\n }\r\n return new Date();\r\n " +
" }\r\n self.TimestampFormat = function (timestamp) {\r\n " +
" var addZero = function (v) { v = v + \'\'; if (v.length == 1) v = \'0\' + v; retur" +
"n v; }\r\n return timestamp.getFullYear() + \'/\' + addZero((1 + time" +
"stamp.getMonth())) + \'/\' + addZero(timestamp.getDate()) + \' \' + addZero(timestam" +
"p.getHours()) + \':\' + addZero(timestamp.getMinutes()) + \':\' + addZero(timestamp." +
"getSeconds());\r\n }\r\n\r\n self.SessionId = sessionId;\r\n " +
" self.TaskName = ko.observable(null);\r\n self.StatusVersion = -1;" +
"\r\n\r\n self.Progress = ko.observable(0);\r\n self.CurrentProce" +
"ss = ko.observable(null);\r\n self.CurrentDescription = ko.observable(n" +
"ull);\r\n\r\n self.IsRunning = ko.observable(null);\r\n\r\n self.T" +
"askExceptionMessage = ko.observable(null);\r\n\r\n self.FinishedTimestamp" +
" = ko.observable(null);\r\n self.NextScheduledTimestamp = ko.observable" +
"(null)\r\n\r\n self.NextScheduledTimestampFormatted = ko.computed(functio" +
"n () {\r\n return self.TimestampFormat(self.TimestampParse(self.Nex" +
"tScheduledTimestamp()));\r\n });\r\n self.FinishedTimestampFor" +
"matted = ko.computed(function () {\r\n return self.TimestampFormat(" +
"self.TimestampParse(self.FinishedTimestamp()));\r\n });\r\n\r\n " +
"self.FinishedUrl = ko.observable(null);\r\n self.FinishedMessage = ko.o" +
"bservable(null);\r\n\r\n self.Finished = function () {\r\n i" +
"f (self.FinishedTimestamp()) {\r\n if (self.FinishedUrl() && !s" +
"elf.TaskExceptionMessage()) {\r\n if (self.FinishedMessage(" +
"))\r\n window.setTimeout(function () { window.location." +
"href = self.FinishedUrl(); }, 3000);\r\n else\r\n " +
" window.location.href = self.FinishedUrl();\r\n " +
"}\r\n }\r\n }\r\n\r\n self.Initialize = function (t" +
"askStatus) {\r\n self.TaskName(taskStatus.TaskName);\r\n " +
" self.FinishedUrl(taskStatus.FinishedUrl);\r\n\r\n self.Progress(ta" +
"skStatus.Progress);\r\n self.CurrentProcess(taskStatus.CurrentProce" +
"ss);\r\n self.CurrentDescription(taskStatus.CurrentDescription);\r\n\r" +
"\n self.IsRunning(taskStatus.IsRunning);\r\n\r\n self.T" +
"askExceptionMessage(taskStatus.TaskExceptionMessage);\r\n\r\n self.Fi" +
"nishedTimestamp(taskStatus.FinishedTimestamp);\r\n self.NextSchedul" +
"edTimestamp(taskStatus.NextScheduledTimestamp);\r\n\r\n self.Finished" +
"Message(taskStatus.FinishedMessage);\r\n\r\n self.Initialized(true);\r" +
"\n\r\n self.Finished();\r\n }\r\n self.Update = fu" +
"nction (taskStatus) {\r\n if (!self.Initialized())\r\n " +
" return self.Initialize(taskStatus);\r\n\r\n if (taskStatus.Statu" +
"sVersion < self.StatusVersion)\r\n return; // Have Newer Status" +
" Update\r\n self.StatusVersion = taskStatus.StatusVersion;\r\n\r\n " +
" if (taskStatus.ChangedProperties) {\r\n for (var cha" +
"ngedPropertyIndex = 0; changedPropertyIndex < taskStatus.ChangedProperties.lengt" +
"h; changedPropertyIndex++) {\r\n switch (taskStatus.Changed" +
"Properties[changedPropertyIndex]) {\r\n case \'Progress\'" +
":\r\n self.Progress(taskStatus.Progress);\r\n " +
" break;\r\n case \'CurrentProcess" +
"\':\r\n self.CurrentProcess(taskStatus.CurrentProces" +
"s);\r\n break;\r\n case \'C" +
"urrentDescription\':\r\n self.CurrentDescription(tas" +
"kStatus.CurrentDescription);\r\n break;\r\n " +
" case \'IsRunning\':\r\n self.IsRunn" +
"ing(taskStatus.IsRunning);\r\n break;\r\n " +
" case \'TaskException\':\r\n self.Task" +
"ExceptionMessage(taskStatus.TaskExceptionMessage);\r\n " +
" break;\r\n case \'NextScheduledTimestamp\':\r\n " +
" self.NextScheduledTimestamp(taskStatus.NextScheduledTime" +
"stamp);\r\n break;\r\n cas" +
"e \'FinishedUrl\':\r\n self.FinishedUrl(taskStatus.Fi" +
"nishedUrl);\r\n break;\r\n " +
" case \'FinishedMessage\':\r\n self.FinishedMessage(t" +
"askStatus.FinishedMessage);\r\n break;\r\n " +
" case \'FinishedTimestamp\':\r\n self" +
".FinishedTimestamp(taskStatus.FinishedTimestamp);\r\n " +
" window.setTimeout(self.Finished, 1);\r\n break;\r" +
"\n default:\r\n // Ignore" +
"\r\n }\r\n }\r\n }\r\n " +
" }\r\n }\r\n\r\n vm = new statusViewModel(sessionId);\r\n ko.appl" +
"yBindings(vm, view[0]);\r\n\r\n // Start Live Connection\r\n updateWithL" +
"ive();\r\n\r\n function updateWithAjax(onSuccess) {\r\n $.ajax({\r\n " +
" url: sessionStatusUrl,\r\n dataType: \'json\',\r\n " +
" type: \'POST\',\r\n traditional: true,\r\n succ" +
"ess: update_Received,\r\n error: function (jqXHR, textStatus, error" +
"Thrown) {\r\n alert(\'Unable to load Session: \' + errorThrown);\r" +
"\n }\r\n });\r\n }\r\n function updateWithLive(" +
") {\r\n liveConnection = $.connection(\'");
#line 243 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
Write(Url.Content("~/API/Logging/TaskStatusNotifications"));
#line default
#line hidden
WriteLiteral(@"', { addToGroups: sessionId });
liveConnection.received(update_Received);
liveConnection.error(function (e) { if (e.status != 200) alert('Live-Status Error: ' + e.statusText + ': ' + e.responseText); });
liveConnection.start(function () {
updateWithAjax();
});
}
function update_Received(taskStatus) {
vm.Update(taskStatus);
}
});
</script>
");
}
}
}
@@ -1,7 +1,7 @@
@model Disco.Web.Areas.Config.Models.Shared.LogEventsModel
@{
Authorization.Require(Claims.Config.Logging.Show);
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
var uniqueId = Guid.NewGuid().ToString("N");
@@ -44,12 +44,12 @@
$(function () {
var logEventsHost = $('LogEvents_@(uniqueId)');
var logModuleId = '@(Model.ModuleFilter != null ? Model.ModuleFilter.ModuleId.ToString() : null)';
var logModuleLiveGroupName = '@(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.BI.Interop.SignalRHandlers.LogNotifications.AllNotifications)';
var logEventTypeFiltered = @(eventTypesFilterJson);
var logModuleLiveGroupName = '@(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.Services.Logging.LogNotificationsHub.AllLoggingNotification)';
var logEventTypeFiltered = @(eventTypesFilterJson);
var logStartFiler = @(AjaxHelpers.JsonDate(Model.StartFilter));
var logEndFiler = @(AjaxHelpers.JsonDate(Model.EndFilter));
var logTakeFiler = '@(Model.TakeFilter)';
var liveConnection = null;
var logHub = null;
var liveEventReceivedFunction = '@(Model.JavascriptLiveEventFunctionName)';
var useLive = ('True'==='@(Model.IsLive)');
@@ -89,7 +89,7 @@
dataType: 'json',
type: 'POST',
data: loadData,
success: function (d) {
success: function (d) {
initLogs(d);
},
error: function (jqXHR, textStatus, errorThrown) {
@@ -113,16 +113,21 @@
}
}
liveConnection = $.connection('@(Url.Content("~/API/Logging/Notifications"))', {addToGroups: logModuleLiveGroupName});
liveConnection.received(logReceived);
liveConnection.error(function(e){if (e.status != 200) alert('Live-Log Error: '+e.statusText +': '+e.responseText);});
liveConnection.start();
}
}
logHub = $.connection.logNotifications;
logHub.client.receiveLog = function(message){
if (message.UseDisplay) logsViewModel.EventLogs.unshift(message);
if (liveEventReceivedFunction) liveEventReceivedFunction(message);
};
function logReceived(log){
if (log.UseDisplay) logsViewModel.EventLogs.unshift(log);
if (liveEventReceivedFunction) liveEventReceivedFunction(log);
$.connection.hub.qs = {LogModules: logModuleLiveGroupName};
$.connection.hub.error(function(error){
alert('Live-Log Error: '+error);
});
$.connection.hub.start().fail(function(error){
alert('Live-Log Connection Error: '+error);
});
}
}
loadInitialData();
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -48,7 +48,7 @@ namespace Disco.Web.Areas.Config.Views.Shared
#line 2 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
Authorization.Require(Claims.Config.Logging.Show);
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
var uniqueId = Guid.NewGuid().ToString("N");
@@ -58,15 +58,15 @@ namespace Disco.Web.Areas.Config.Views.Shared
#line hidden
WriteLiteral("\r\n<div");
WriteAttribute("id", Tuple.Create(" id=\"", 313), Tuple.Create("\"", 339)
, Tuple.Create(Tuple.Create("", 318), Tuple.Create("LogEvents_", 318), true)
WriteAttribute("id", Tuple.Create(" id=\"", 309), Tuple.Create("\"", 335)
, Tuple.Create(Tuple.Create("", 314), Tuple.Create("LogEvents_", 314), true)
#line 9 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
, Tuple.Create(Tuple.Create("", 328), Tuple.Create<System.Object, System.Int32>(uniqueId
, Tuple.Create(Tuple.Create("", 324), Tuple.Create<System.Object, System.Int32>(uniqueId
#line default
#line hidden
, 328), false)
, 324), false)
);
WriteLiteral(" class=\"logEventsViewport\"");
@@ -96,21 +96,21 @@ WriteLiteral(">Message\r\n </th>\r\n </tr>\r\n
WriteLiteral(" class=\"logEventsViewportContainer\"");
WriteAttribute("style", Tuple.Create(" style=\"", 814), Tuple.Create("\"", 1024)
WriteAttribute("style", Tuple.Create(" style=\"", 810), Tuple.Create("\"", 1020)
#line 24 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
, Tuple.Create(Tuple.Create("", 822), Tuple.Create<System.Object, System.Int32>(Model.ViewPortWidth.HasValue ? string.Format("width:{0}px;", Model.ViewPortWidth.Value) : null
, Tuple.Create(Tuple.Create("", 818), Tuple.Create<System.Object, System.Int32>(Model.ViewPortWidth.HasValue ? string.Format("width:{0}px;", Model.ViewPortWidth.Value) : null
#line default
#line hidden
, 822), false)
, 818), false)
#line 24 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
, Tuple.Create(Tuple.Create("", 919), Tuple.Create<System.Object, System.Int32>(Model.ViewPortHeight.HasValue ? string.Format("height:{0}px;", Model.ViewPortHeight.Value - 18) : null
, Tuple.Create(Tuple.Create("", 915), Tuple.Create<System.Object, System.Int32>(Model.ViewPortHeight.HasValue ? string.Format("height:{0}px;", Model.ViewPortHeight.Value - 18) : null
#line default
#line hidden
, 919), false)
, 915), false)
);
WriteLiteral(">\r\n <div");
@@ -205,7 +205,7 @@ WriteLiteral("\';\r\n var logModuleLiveGroupName = \'");
#line 47 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
Write(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.BI.Interop.SignalRHandlers.LogNotifications.AllNotifications);
Write(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.Services.Logging.LogNotificationsHub.AllLoggingNotification);
#line default
@@ -219,7 +219,7 @@ WriteLiteral("\';\r\n var logEventTypeFiltered = ");
#line default
#line hidden
WriteLiteral(";\r\n var logStartFiler = ");
WriteLiteral("; \r\n var logStartFiler = ");
#line 49 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
@@ -246,8 +246,8 @@ WriteLiteral(";\r\n var logTakeFiler = \'");
#line default
#line hidden
WriteLiteral("\';\r\n var liveConnection = null;\r\n var liveEventReceivedFunc" +
"tion = \'");
WriteLiteral("\';\r\n var logHub = null;\r\n var liveEventReceivedFunction = \'" +
"");
#line 53 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
@@ -308,60 +308,33 @@ WriteLiteral(@"');
#line default
#line hidden
WriteLiteral(@"',
dataType: 'json',
type: 'POST',
data: loadData,
success: function (d) {
initLogs(d);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to retrieve logs: ' + textStatus);
}
});
}
function initLogs(loadedLogs){
logsViewModel = new LogsViewModel(loadedLogs);
ko.applyBindings(logsViewModel, logEventsHost.get(0));
if (useLive){
if (liveEventReceivedFunction){
if (!document.DiscoFunctions) document.DiscoFunctions = {};
if (!document.DiscoFunctions.LogEventsFunctions) document.DiscoFunctions.LogEventsFunctions = {};
if (document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction]){
liveEventReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction];
}else{
liveEventReceivedFunction = null;
}
}
liveConnection = $.connection('");
#line 116 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
Write(Url.Content("~/API/Logging/Notifications"));
#line default
#line hidden
WriteLiteral(@"', {addToGroups: logModuleLiveGroupName});
liveConnection.received(logReceived);
liveConnection.error(function(e){if (e.status != 200) alert('Live-Log Error: '+e.statusText +': '+e.responseText);});
liveConnection.start();
}
}
function logReceived(log){
if (log.UseDisplay) logsViewModel.EventLogs.unshift(log);
if (liveEventReceivedFunction) liveEventReceivedFunction(log);
}
loadInitialData();
});
</script>
</div>
");
WriteLiteral("\',\r\n dataType: \'json\',\r\n type: \'POST\',\r\n " +
" data: loadData,\r\n success: function (d) { \r\n" +
" initLogs(d);\r\n },\r\n " +
" error: function (jqXHR, textStatus, errorThrown) {\r\n al" +
"ert(\'Unable to retrieve logs: \' + textStatus);\r\n }\r\n " +
" });\r\n }\r\n\r\n function initLogs(loadedLogs){\r\n " +
" logsViewModel = new LogsViewModel(loadedLogs);\r\n ko.appl" +
"yBindings(logsViewModel, logEventsHost.get(0));\r\n\r\n if (useLive){" +
"\r\n if (liveEventReceivedFunction){\r\n i" +
"f (!document.DiscoFunctions) document.DiscoFunctions = {};\r\n " +
" if (!document.DiscoFunctions.LogEventsFunctions) document.DiscoFunctions.Log" +
"EventsFunctions = {};\r\n if (document.DiscoFunctions.LogEv" +
"entsFunctions[liveEventReceivedFunction]){\r\n liveEven" +
"tReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceived" +
"Function];\r\n }else{\r\n liveEven" +
"tReceivedFunction = null;\r\n }\r\n }\r\n\r\n " +
" logHub = $.connection.logNotifications;\r\n " +
"logHub.client.receiveLog = function(message){\r\n if (messa" +
"ge.UseDisplay) logsViewModel.EventLogs.unshift(message);\r\n " +
" if (liveEventReceivedFunction) liveEventReceivedFunction(message);\r\n " +
" };\r\n\r\n $.connection.hub.qs = {LogModules: logModule" +
"LiveGroupName};\r\n $.connection.hub.error(function(error){\r\n " +
" alert(\'Live-Log Error: \'+error);\r\n });\r" +
"\n\r\n $.connection.hub.start().fail(function(error){\r\n " +
" alert(\'Live-Log Connection Error: \'+error);\r\n " +
"});\r\n }\r\n }\r\n\r\n loadInitialData();\r\n " +
" });\r\n </script>\r\n</div>\r\n");
}
}
@@ -0,0 +1,242 @@
@model string
@{
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
}
<div style="min-height: 300px;">
<div id="Logging_Task_Status" class="form" style="width: 520px;" data-bind="visible: Initialized">
<h2 data-bind="text: TaskName">&nbsp;</h2>
<table>
<tr data-bind="visible: IsRunning">
<th class="process" data-bind="text: CurrentProcess">&nbsp;
</th>
</tr>
<tr data-bind="visible: IsRunning">
<td class="description" data-bind="text: CurrentDescription">&nbsp;
</td>
</tr>
<tr data-bind="visible: IsRunning">
<td class="progress">
<div data-bind="progressValue: Progress">
</div>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp">
<td class="finishedTimestamp">
<h3>Finished: <span data-bind="text: FinishedTimestampFormatted"></span>
</h3>
</td>
</tr>
<tr data-bind="visible: FinishedTimestamp() && !TaskExceptionMessage()">
<td class="finishedMessage" data-bind="css: { finishedRedirect: FinishedUrl }">
<span data-bind="text: FinishedMessage"></span>
</td>
</tr>
<tr data-bind="visible: TaskExceptionMessage">
<td class="exception">Last Error:
<div class="code" data-bind="text: TaskExceptionMessage">
</div>
</td>
</tr>
<tr data-bind="visible: NextScheduledTimestamp">
<td class="nextScheduledTimestamp">Next Scheduled: <span data-bind="text: NextScheduledTimestampFormatted"></span>
</td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
ko.bindingHandlers.progressValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var $element = $(element);
if (!$element.is('.ui-progressbar'))
$element.progressbar();
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var v = ko.utils.unwrapObservable(valueAccessor());
var vInt = parseInt(v);
if (vInt >= 0) {
$(element).progressbar('option', 'value', vInt);
}
}
};
//* http://webcloud.se/log/JavaScript-and-ISO-8601/
Date.prototype.setISO8601 = function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
this.setTime(Number(time));
return this;
}
</script>
<script type="text/javascript">
$(function () {
var sessionId = '@(Model)';
var view = $('#Logging_Task_Status');
var vm = null;
var notificationsHub = null;
var statusViewModel = function (sessionId) {
var self = this;
self.Initialized = ko.observable(false);
self.TimestampParse = function (timestamp) {
if (timestamp) {
if (timestamp.indexOf("\/Date(") == 0)
return new Date(parseInt(timestamp.substr(6)));
else
return (new Date()).setISO8601(timestamp);
}
return new Date();
}
self.TimestampFormat = function (timestamp) {
var addZero = function (v) { v = v + ''; if (v.length == 1) v = '0' + v; return v; }
return timestamp.getFullYear() + '/' + addZero((1 + timestamp.getMonth())) + '/' + addZero(timestamp.getDate()) + ' ' + addZero(timestamp.getHours()) + ':' + addZero(timestamp.getMinutes()) + ':' + addZero(timestamp.getSeconds());
}
self.SessionId = sessionId;
self.TaskName = ko.observable(null);
self.Progress = ko.observable(0);
self.CurrentProcess = ko.observable(null);
self.CurrentDescription = ko.observable(null);
self.IsRunning = ko.observable(null);
self.TaskExceptionMessage = ko.observable(null);
self.FinishedTimestamp = ko.observable(null);
self.NextScheduledTimestamp = ko.observable(null)
self.NextScheduledTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));
});
self.FinishedTimestampFormatted = ko.computed(function () {
return self.TimestampFormat(self.TimestampParse(self.FinishedTimestamp()));
});
self.FinishedUrl = ko.observable(null);
self.FinishedMessage = ko.observable(null);
self.Finished = function () {
if (self.FinishedTimestamp()) {
if (self.FinishedUrl() && !self.TaskExceptionMessage()) {
if (self.FinishedMessage())
window.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);
else
window.location.href = self.FinishedUrl();
}
}
}
self.Initialize = function (taskStatus) {
if (!self.Initialized()) {
self.TaskName(taskStatus.TaskName);
self.FinishedUrl(taskStatus.FinishedUrl);
self.Progress(taskStatus.Progress);
self.CurrentProcess(taskStatus.CurrentProcess);
self.CurrentDescription(taskStatus.CurrentDescription);
self.IsRunning(taskStatus.IsRunning);
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
self.FinishedMessage(taskStatus.FinishedMessage);
self.Initialized(true);
self.Finished();
}
}
self.Update = function (taskStatus) {
if (!self.Initialized())
return;
if (taskStatus) {
$.each(taskStatus, function (key, value) {
switch (key) {
case 'Progress':
self.Progress(value);
break;
case 'CurrentProcess':
self.CurrentProcess(value);
break;
case 'CurrentDescription':
self.CurrentDescription(value);
break;
case 'IsRunning':
self.IsRunning(value);
break;
case 'TaskExceptionMessage':
self.TaskExceptionMessage(value);
break;
case 'NextScheduledTimestamp':
self.NextScheduledTimestamp(value);
break;
case 'FinishedUrl':
self.FinishedUrl(value);
break;
case 'FinishedMessage':
self.FinishedMessage(value);
break;
case 'FinishedTimestamp':
self.FinishedTimestamp(value);
window.setTimeout(self.Finished, 1);
break;
default:
// Ignore
}
});
}
}
}
vm = new statusViewModel(sessionId);
ko.applyBindings(vm, view[0]);
// Start Live Connection
updateWithLive();
function updateWithLive() {
notificationsHub = $.connection.scheduledTaskNotifications;
notificationsHub.client.initializeTaskStatus = vm.Initialize;
notificationsHub.client.updateTaskStatus = vm.Update;
$.connection.hub.qs = { TaskSessionId: sessionId };
$.connection.hub.error(function (error) {
alert('Live-Status Error: ' + error);
});
$.connection.hub.start()
.fail(function (error) {
alert('Live-Status Connection Error: ' + error);
});
}
});
</script>
@@ -0,0 +1,281 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Areas.Config.Views.Shared
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Shared/TaskStatus.cshtml")]
public partial class TaskStatus : Disco.Services.Web.WebViewPage<string>
{
public TaskStatus()
{
}
public override void Execute()
{
#line 2 "..\..\Areas\Config\Views\Shared\TaskStatus.cshtml"
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" style=\"min-height: 300px;\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"Logging_Task_Status\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 520px;\"");
WriteLiteral(" data-bind=\"visible: Initialized\"");
WriteLiteral(">\r\n <h2");
WriteLiteral(" data-bind=\"text: TaskName\"");
WriteLiteral(">&nbsp;</h2>\r\n <table>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <th");
WriteLiteral(" class=\"process\"");
WriteLiteral(" data-bind=\"text: CurrentProcess\"");
WriteLiteral(">&nbsp;\r\n </th>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"description\"");
WriteLiteral(" data-bind=\"text: CurrentDescription\"");
WriteLiteral(">&nbsp;\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: IsRunning\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"progress\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" data-bind=\"progressValue: Progress\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedTimestamp\"");
WriteLiteral(">\r\n <h3>Finished: <span");
WriteLiteral(" data-bind=\"text: FinishedTimestampFormatted\"");
WriteLiteral("></span>\r\n </h3>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: FinishedTimestamp() && !TaskExceptionMessage()\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"finishedMessage\"");
WriteLiteral(" data-bind=\"css: { finishedRedirect: FinishedUrl }\"");
WriteLiteral(">\r\n <span");
WriteLiteral(" data-bind=\"text: FinishedMessage\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n <tr");
WriteLiteral(" data-bind=\"visible: TaskExceptionMessage\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"exception\"");
WriteLiteral(">Last Error:\r\n <div");
WriteLiteral(" class=\"code\"");
WriteLiteral(" data-bind=\"text: TaskExceptionMessage\"");
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteLiteral(" data-bind=\"visible: NextScheduledTimestamp\"");
WriteLiteral(">\r\n <td");
WriteLiteral(" class=\"nextScheduledTimestamp\"");
WriteLiteral(">Next Scheduled: <span");
WriteLiteral(" data-bind=\"text: NextScheduledTimestampFormatted\"");
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r" +
"\n</div>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n ko.bindingHandlers.progressValue = {\r\n init: function (element, val" +
"ueAccessor, allBindingsAccessor, viewModel) {\r\n var $element = $(elem" +
"ent);\r\n if (!$element.is(\'.ui-progressbar\'))\r\n $elemen" +
"t.progressbar();\r\n },\r\n update: function (element, valueAccessor, " +
"allBindingsAccessor, viewModel) {\r\n var v = ko.utils.unwrapObservable" +
"(valueAccessor());\r\n var vInt = parseInt(v);\r\n if (vInt >=" +
" 0) {\r\n $(element).progressbar(\'option\', \'value\', vInt);\r\n " +
" }\r\n }\r\n };\r\n //* http://webcloud.se/log/JavaScript-and-ISO-860" +
"1/\r\n Date.prototype.setISO8601 = function (string) {\r\n var regexp = \"(" +
"[0-9]{4})(-([0-9]{2})(-([0-9]{2})\" +\r\n \"(T([0-9]{2}):([0-9]{2})(:([0-9]{2" +
"})(\\.([0-9]+))?)?\" +\r\n \"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?\";\r\n " +
" var d = string.match(new RegExp(regexp));\r\n\r\n var offset = 0;\r\n " +
" var date = new Date(d[1], 0, 1);\r\n\r\n if (d[3]) { date.setMonth(d[3] - 1)" +
"; }\r\n if (d[5]) { date.setDate(d[5]); }\r\n if (d[7]) { date.setHour" +
"s(d[7]); }\r\n if (d[8]) { date.setMinutes(d[8]); }\r\n if (d[10]) { d" +
"ate.setSeconds(d[10]); }\r\n if (d[12]) { date.setMilliseconds(Number(\"0.\" " +
"+ d[12]) * 1000); }\r\n if (d[14]) {\r\n offset = (Number(d[16]) *" +
" 60) + Number(d[17]);\r\n offset *= ((d[15] == \'-\') ? 1 : -1);\r\n " +
" }\r\n\r\n offset -= date.getTimezoneOffset();\r\n time = (Number(date) " +
"+ (offset * 60 * 1000));\r\n this.setTime(Number(time));\r\n return th" +
"is;\r\n }\r\n</script>\r\n<script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(function () {\r\n var sessionId = \'");
#line 92 "..\..\Areas\Config\Views\Shared\TaskStatus.cshtml"
Write(Model);
#line default
#line hidden
WriteLiteral("\';\r\n\r\n var view = $(\'#Logging_Task_Status\');\r\n var vm = null;\r\n\r\n " +
" var notificationsHub = null;\r\n\r\n var statusViewModel = function (se" +
"ssionId) {\r\n var self = this;\r\n\r\n self.Initialized = ko.ob" +
"servable(false);\r\n\r\n self.TimestampParse = function (timestamp) {\r\n " +
" if (timestamp) {\r\n if (timestamp.indexOf(\"\\/Dat" +
"e(\") == 0)\r\n return new Date(parseInt(timestamp.substr(6)" +
"));\r\n else\r\n return (new Date()).setIS" +
"O8601(timestamp);\r\n }\r\n return new Date();\r\n " +
" }\r\n self.TimestampFormat = function (timestamp) {\r\n " +
" var addZero = function (v) { v = v + \'\'; if (v.length == 1) v = \'0\' + v; ret" +
"urn v; }\r\n return timestamp.getFullYear() + \'/\' + addZero((1 + ti" +
"mestamp.getMonth())) + \'/\' + addZero(timestamp.getDate()) + \' \' + addZero(timest" +
"amp.getHours()) + \':\' + addZero(timestamp.getMinutes()) + \':\' + addZero(timestam" +
"p.getSeconds());\r\n }\r\n\r\n self.SessionId = sessionId;\r\n " +
" self.TaskName = ko.observable(null);\r\n\r\n self.Progress = ko.o" +
"bservable(0);\r\n self.CurrentProcess = ko.observable(null);\r\n " +
" self.CurrentDescription = ko.observable(null);\r\n\r\n self.IsRunning " +
"= ko.observable(null);\r\n\r\n self.TaskExceptionMessage = ko.observable(" +
"null);\r\n\r\n self.FinishedTimestamp = ko.observable(null);\r\n " +
" self.NextScheduledTimestamp = ko.observable(null)\r\n\r\n self.NextSched" +
"uledTimestampFormatted = ko.computed(function () {\r\n return self." +
"TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));\r\n " +
" });\r\n self.FinishedTimestampFormatted = ko.computed(function () {\r\n" +
" return self.TimestampFormat(self.TimestampParse(self.FinishedTim" +
"estamp()));\r\n });\r\n\r\n self.FinishedUrl = ko.observable(nul" +
"l);\r\n self.FinishedMessage = ko.observable(null);\r\n\r\n self" +
".Finished = function () {\r\n if (self.FinishedTimestamp()) {\r\n " +
" if (self.FinishedUrl() && !self.TaskExceptionMessage()) {\r\n " +
" if (self.FinishedMessage())\r\n wind" +
"ow.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);" +
"\r\n else\r\n window.location.href" +
" = self.FinishedUrl();\r\n }\r\n }\r\n }\r" +
"\n\r\n self.Initialize = function (taskStatus) {\r\n if (!s" +
"elf.Initialized()) {\r\n self.TaskName(taskStatus.TaskName);\r\n " +
" self.FinishedUrl(taskStatus.FinishedUrl);\r\n\r\n " +
" self.Progress(taskStatus.Progress);\r\n self.CurrentProcess" +
"(taskStatus.CurrentProcess);\r\n self.CurrentDescription(taskSt" +
"atus.CurrentDescription);\r\n\r\n self.IsRunning(taskStatus.IsRun" +
"ning);\r\n\r\n self.TaskExceptionMessage(taskStatus.TaskException" +
"Message);\r\n\r\n self.FinishedTimestamp(taskStatus.FinishedTimes" +
"tamp);\r\n self.NextScheduledTimestamp(taskStatus.NextScheduled" +
"Timestamp);\r\n\r\n self.FinishedMessage(taskStatus.FinishedMessa" +
"ge);\r\n\r\n self.Initialized(true);\r\n\r\n self." +
"Finished();\r\n }\r\n }\r\n self.Update = functio" +
"n (taskStatus) {\r\n if (!self.Initialized())\r\n " +
"return;\r\n\r\n if (taskStatus) {\r\n $.each(taskSta" +
"tus, function (key, value) {\r\n switch (key) {\r\n " +
" case \'Progress\':\r\n self.Progres" +
"s(value);\r\n break;\r\n c" +
"ase \'CurrentProcess\':\r\n self.CurrentProcess(value" +
");\r\n break;\r\n case \'Cu" +
"rrentDescription\':\r\n self.CurrentDescription(valu" +
"e);\r\n break;\r\n case \'I" +
"sRunning\':\r\n self.IsRunning(value);\r\n " +
" break;\r\n case \'TaskExceptionMessa" +
"ge\':\r\n self.TaskExceptionMessage(value);\r\n " +
" break;\r\n case \'NextScheduled" +
"Timestamp\':\r\n self.NextScheduledTimestamp(value);" +
"\r\n break;\r\n case \'Fini" +
"shedUrl\':\r\n self.FinishedUrl(value);\r\n " +
" break;\r\n case \'FinishedMessage\':" +
"\r\n self.FinishedMessage(value);\r\n " +
" break;\r\n case \'FinishedTimestamp\':\r\n " +
" self.FinishedTimestamp(value);\r\n " +
" window.setTimeout(self.Finished, 1);\r\n " +
" break;\r\n default:\r\n " +
" // Ignore\r\n }\r\n });\r\n " +
" }\r\n }\r\n }\r\n\r\n vm = new statusViewModel(sessionId);\r\n " +
" ko.applyBindings(vm, view[0]);\r\n\r\n // Start Live Connection\r\n " +
" updateWithLive();\r\n\r\n function updateWithLive() {\r\n notific" +
"ationsHub = $.connection.scheduledTaskNotifications;\r\n notificationsH" +
"ub.client.initializeTaskStatus = vm.Initialize;\r\n notificationsHub.cl" +
"ient.updateTaskStatus = vm.Update;\r\n\r\n $.connection.hub.qs = { TaskSe" +
"ssionId: sessionId };\r\n $.connection.hub.error(function (error) {\r\n " +
" alert(\'Live-Status Error: \' + error);\r\n });\r\n\r\n " +
" $.connection.hub.start()\r\n .fail(function (error) {\r\n " +
" alert(\'Live-Status Connection Error: \' + error);\r\n })" +
";\r\n }\r\n\r\n });\r\n</script>\r\n");
}
}
}
#pragma warning restore 1591
@@ -1,6 +1,5 @@
using Disco.Models.Repository;
using Disco.Services.Jobs.Noticeboards;
using Disco.Services.Web;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
@@ -8,81 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
{
public partial class HeldDevicesController : DatabaseController
{
#region Helpers
private List<Models.HeldDevices.HeldDeviceModel> GetHeldDevices(IQueryable<Job> query)
{
var jobs = query.Where(j =>
!j.ClosedDate.HasValue &&
j.DeviceSerialNumber != null &&
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
).Select(j => new Models.HeldDevices.HeldDeviceQueryModel
{
JobId = j.Id,
DeviceSerialNumber = j.DeviceSerialNumber,
DeviceComputerName = j.Device.DeviceDomainId,
DeviceLocation = j.Device.Location,
DeviceProfileId = j.Device.DeviceProfileId,
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
UserId = j.Device.AssignedUserId,
UserDisplayName = j.Device.AssignedUser.DisplayName,
WaitingForUserAction = j.WaitingForUserAction.HasValue || ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue),
WaitingForUserActionSince = j.WaitingForUserAction.HasValue ? j.WaitingForUserAction : (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue ? j.JobMetaNonWarranty.AccountingChargeRequiredDate : j.JobMetaNonWarranty.AccountingChargeAddedDate),
ReadyForReturn = j.DeviceReadyForReturn.HasValue,
EstimatedReturnTime = j.ExpectedClosedDate,
ReadyForReturnSince = j.DeviceReadyForReturn
}).GroupBy(j => j.DeviceSerialNumber);
var thd = new List<Models.HeldDevices.HeldDeviceModel>();
foreach (var job in jobs)
{
if (job.Any(j => j.WaitingForUserAction))
{
thd.Add(job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).FirstOrDefault().ToUserHeldDeviceModel(Database));
}
else
{
if (job.All(j => j.ReadyForReturn))
{
thd.Add(job.FirstOrDefault().ToUserHeldDeviceModel(Database));
}
else
{
thd.Add(job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).FirstOrDefault().ToUserHeldDeviceModel(Database));
}
}
}
return thd;
}
private List<Models.HeldDevices.HeldDeviceModel> GetHeldDevices()
{
return GetHeldDevices(Database.Jobs);
}
private Models.HeldDevices.HeldDeviceModel GetHeldDevice(string DeviceSerialNumber)
{
return GetHeldDevices(Database.Jobs.Where(j => j.DeviceSerialNumber == DeviceSerialNumber)).FirstOrDefault();
}
#endregion
public virtual ActionResult Index()
{
return View(GetHeldDevices());
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
return View(m);
}
public virtual ActionResult ReadyForReturnXml()
{
var readyForReturn = GetHeldDevices().Where(j => j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
var readyForReturn = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
.Where(j => j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(readyForReturn);
}
public virtual ActionResult WaitingForUserActionXml()
{
var waitingForUserAction = GetHeldDevices().Where(j => j.WaitingForUserAction).ToArray();
var waitingForUserAction = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
.Where(j => j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(waitingForUserAction);
}
public virtual ActionResult HeldDevicesXml()
{
var heldDevices = GetHeldDevices().Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
var heldDevices = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
.Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(heldDevices);
}
@@ -93,13 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
public virtual ActionResult HeldDevice(string id)
{
var uhd = GetHeldDevice(id);
return Json(uhd, JsonRequestBehavior.AllowGet);
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevice(Database, id);
return Json(m, JsonRequestBehavior.AllowGet);
}
public virtual ActionResult HeldDevices()
{
var uhd = GetHeldDevices();
return Json(uhd, JsonRequestBehavior.AllowGet);
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
return Json(m, JsonRequestBehavior.AllowGet);
}
}
}
@@ -1,6 +1,5 @@
using Disco.Models.Repository;
using Disco.Services.Jobs.Noticeboards;
using Disco.Services.Web;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
@@ -8,79 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
{
public partial class UserHeldDevicesController : DatabaseController
{
#region Helpers
private List<Models.UserHeldDevices.UserHeldDeviceModel> GetUserHeldDevices(IQueryable<Job> query)
{
var jobs = query.Where(j =>
!j.ClosedDate.HasValue && j.Device.AssignedUserId != null &&
j.DeviceSerialNumber != null &&
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
).Select(j => new Models.UserHeldDevices.HeldJobDeviceModel
{
JobId = j.Id,
WaitingForUserAction = j.WaitingForUserAction.HasValue || ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue),
WaitingForUserActionSince = j.WaitingForUserAction.HasValue ? j.WaitingForUserAction : (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue ? j.JobMetaNonWarranty.AccountingChargeRequiredDate : j.JobMetaNonWarranty.AccountingChargeAddedDate),
ReadyForReturn = j.DeviceReadyForReturn.HasValue,
EstimatedReturnTime = j.ExpectedClosedDate,
ReadyForReturnSince = j.DeviceReadyForReturn,
UserId = j.Device.AssignedUserId,
UserDisplayName = j.Device.AssignedUser.DisplayName,
DeviceProfileId = j.Device.DeviceProfileId,
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress
}).GroupBy(j => j.UserId);
var thd = new List<Models.UserHeldDevices.UserHeldDeviceModel>();
foreach (var job in jobs)
{
if (job.Any(j => j.WaitingForUserAction))
{
thd.Add(job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).FirstOrDefault().ToUserHeldDeviceModel(Database));
}
else
{
if (job.All(j => j.ReadyForReturn))
{
thd.Add(job.FirstOrDefault().ToUserHeldDeviceModel(Database));
}
else
{
thd.Add(job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).FirstOrDefault().ToUserHeldDeviceModel(Database));
}
}
}
return thd;
}
#endregion
private List<Models.UserHeldDevices.UserHeldDeviceModel> GetUserHeldDevices()
{
return GetUserHeldDevices(Database.Jobs);
}
private Models.UserHeldDevices.UserHeldDeviceModel GetUserHeldDevice(string UserId)
{
return GetUserHeldDevices(Database.Jobs.Where(j => j.Device.AssignedUserId == UserId)).FirstOrDefault();
}
public virtual ActionResult Index()
{
return View(GetUserHeldDevices());
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
return View(m);
}
public virtual ActionResult ReadyForReturnXml()
{
var readyForReturn = GetUserHeldDevices().Where(j => j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
var readyForReturn = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
.Where(j => j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(readyForReturn);
}
public virtual ActionResult WaitingForUserActionXml()
{
var userHeldDevices = GetUserHeldDevices().Where(j => j.WaitingForUserAction).ToArray();
var userHeldDevices = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
.Where(j => j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(userHeldDevices);
}
public virtual ActionResult UserHeldDevicesXml()
{
var userHeldDevices = GetUserHeldDevices().Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
var userHeldDevices = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
.Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
return new Extensions.XmlResult(userHeldDevices);
}
@@ -91,14 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
public virtual ActionResult UserHeldDevice(string id)
{
var uhd = GetUserHeldDevice(id);
return Json(uhd, JsonRequestBehavior.AllowGet);
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDeviceForUsers(Database, id);
return Json(m, JsonRequestBehavior.AllowGet);
}
public virtual ActionResult UserHeldDevices()
{
var uhd = GetUserHeldDevices();
return Json(uhd, JsonRequestBehavior.AllowGet);
}
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
return Json(m, JsonRequestBehavior.AllowGet);
}
}
}
@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Disco.Web.Areas.Public.Models.HeldDevices
{
public class HeldDeviceModel
{
public string DeviceSerialNumber { get; set; }
public string DeviceComputerName { get; set; }
public int DeviceProfileId { get; set; }
public string DeviceAddress { get; set; }
public string DeviceLocation { get; set; }
public string DeviceDescription
{
get
{
StringBuilder sb = new StringBuilder(this.DeviceComputerName);
if (UserId != null)
sb.Append(" - ").Append(this.UserDisplayName).Append(" (").Append(this.UserId).Append(")");
if (!string.IsNullOrWhiteSpace(this.DeviceLocation))
sb.Append(" - ").Append(this.DeviceLocation);
else if (UserId == null)
sb.Append(" - ").Append(this.DeviceSerialNumber);
return sb.ToString();
}
}
public string UserId { get; set; }
public string UserDisplayName { get; set; }
public bool WaitingForUserAction { get; set; }
public string WaitingForUserActionSince { get; set; }
public bool ReadyForReturn { get; set; }
public string EstimatedReturnTime { get; set; }
public string ReadyForReturnSince { get; set; }
public bool IsAlert { get; set; }
}
}
@@ -1,61 +0,0 @@
using Disco.Data.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Disco.BI.Extensions;
namespace Disco.Web.Areas.Public.Models.HeldDevices
{
public class HeldDeviceQueryModel
{
public int JobId { get; set; }
public string DeviceSerialNumber { get; set; }
public string DeviceComputerName { get; set; }
public int DeviceProfileId { get; set; }
public int? DeviceAddressId { get; set; }
public string DeviceLocation { get; set; }
public string UserId { get; set; }
public string UserDisplayName { get; set; }
public bool ReadyForReturn { get; set; }
public bool WaitingForUserAction { get; set; }
public DateTime? EstimatedReturnTime { get; set; }
public DateTime? ReadyForReturnSince { get; set; }
public DateTime? WaitingForUserActionSince { get; set; }
public HeldDeviceModel ToUserHeldDeviceModel(DiscoDataContext Database)
{
var uhdm = new HeldDeviceModel()
{
DeviceSerialNumber = this.DeviceSerialNumber,
DeviceComputerName = this.DeviceComputerName,
DeviceLocation = this.DeviceLocation,
DeviceProfileId = this.DeviceProfileId,
DeviceAddress = (this.DeviceAddressId.HasValue ? Database.DiscoConfiguration.OrganisationAddresses.GetAddress(this.DeviceAddressId.Value).ShortName : string.Empty),
UserId = this.UserId,
UserDisplayName = this.UserDisplayName,
ReadyForReturn = this.ReadyForReturn,
WaitingForUserAction = this.WaitingForUserAction
};
var n = DateTime.Now;
if (!this.ReadyForReturn && this.EstimatedReturnTime.HasValue && this.EstimatedReturnTime.Value > n)
{
uhdm.EstimatedReturnTime = this.EstimatedReturnTime.FromNow();
}
if (this.ReadyForReturn)
{
uhdm.ReadyForReturnSince = this.ReadyForReturnSince.FromNow();
uhdm.IsAlert = (this.ReadyForReturnSince.Value < DateTime.Now.AddDays(-3));
}
if (this.WaitingForUserAction)
{
uhdm.WaitingForUserActionSince = this.WaitingForUserActionSince.FromNow();
uhdm.IsAlert = (this.WaitingForUserActionSince.Value < n.AddDays(-6));
}
return uhdm;
}
}
}
@@ -1,7 +1,6 @@
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.AspNet.SignalR;
using Disco.BI.Interop.SignalRHandlers;
namespace Disco.Web.Areas.Public
{
@@ -17,11 +16,6 @@ namespace Disco.Web.Areas.Public
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapConnection<UserHeldDeviceNotifications>(
"Public_UserHeldDevices_Notifications", "Public/UserHeldDevices/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
context.Routes.MapConnection<HeldDeviceNotifications>(
"Public_HeldDevices_Notifications", "Public/HeldDevices/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
context.MapRoute(
"Public_Credits",
"Public/Credits/{id}",
@@ -1,4 +1,4 @@
@model IEnumerable<Disco.Web.Areas.Public.Models.HeldDevices.HeldDeviceModel>
@model IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>
@{
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices", null);
Html.BundleDeferred("~/Style/Public/HeldDevices");
@@ -10,16 +10,16 @@
}
<h2>In Process (@DevicesInProcess.Length)</h2>
<table class="dataTable">
@foreach (var item in DevicesInProcess)
@foreach (var item in DevicesInProcess.OrderBy(i => i.DeviceComputerNameFriendly))
{
<tr>
<td class="id">
@item.DeviceComputerName
@item.DeviceComputerNameFriendly
</td>
<td class="description">
@if (item.UserId != null)
{
<span class="user">@item.UserDisplayName (@item.UserId)</span>
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
}
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
{
@@ -36,9 +36,9 @@
@item.DeviceSerialNumber
}
}
@if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
@if (item.EstimatedReturnTime.HasValue)
{
<span class="smallMessage">(Expected: @item.EstimatedReturnTime)</span>
<span class="smallMessage">(Expected: @CommonHelpers.FriendlyDate(item.EstimatedReturnTime))</span>
}
</td>
</tr>
@@ -51,16 +51,16 @@
}
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
<table class="dataTable">
@foreach (var item in WaitingForUserActionJobs)
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.DeviceComputerNameFriendly))
{
<tr>
<td class="id">
@item.DeviceComputerName
@item.DeviceComputerNameFriendly
</td>
<td class="description">
@if (item.UserId != null)
{
<span class="user">@item.UserDisplayName (@item.UserId)</span>
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
}
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
{
@@ -78,7 +78,7 @@
}
}
</td>
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @item.WaitingForUserActionSince
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @CommonHelpers.FriendlyDate(item.WaitingForUserActionSince)
</td>
</tr>
}
@@ -89,16 +89,16 @@
}
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
<table class="dataTable">
@foreach (var item in DevicesReadyForReturn)
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.DeviceComputerNameFriendly))
{
<tr>
<td class="id">
@item.DeviceComputerName
@item.DeviceComputerNameFriendly
</td>
<td class="description">
@if (item.UserId != null)
{
<span class="user">@item.UserDisplayName (@item.UserId)</span>
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
}
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
{
@@ -116,7 +116,7 @@
}
}
</td>
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @item.ReadyForReturnSince
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @CommonHelpers.FriendlyDate(item.ReadyForReturnSince)
</td>
</tr>
}
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -36,7 +36,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/HeldDevices/Index.cshtml")]
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Web.Areas.Public.Models.HeldDevices.HeldDeviceModel>>
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>>
{
public Index()
{
@@ -99,7 +99,7 @@ WriteLiteral(">\r\n");
#line hidden
#line 13 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
foreach (var item in DevicesInProcess)
foreach (var item in DevicesInProcess.OrderBy(i => i.DeviceComputerNameFriendly))
{
@@ -115,7 +115,7 @@ WriteLiteral(" ");
#line 17 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.DeviceComputerName);
Write(item.DeviceComputerNameFriendly);
#line default
@@ -157,7 +157,7 @@ WriteLiteral(" (");
#line 22 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.UserId);
Write(item.UserIdFriendly);
#line default
@@ -235,7 +235,7 @@ WriteLiteral(" ");
#line 39 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
if (item.EstimatedReturnTime.HasValue)
{
@@ -249,7 +249,7 @@ WriteLiteral(">(Expected: ");
#line 41 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.EstimatedReturnTime);
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
#line default
@@ -315,7 +315,7 @@ WriteLiteral(">\r\n");
#line hidden
#line 54 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
foreach (var item in WaitingForUserActionJobs)
foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.DeviceComputerNameFriendly))
{
@@ -331,7 +331,7 @@ WriteLiteral(" ");
#line 58 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.DeviceComputerName);
Write(item.DeviceComputerNameFriendly);
#line default
@@ -373,7 +373,7 @@ WriteLiteral(" (");
#line 63 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.UserId);
Write(item.UserIdFriendly);
#line default
@@ -449,22 +449,22 @@ WriteLiteral("\r\n");
#line hidden
WriteLiteral(" </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 3267), Tuple.Create("\"", 3325)
, Tuple.Create(Tuple.Create("", 3275), Tuple.Create("timestamp", 3275), true)
WriteAttribute("class", Tuple.Create(" class=\"", 3397), Tuple.Create("\"", 3455)
, Tuple.Create(Tuple.Create("", 3405), Tuple.Create("timestamp", 3405), true)
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 3284), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
, Tuple.Create(Tuple.Create("", 3414), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line default
#line hidden
, 3284), false)
, 3414), false)
);
WriteLiteral(">Since ");
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.WaitingForUserActionSince);
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
#line default
@@ -517,7 +517,7 @@ WriteLiteral(">\r\n");
#line hidden
#line 92 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
foreach (var item in DevicesReadyForReturn)
foreach (var item in DevicesReadyForReturn.OrderBy(i => i.DeviceComputerNameFriendly))
{
@@ -533,7 +533,7 @@ WriteLiteral(" ");
#line 96 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.DeviceComputerName);
Write(item.DeviceComputerNameFriendly);
#line default
@@ -575,7 +575,7 @@ WriteLiteral(" (");
#line 101 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.UserId);
Write(item.UserIdFriendly);
#line default
@@ -651,22 +651,22 @@ WriteLiteral("\r\n");
#line hidden
WriteLiteral(" </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 4805), Tuple.Create("\"", 4863)
, Tuple.Create(Tuple.Create("", 4813), Tuple.Create("timestamp", 4813), true)
WriteAttribute("class", Tuple.Create(" class=\"", 5022), Tuple.Create("\"", 5080)
, Tuple.Create(Tuple.Create("", 5030), Tuple.Create("timestamp", 5030), true)
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 4822), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
, Tuple.Create(Tuple.Create("", 5039), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line default
#line hidden
, 4822), false)
, 5039), false)
);
WriteLiteral(">Ready ");
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
Write(item.ReadyForReturnSince);
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
#line default
@@ -1,5 +1,6 @@
@{
Layout = null;
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/ClientScripts/Core");
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
@@ -9,468 +10,397 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Disco - Held Devices</title>
<title>Disco ICT - Held Devices</title>
@Html.BundleRenderDeferred()
</head>
<body>
<body class="status-connecting">
<div id="page">
<header id="mainHeader">
Held Devices
<header id="header">
<div id="heading">Held Devices</div>
<div id="statusConnecting"><i class="fa fa-cog fa-spin"></i><span>connecting...</span></div>
<div id="statusError"><i class="fa fa-cog fa-spin"></i><span>disconnected, reconnecting...</span></div>
<div id="credits">
powered by Disco ICT <i title="Disco ICT - Jobs"></i>
</div>
</header>
<section id="mainSection">
<div id="inProcess" class="list">
<h3>In Process <span id="inProcessCount"></span>
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: inProcess().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<div id="readyForReturn" class="list">
<h3>Ready for Return <span id="readyForReturnCount"></span>
<h3>Ready for Return (<span data-bind="text: readyForReturn().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: readyForReturn().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<div id="waitingForUserAction" class="list">
<h3>Waiting for User Action <span id="waitingForUserActionCount"></span>
<h3>Waiting for User Action (<span data-bind="text: waitingForUserAction().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: waitingForUserAction().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<footer id="footer">
</footer>
</section>
<footer>
</footer>
</div>
<script type="text/javascript">
// Resizing
$(function () {
var $inProcess = $('#inProcess');
var $inProcessContent = $inProcess.find('.content');
var $inProcessHeader = $inProcess.find('.h3');
var $readyForReturn = $('#readyForReturn');
var $readyForReturnContent = $readyForReturn.find('.content');
var $readyForReturnHeader = $readyForReturn.find('.h3');
var $waitingForUserAction = $('#waitingForUserAction');
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
var $mainSection = $('#mainSection');
var $mainHeader = $('#mainHeader');
var $mainFooter = $('#mainFooter');
var onResize = function () {
var width = $mainSection.width();
var height = $(window).height() - $mainHeader.outerHeight() - $mainFooter.outerHeight() - 25;
$inProcess.height(height);
$inProcess.width((width * .28) - 11);
$inProcessContent.height(height - $inProcessHeader.outerHeight() - 56);
$readyForReturn.height(height);
$readyForReturn.width((width * .36) - 11);
$readyForReturnContent.height(height - $readyForReturnHeader.outerHeight() - 56);
$waitingForUserAction.height(height);
$waitingForUserAction.width((width * .36) - 11);
$waitingForUserActionContent.height(height - $waitingForUserActionHeader.outerHeight() - 56);
};
$(window).resize(onResize);
onResize();
});
<script type="text/html" id="item-template">
<li data-bind="css: { alert: IsAlert }">
<span data-bind="text: DeviceDescription"></span>
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
<!-- /ko -->
<!-- ko if: WaitingForUserAction -->
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
<!-- /ko -->
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
<!-- /ko -->
</li>
</script>
<script type="text/javascript">
// Hide Mouse Mouse
$(function () {
var mouseVisible = true;
var mouseHideToken;
var documentBody = $('body');
<script>
ko.bindingHandlers.livestamp = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
var hideMouse = function () {
if (mouseVisible) {
documentBody.css('cursor', 'none');
mouseVisible = false;
}
};
var showMouse = function () {
if (!mouseVisible) {
documentBody.css('cursor', 'auto');
mouseVisible = true;
}
};
$(document).mousemove(function () {
showMouse();
if (mouseHideToken)
window.clearTimeout(mouseHideToken);
mouseHideToken = window.setTimeout(hideMouse, 2000);
});
});
</script>
<script type="text/javascript">
$(function () {
var models = {};
var modelsInProcessSorted = [];
var modelsInProcessCount = 0;
var modelsReadyForReturnSorted = [];
var modelsReadyForReturnCount = 0;
var modelsWaitingForUserActionSorted = [];
var modelsWaitingForUserActionCount = 0;
var $inProcess = $('#inProcess');
var $inProcessContent = $inProcess.find('.content ul');
var $readyForReturn = $('#readyForReturn');
var $readyForReturnContent = $readyForReturn.find('.content ul');
var $waitingForUserAction = $('#waitingForUserAction');
var $waitingForUserActionContent = $waitingForUserAction.find('.content ul');
var modelsInProcessIndexOffset = 0;
var scrollInProcessToken = null;
var modelsReadyForReturnIndexOffset = 0;
var scrollReadyForReturnToken = null;
var modelsWaitingForUserActionIndexOffset = 0;
var scrollWaitingForUserActionToken = null;
var scrollSpeed = 3000;
var persistantConnection = null;
var filterDeviceAddressInclude;
var filterDeviceAddressExclude;
var filterDeviceProfileInclude;
var filterDeviceProfileExclude;
var getParameterByName = function (name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if (results == null)
return "";
if (valueUnwrapped)
$(element).livestamp(valueUnwrapped);
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
$(element).livestamp('destroy');
}
};
</script>
<script>
$(function () {
var hub;
var viewModel;
var buildFilters = function () {
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
if (deviceAddressInclude) {
filterDeviceAddressInclude = {};
var split = deviceAddressInclude.split(",");
for (var i = 0; i < split.length; i++) {
filterDeviceAddressInclude[split[i].toLowerCase()] = true;
}
} else {
var deviceAddressExclude = getParameterByName('deviceAddressExclude');
if (deviceAddressExclude) {
filterDeviceAddressExclude = {};
var split = deviceAddressExclude.split(",");
for (var i = 0; i < split.length; i++) {
filterDeviceAddressExclude[split[i].toLowerCase()] = true;
}
} else {
var deviceProfileInclude = getParameterByName('deviceProfileInclude');
if (deviceProfileInclude) {
filterDeviceProfileInclude = {};
var deviceProfileIncludeSplit = deviceProfileInclude.split(",");
for (var i = 0; i < deviceProfileIncludeSplit.length; i++) {
filterDeviceProfileInclude[parseInt(deviceProfileIncludeSplit[i])] = true;
}
} else {
var deviceProfileExclude = getParameterByName('deviceProfileExclude');
if (deviceProfileExclude) {
filterDeviceProfileExclude = {};
var deviceProfileExcludeSplit = deviceProfileExclude.split(",");
for (var i = 0; i < deviceProfileExcludeSplit.length; i++) {
filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;
}
}
}
}
}
}
var calculateFilter = function (model) {
if (model) {
if (filterDeviceAddressInclude) {
return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)
}
if (filterDeviceAddressExclude) {
return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()])
}
if (filterDeviceProfileInclude) {
return (filterDeviceProfileInclude[model.DeviceProfileId] == true)
}
if (filterDeviceProfileExclude) {
return (!filterDeviceProfileExclude[model.DeviceProfileId])
}
return true;
}
return false;
}
var rotateSpeed = 3000;
var itemFilters;
var sortModels = function () {
modelsInProcessSorted = [];
modelsReadyForReturnSorted = [];
modelsWaitingForUserActionSorted = [];
var modelSortFunc = function (a, b) {
if (a.DeviceSerialNumber.toUpperCase() == b.DeviceSerialNumber.toUpperCase()) {
return 0;
} else {
if (a.DeviceSerialNumber.toUpperCase() < b.DeviceSerialNumber.toUpperCase()) {
return -1
} else {
return 1
}
}
};
for (var key in models) {
var model = models[key];
if (model) {
if (model.WaitingForUserAction) {
modelsWaitingForUserActionSorted.push(model);
} else {
if (model.ReadyForReturn) {
modelsReadyForReturnSorted.push(model);
} else {
modelsInProcessSorted.push(model);
}
}
}
}
modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortFunc);
modelsInProcessSorted = modelsInProcessSorted.sort(modelSortFunc);
modelsWaitingForUserActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);
var $inProcessList = $('#inProcess').find('ul');
var $readyForReturnList = $('#readyForReturn').find('ul');
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
if (modelsInProcessSorted.length != modelsInProcessCount) {
modelsInProcessCount = modelsInProcessSorted.length;
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
}
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
}
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
}
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
var self = this;
};
self.initialized = false;
var scrollReadyForReturn = function () {
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
modelsReadyForReturnIndexOffset++;
if (modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {
modelsReadyForReturnIndexOffset = 0;
}
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
};
var updateScrollReadyForReturn = function () {
var containerHeight = $readyForReturn.find('.content').height();
var contentHeight = $readyForReturnContent.height();
if (containerHeight >= contentHeight && scrollReadyForReturnToken) {
window.clearTimeout(scrollReadyForReturnToken);
return;
}
if (containerHeight < contentHeight && scrollReadyForReturnToken == null) {
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
}
};
var scrollInProcess = function () {
$inProcessContent.find('li').last().detach().prependTo($inProcessContent).hide().slideDown('slow');
modelsInProcessIndexOffset++;
if (modelsInProcessIndexOffset >= modelsInProcessSorted.length) {
modelsInProcessIndexOffset = 0;
}
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
};
var updateScrollInProcess = function () {
var containerHeight = $inProcess.find('.content').height();
var contentHeight = $inProcessContent.height();
if (containerHeight >= contentHeight && scrollInProcessToken) {
window.clearTimeout(scrollInProcessToken);
return;
}
if (containerHeight < contentHeight && scrollInProcessToken == null) {
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
}
};
var scrollWaitingForUserAction = function () {
$waitingForUserActionContent.find('li').last().detach().prependTo($waitingForUserActionContent).hide().slideDown('slow');
modelsInProcessIndexOffset++;
if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserActionSorted.length) {
modelsWaitingForUserActionIndexOffset = 0;
}
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
};
var updateScrollWaitingForUserAction = function () {
var containerHeight = $waitingForUserAction.find('.content').height();
var contentHeight = $waitingForUserActionContent.height();
if (containerHeight >= contentHeight && scrollWaitingForUserActionToken) {
window.clearTimeout(scrollWaitingForUserActionToken);
return;
}
if (containerHeight < contentHeight && scrollWaitingForUserActionToken == null) {
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
}
};
self.inProcess = ko.observableArray(inProcess);
self.readyForReturn = ko.observableArray(readyForReturn);
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
var modelInsertIndex = function (model) {
sortModels();
var findIndex = function (model, array, offset) {
for (var i = 0; i < array.length; i++) {
if (model.DeviceSerialNumber == array[i].DeviceSerialNumber) {
var index = i + offset;
if (index > (array.length - 1)) {
index = index - (array.length - 1);
}
return index;
}
};
};
if (model.WaitingForUserAction) {
return findIndex(model, modelsWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);
} else {
if (model.ReadyForReturn) {
return findIndex(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);
} else {
return findIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);
}
}
}
var modelInsert = function (model) {
var index = modelInsertIndex(model);
var insertTo = function (model, host) {
var hostLi = host.children('li');
if (hostLi.length == 0 || hostLi.length < index) {
host.append(model.htmlLi);
} else {
if (index == 0) {
host.prepend(model.htmlLi);
} else {
$(hostLi.get(index - 1)).after(model.htmlLi);
}
}
}
if (model.WaitingForUserAction) {
insertTo(model, $waitingForUserActionContent);
window.setTimeout(updateScrollWaitingForUserAction, 100);
} else {
if (model.ReadyForReturn) {
insertTo(model, $readyForReturnContent);
window.setTimeout(updateScrollReadyForReturn, 100);
} else {
insertTo(model, $inProcessContent);
window.setTimeout(updateScrollInProcess, 100);
}
}
}
var removeModel = function (model) {
if (model) {
model.htmlLi.slideUp('fast', function () {
model.htmlLi.remove();
self.onRemove = function (element, index, data) {
$(element).slideUp(400, function () {
$(this).remove();
});
}
};
var processModel = function (id, model, init) {
if (!calculateFilter(model)) {
removeModel(models[id]);
delete models[id];
sortModels();
} else {
var existing = models[id];
models[id] = model;
// Add
model.htmlContent = $('<div>').text(model.DeviceDescription);
if (!model.ReadyForReturn && model.EstimatedReturnTime) {
model.htmlContent.append($('<span class="small">').text(' (Expected: ' + model.EstimatedReturnTime + ')'));
}
if (model.WaitingForUserAction) {
model.htmlContent.append($('<span class="small">').text(' (Since ' + model.WaitingForUserActionSince + ')'));
} else {
if (model.ReadyForReturn && model.ReadyForReturnSince) {
model.htmlContent.append($('<span class="small">').text(' (Ready ' + model.ReadyForReturnSince + ')'));
}
}
if (existing) {
if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction) {
removeModel(existing);
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
modelInsert(model);
if (init) {
model.htmlLi.fadeIn();
} else {
model.htmlLi.slideDown();
}
} else {
model.htmlLi = existing.htmlLi;
model.htmlLi.slideUp('fast', function () {
model.htmlLi.html(model.htmlContent).slideDown();
});
}
} else {
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
modelInsert(model);
if (init) {
model.htmlLi.fadeIn();
} else {
model.htmlLi.slideDown('slow');
}
}
if (model.htmlLi && model.IsAlert) {
model.htmlLi.addClass('alert');
}
self.onAdd = function (element, index, data) {
if (self.initialized)
$(element).hide().slideDown(400);
}
};
var updatedModel = function (id) {
var deviceSerialNumber = id.toString();
$.ajax({
dataType: 'json',
url: '@(Url.Action(MVC.Public.HeldDevices.HeldDevice()))',
data: { id: deviceSerialNumber },
success: function (data) {
processModel(deviceSerialNumber, data, false);
},
error: function (jqXHR, textStatus, errorThrown) {
if (textStatus == 'parsererror') // null Result
processModel(deviceSerialNumber, null, false);
}
})
};
var connectionError = function () {
if (persistantConnection) {
persistantConnection.stop();
persistantConnection = null;
window.setTimeout(function () {
window.location.href = '@(Url.Action(MVC.Public.HeldDevices.Noticeboard()))';
}, 10000);
}
}
var init = function () {
buildFilters();
persistantConnection = $.connection('@(Url.Content("~/Public/HeldDevices/Notifications"))');
persistantConnection.received(updatedModel);
persistantConnection.error(connectionError);
persistantConnection.start(function () {
$.getJSON('@(Url.Action(MVC.Public.HeldDevices.HeldDevices()))', null, function (data) {
for (var i = 0; i < data.length; i++) {
processModel(data[i].DeviceSerialNumber, data[i], true);
}
function init() {
// Connect to Hub
hub = $.connection.noticeboardUpdates;
// Map Functions
hub.client.updateHeldDevice = updateHeldDevice;
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevices.Name)' };
$.connection.hub.error(connectionError);
$.connection.hub.disconnected(connectionError);
$.connection.hub.reconnected(connectionError);
// Start Connection
$.connection.hub.start().fail(connectionError).done(loadData);
}
// Called after SignalR is connected
function loadData() {
$.getJSON('@(Url.Action(MVC.Public.HeldDevices.HeldDevices()))', null, function (data) {
var inProcess = [];
var readyForReturn = [];
var waitingForUserAction = [];
data.filter(function (heldDeviceItem) {
return includeItem(heldDeviceItem)
}).forEach(function (heldDeviceItem) {
if (isWaitingForUserAction(heldDeviceItem))
waitingForUserAction.push(heldDeviceItem);
else if (isReadyForReturn(heldDeviceItem))
readyForReturn.push(heldDeviceItem);
else if (isInProcess(heldDeviceItem))
inProcess.push(heldDeviceItem);
});
inProcess.sort(sortFunction);
readyForReturn.sort(sortFunction);
waitingForUserAction.sort(sortFunction);
viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction);
ko.applyBindings(viewModel);
viewModel.initialized = true;
$('body').removeClass('status-connecting');
window.setTimeout(scheduleRotation, rotateSpeed);
});
};
init();
buildFilters();
}
// Called by SignalR
function updateHeldDevice(updates) {
if (viewModel) {
$.each(updates, function (deviceSerialNumber, heldDeviceItem) {
// Remove Existing
removeItem(deviceSerialNumber);
// Add Item
addItem(heldDeviceItem);
});
}
}
function removeItem(deviceSerialNumber) {
removeItemFromArray(viewModel.inProcess, deviceSerialNumber);
removeItemFromArray(viewModel.readyForReturn, deviceSerialNumber);
removeItemFromArray(viewModel.waitingForUserAction, deviceSerialNumber);
}
function addItem(heldDeviceItem) {
if (heldDeviceItem !== null &&
heldDeviceItem !== undefined &&
includeItem(heldDeviceItem)) {
var array;
if (isWaitingForUserAction(heldDeviceItem))
array = viewModel.waitingForUserAction;
else if (isReadyForReturn(heldDeviceItem))
array = viewModel.readyForReturn;
else if (isInProcess(heldDeviceItem))
array = viewModel.inProcess;
if (array().length === 0) {
array.push(heldDeviceItem);
} else {
var index = findSortedInsertIndex(array, heldDeviceItem);
if (index === -1)
array.push(heldDeviceItem);
else
array.splice(index, 0, heldDeviceItem);
}
}
}
function rotateArrays() {
rotateArray(viewModel.inProcess, $inProcessList);
rotateArray(viewModel.readyForReturn, $readyForReturnList);
rotateArray(viewModel.waitingForUserAction, $waitingForUserActionList);
}
function scheduleRotation() {
rotateArrays();
window.setTimeout(scheduleRotation, rotateSpeed);
}
function includeItem(heldDeviceItem) {
if (itemFilters == null || itemFilters.length == 0)
return true;
return itemFilters.reduce(function (previousValue, currentValue, index, array) {
if (previousValue === false)
return false;
return currentValue(heldDeviceItem);
}, true);
}
function buildFilters() {
var filters = [];
var queryStringParameters = getQueryStringParameters();
if (queryStringParameters !== null) {
$.each(queryStringParameters, function (key, value) {
switch (key.toLowerCase()) {
case 'deviceaddressinclude':
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
if (deviceAddresses.length > 0) {
filters.push(function (heldDeviceItem) {
// false if DeviceAddressShortName is null
if (!heldDeviceItem.DeviceAddressShortName)
return false;
// true if DeviceAddressShortName is included
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) >= 0;
});
}
break;
case 'deviceaddressexclude':
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
if (deviceAddresses.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceAddressShortName is null
if (!heldDeviceItem.DeviceAddressShortName)
return true;
// true if DeviceAddressShortName is excluded
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) < 0;
});
}
break;
case 'deviceprofileinclude':
var deviceProfiles = value.split(",");
if (deviceProfiles.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceProfileId is included
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;
});
}
break;
case 'deviceprofileexclude':
var deviceProfiles = value.split(",");
if (deviceProfiles.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceProfileId is excluded
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;
});
}
break;
}
});
}
if (filters.length > 0)
itemFilters = filters;
else
itemFilters = null;
}
function connectionError() {
try {
$('body').addClass('status-error');
$.connection.hub.stop();
} catch (e) {
// Ignore
}
window.setTimeout(function () {
window.location.href = window.location.href;
}, 10000);
}
// Helpers
function rotateArray(koArray, element) {
var items = koArray();
if (items.length <= 1)
return 0;
if (element.height() < (element.parent().height() - 30)) {
if (findUnsortedArrayTopIndex(items) !== 0)
koArray.sort(sortFunction);
// Don't rotate if small & sorted correctly
return;
}
// Move Last Item to Top
var item = koArray.pop();
koArray.unshift(item);
}
function removeItemFromArray(koArray, deviceSerialNumber) {
var items = koArray();
for (var i = 0; i < items.length; i++) {
if (items[i].DeviceSerialNumber == deviceSerialNumber) {
koArray.splice(i, 1);
items = koArray();
i--;
}
}
}
function findUnsortedArrayTopIndex(items) {
// Only one Item
if (items.length <= 1)
return 0;
for (var i = 1; i < items.length; i++) {
var s = sortFunction(items[i - 1], items[i]);
if (s > 0)
return i;
}
return 0;
}
function findSortedInsertIndex(koArray, heldDeviceItem) {
var items = koArray();
var startIndex = findUnsortedArrayTopIndex(items);
for (var i = startIndex; i < items.length; i++) {
var s = sortFunction(heldDeviceItem, items[i]);
if (s <= 0)
return i;
}
if (startIndex !== 0) {
for (var i = 0; i < startIndex; i++) {
var s = sortFunction(heldDeviceItem, items[i]);
if (s <= 0)
return i;
}
return startIndex;
} else {
return -1;
}
}
function sortFunction(l, r) {
return l.DeviceDescription.toLowerCase() == r.DeviceDescription.toLowerCase() ? 0 : (l.DeviceDescription.toLowerCase() < r.DeviceDescription.toLowerCase() ? -1 : 1)
}
function isInProcess(i) {
return !i.ReadyForReturn && !i.WaitingForUserAction;
}
function isReadyForReturn(i) {
return i.ReadyForReturn && !i.WaitingForUserAction;
}
function isWaitingForUserAction(i) {
return i.WaitingForUserAction;
}
function getQueryStringParameters() {
if (window.location.search.length === 0)
return null;
var params = {};
window.location.search.substr(1).split("&").forEach(function (pair) {
if (pair === "") return;
var parts = pair.split("=");
params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace(/\+/g, " "));
});
return params;
}
init();
});
</script>
<div id="mainFooter">
<img style="width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;" src="@Links.ClientSource.Style.Images.Heading_png" alt="Disco Logo" />
powered by Disco
</div>
</body>
</html>
</html>
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices
#line 1 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Layout = null;
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/ClientScripts/Core");
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
WriteLiteral(" content=\"IE=edge\"");
WriteLiteral(" />\r\n <title>Disco - Held Devices</title>\r\n");
WriteLiteral(" />\r\n <title>Disco ICT - Held Devices</title>\r\n");
WriteLiteral(" ");
#line 13 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
#line 14 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Html.BundleRenderDeferred());
#line default
#line hidden
WriteLiteral("\r\n</head>\r\n<body>\r\n <div");
WriteLiteral("\r\n</head>\r\n<body");
WriteLiteral(" class=\"status-connecting\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"page\"");
WriteLiteral(">\r\n <header");
WriteLiteral(" id=\"mainHeader\"");
WriteLiteral(" id=\"header\"");
WriteLiteral(">\r\n Held Devices\r\n </header>\r\n <section");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"heading\"");
WriteLiteral(">Held Devices</div>\r\n <div");
WriteLiteral(" id=\"statusConnecting\"");
WriteLiteral("><i");
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
WriteLiteral("></i><span>connecting...</span></div>\r\n <div");
WriteLiteral(" id=\"statusError\"");
WriteLiteral("><i");
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
WriteLiteral("></i><span>disconnected, reconnecting...</span></div>\r\n <div");
WriteLiteral(" id=\"credits\"");
WriteLiteral(">\r\n powered by Disco ICT <i");
WriteLiteral(" title=\"Disco ICT - Jobs\"");
WriteLiteral("></i>\r\n </div>\r\n </header>\r\n <section");
WriteLiteral(" id=\"mainSection\"");
@@ -93,403 +126,289 @@ WriteLiteral(" id=\"inProcess\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>In Process <span");
WriteLiteral(">\r\n <h3>In Process (<span");
WriteLiteral(" id=\"inProcessCount\"");
WriteLiteral(" data-bind=\"text: inProcess().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n <div");
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
" <div");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: inProcess, afterRender: o" +
"nAdd, beforeRemove: onRemove }\"");
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
WriteLiteral(" id=\"readyForReturn\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>Ready for Return <span");
WriteLiteral(">\r\n <h3>Ready for Return (<span");
WriteLiteral(" id=\"readyForReturnCount\"");
WriteLiteral(" data-bind=\"text: readyForReturn().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n <div");
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
" <div");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: readyForReturn, afterRend" +
"er: onAdd, beforeRemove: onRemove }\"");
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
WriteLiteral(" id=\"waitingForUserAction\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>Waiting for User Action <span");
WriteLiteral(">\r\n <h3>Waiting for User Action (<span");
WriteLiteral(" id=\"waitingForUserActionCount\"");
WriteLiteral(" data-bind=\"text: waitingForUserAction().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
"</div>\r\n <script");
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
" <div");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
"#inProcess\');\r\n var $inProcessContent = $inProcess.find(\'.content\');\r" +
"\n var $inProcessHeader = $inProcess.find(\'.h3\');\r\n var $re" +
"adyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnContent = $" +
"readyForReturn.find(\'.content\');\r\n var $readyForReturnHeader = $ready" +
"ForReturn.find(\'.h3\');\r\n var $waitingForUserAction = $(\'#waitingForUs" +
"erAction\');\r\n var $waitingForUserActionContent = $waitingForUserActio" +
"n.find(\'.content\');\r\n var $waitingForUserActionHeader = $waitingForUs" +
"erAction.find(\'.h3\');\r\n var $mainSection = $(\'#mainSection\');\r\n " +
" var $mainHeader = $(\'#mainHeader\');\r\n var $mainFooter = $(\'#mai" +
"nFooter\');\r\n\r\n var onResize = function () {\r\n var widt" +
"h = $mainSection.width();\r\n var height = $(window).height() - $ma" +
"inHeader.outerHeight() - $mainFooter.outerHeight() - 25;\r\n\r\n $inP" +
"rocess.height(height);\r\n $inProcess.width((width * .28) - 11);\r\n " +
" $inProcessContent.height(height - $inProcessHeader.outerHeight() " +
"- 56);\r\n\r\n $readyForReturn.height(height);\r\n $read" +
"yForReturn.width((width * .36) - 11);\r\n $readyForReturnContent.he" +
"ight(height - $readyForReturnHeader.outerHeight() - 56);\r\n\r\n $wai" +
"tingForUserAction.height(height);\r\n $waitingForUserAction.width((" +
"width * .36) - 11);\r\n $waitingForUserActionContent.height(height " +
"- $waitingForUserActionHeader.outerHeight() - 56);\r\n };\r\n\r\n " +
" $(window).resize(onResize);\r\n onResize();\r\n });\r\n </scrip" +
"t>\r\n <script");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
"erAdd: onAdd, beforeRemove: onRemove }\"");
WriteLiteral(@">
// Hide Mouse Mouse
$(function () {
var mouseVisible = true;
var mouseHideToken;
var documentBody = $('body');
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
var hideMouse = function () {
if (mouseVisible) {
documentBody.css('cursor', 'none');
mouseVisible = false;
}
};
var showMouse = function () {
if (!mouseVisible) {
documentBody.css('cursor', 'auto');
mouseVisible = true;
}
};
WriteLiteral(" id=\"footer\"");
$(document).mousemove(function () {
showMouse();
if (mouseHideToken)
window.clearTimeout(mouseHideToken);
mouseHideToken = window.setTimeout(hideMouse, 2000);
});
});
</script>
<script");
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" type=\"text/html\"");
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
" var persistantConnection = null;\r\n var filterDeviceAddress" +
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n\r\n v" +
"ar getParameterByName = function (name) {\r\n name = name.replace(/" +
"[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS = \"[\\\\?&]\" +" +
" name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS);\r\n " +
" var results = regex.exec(window.location.search);\r\n if (re" +
"sults == null)\r\n return \"\";\r\n else\r\n " +
" return decodeURIComponent(results[1].replace(/\\+/g, \" \"));\r\n " +
" }\r\n\r\n var buildFilters = function () {\r\n var deviceA" +
"ddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n if " +
"(deviceAddressInclude) {\r\n filterDeviceAddressInclude = {};\r\n" +
" var split = deviceAddressInclude.split(\",\");\r\n " +
" for (var i = 0; i < split.length; i++) {\r\n filterDe" +
"viceAddressInclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
" } else {\r\n var deviceAddressExclude = getParameter" +
"ByName(\'deviceAddressExclude\');\r\n if (deviceAddressExclude) {" +
"\r\n filterDeviceAddressExclude = {};\r\n " +
" var split = deviceAddressExclude.split(\",\");\r\n for (v" +
"ar i = 0; i < split.length; i++) {\r\n filterDeviceAddr" +
"essExclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
" } else {\r\n var deviceProfileInclude = getParam" +
"eterByName(\'deviceProfileInclude\');\r\n if (deviceProfileIn" +
"clude) {\r\n filterDeviceProfileInclude = {};\r\n " +
" var deviceProfileIncludeSplit = deviceProfileInclude.split(\"" +
",\");\r\n for (var i = 0; i < deviceProfileIncludeSplit." +
"length; i++) {\r\n filterDeviceProfileInclude[parse" +
"Int(deviceProfileIncludeSplit[i])] = true;\r\n }\r\n " +
" } else {\r\n var deviceProfileExclud" +
"e = getParameterByName(\'deviceProfileExclude\');\r\n if " +
"(deviceProfileExclude) {\r\n filterDeviceProfileExc" +
"lude = {};\r\n var deviceProfileExcludeSplit = devi" +
"ceProfileExclude.split(\",\");\r\n for (var i = 0; i " +
"< deviceProfileExcludeSplit.length; i++) {\r\n " +
"filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;\r\n " +
" }\r\n }\r\n " +
" }\r\n }\r\n }\r\n }\r\n va" +
"r calculateFilter = function (model) {\r\n if (model) {\r\n " +
" if (filterDeviceAddressInclude) {\r\n return (fil" +
"terDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)\r\n " +
" }\r\n if (filterDeviceAddressExclude) {\r\n " +
" return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()" +
"])\r\n }\r\n if (filterDeviceProfileInclude) {" +
"\r\n return (filterDeviceProfileInclude[model.DeviceProfile" +
"Id] == true)\r\n }\r\n if (filterDeviceProfile" +
"Exclude) {\r\n return (!filterDeviceProfileExclude[model.De" +
"viceProfileId])\r\n }\r\n return true;\r\n " +
" }\r\n return false;\r\n }\r\n\r\n var sor" +
"tModels = function () {\r\n modelsInProcessSorted = [];\r\n " +
" modelsReadyForReturnSorted = [];\r\n modelsWaitingForUserActi" +
"onSorted = [];\r\n var modelSortFunc = function (a, b) {\r\n " +
" if (a.DeviceSerialNumber.toUpperCase() == b.DeviceSerialNumber.toUppe" +
"rCase()) {\r\n return 0;\r\n } else {\r\n " +
" if (a.DeviceSerialNumber.toUpperCase() < b.DeviceSerialNumb" +
"er.toUpperCase()) {\r\n return -1\r\n " +
" } else {\r\n return 1\r\n }\r\n " +
" }\r\n };\r\n for (var key in models" +
") {\r\n var model = models[key];\r\n if (model" +
") {\r\n if (model.WaitingForUserAction) {\r\n " +
" modelsWaitingForUserActionSorted.push(model);\r\n " +
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
" modelsReadyForReturnSorted.push(model);\r\n " +
" } else {\r\n modelsInProcessSorted.push(" +
"model);\r\n }\r\n }\r\n " +
" }\r\n }\r\n modelsReadyForReturnSorted = models" +
"ReadyForReturnSorted.sort(modelSortFunc);\r\n modelsInProcessSorted" +
" = modelsInProcessSorted.sort(modelSortFunc);\r\n modelsWaitingForU" +
"serActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);\r\n\r\n " +
" if (modelsInProcessSorted.length != modelsInProcessCount) {\r\n " +
" modelsInProcessCount = modelsInProcessSorted.length;\r\n " +
" $(\'#inProcessCount\').text(\'(\' + modelsInProcessCount + \')\');\r\n " +
" }\r\n if (modelsReadyForReturnSorted.length != modelsReadyForRe" +
"turnCount) {\r\n modelsReadyForReturnCount = modelsReadyForRetu" +
"rnSorted.length;\r\n $(\'#readyForReturnCount\').text(\'(\' + model" +
"sReadyForReturnCount + \')\');\r\n }\r\n if (modelsWaiti" +
"ngForUserActionSorted.length != modelsWaitingForUserActionCount) {\r\n " +
" modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.lengt" +
"h;\r\n $(\'#waitingForUserActionCount\').text(\'(\' + modelsWaiting" +
"ForUserActionCount + \')\');\r\n }\r\n\r\n };\r\n\r\n v" +
"ar scrollReadyForReturn = function () {\r\n $readyForReturnContent." +
"find(\'li\').last().detach().prependTo($readyForReturnContent).hide().slideDown(\'s" +
"low\');\r\n modelsReadyForReturnIndexOffset++;\r\n if (" +
"modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {\r\n " +
" modelsReadyForReturnIndexOffset = 0;\r\n }\r\n " +
" scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scroll" +
"Speed);\r\n };\r\n var updateScrollReadyForReturn = function (" +
") {\r\n var containerHeight = $readyForReturn.find(\'.content\').heig" +
"ht();\r\n var contentHeight = $readyForReturnContent.height();\r\n " +
" if (containerHeight >= contentHeight && scrollReadyForReturnToken) " +
"{\r\n window.clearTimeout(scrollReadyForReturnToken);\r\n " +
" return;\r\n }\r\n if (containerHeight < co" +
"ntentHeight && scrollReadyForReturnToken == null) {\r\n scrollR" +
"eadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);\r\n " +
" }\r\n };\r\n var scrollInProcess = function () {\r\n" +
" $inProcessContent.find(\'li\').last().detach().prependTo($inProces" +
"sContent).hide().slideDown(\'slow\');\r\n modelsInProcessIndexOffset+" +
"+;\r\n if (modelsInProcessIndexOffset >= modelsInProcessSorted.leng" +
"th) {\r\n modelsInProcessIndexOffset = 0;\r\n }\r\n " +
" scrollInProcessToken = window.setTimeout(scrollInProcess, scrollS" +
"peed);\r\n };\r\n var updateScrollInProcess = function () {\r\n " +
" var containerHeight = $inProcess.find(\'.content\').height();\r\n " +
" var contentHeight = $inProcessContent.height();\r\n if " +
"(containerHeight >= contentHeight && scrollInProcessToken) {\r\n " +
" window.clearTimeout(scrollInProcessToken);\r\n return;\r\n " +
" }\r\n if (containerHeight < contentHeight && scrollInPro" +
"cessToken == null) {\r\n scrollInProcessToken = window.setTimeo" +
"ut(scrollInProcess, scrollSpeed);\r\n }\r\n };\r\n " +
" var scrollWaitingForUserAction = function () {\r\n $waitingForUse" +
"rActionContent.find(\'li\').last().detach().prependTo($waitingForUserActionContent" +
").hide().slideDown(\'slow\');\r\n modelsInProcessIndexOffset++;\r\n " +
" if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserAct" +
"ionSorted.length) {\r\n modelsWaitingForUserActionIndexOffset =" +
" 0;\r\n }\r\n scrollWaitingForUserActionToken = window" +
".setTimeout(scrollWaitingForUserAction, scrollSpeed);\r\n };\r\n " +
" var updateScrollWaitingForUserAction = function () {\r\n var con" +
"tainerHeight = $waitingForUserAction.find(\'.content\').height();\r\n " +
" var contentHeight = $waitingForUserActionContent.height();\r\n if " +
"(containerHeight >= contentHeight && scrollWaitingForUserActionToken) {\r\n " +
" window.clearTimeout(scrollWaitingForUserActionToken);\r\n " +
" return;\r\n }\r\n if (containerHeight < conten" +
"tHeight && scrollWaitingForUserActionToken == null) {\r\n scrol" +
"lWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrol" +
"lSpeed);\r\n }\r\n };\r\n\r\n var modelInsertIndex " +
"= function (model) {\r\n sortModels();\r\n var findInd" +
"ex = function (model, array, offset) {\r\n for (var i = 0; i < " +
"array.length; i++) {\r\n if (model.DeviceSerialNumber == ar" +
"ray[i].DeviceSerialNumber) {\r\n var index = i + offset" +
";\r\n if (index > (array.length - 1)) {\r\n " +
" index = index - (array.length - 1);\r\n " +
" }\r\n return index;\r\n }\r\n " +
" };\r\n };\r\n if (model.WaitingForUser" +
"Action) {\r\n return findIndex(model, modelsWaitingForUserActio" +
"nSorted, modelsWaitingForUserActionIndexOffset);\r\n } else {\r\n " +
" if (model.ReadyForReturn) {\r\n return find" +
"Index(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);\r\n " +
" } else {\r\n return findIndex(model, models" +
"InProcessSorted, modelsInProcessIndexOffset);\r\n }\r\n " +
" }\r\n }\r\n var modelInsert = function (model) {\r\n " +
" var index = modelInsertIndex(model);\r\n var insertTo = f" +
"unction (model, host) {\r\n var hostLi = host.children(\'li\');\r\n" +
" if (hostLi.length == 0 || hostLi.length < index) {\r\n " +
" host.append(model.htmlLi);\r\n } else {\r\n " +
" if (index == 0) {\r\n host.prepend(mo" +
"del.htmlLi);\r\n } else {\r\n $(ho" +
"stLi.get(index - 1)).after(model.htmlLi);\r\n }\r\n " +
" }\r\n }\r\n if (model.WaitingForUserAction) " +
"{\r\n insertTo(model, $waitingForUserActionContent);\r\n " +
" window.setTimeout(updateScrollWaitingForUserAction, 100);\r\n " +
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
" insertTo(model, $readyForReturnContent);\r\n windo" +
"w.setTimeout(updateScrollReadyForReturn, 100);\r\n } else {\r\n " +
" insertTo(model, $inProcessContent);\r\n " +
" window.setTimeout(updateScrollInProcess, 100);\r\n }\r\n " +
" }\r\n }\r\n\r\n var removeModel = function (model) {\r\n" +
" if (model) {\r\n model.htmlLi.slideUp(\'fast\', f" +
"unction () {\r\n model.htmlLi.remove();\r\n " +
" });\r\n }\r\n };\r\n\r\n var processModel = funct" +
"ion (id, model, init) {\r\n if (!calculateFilter(model)) {\r\n " +
" removeModel(models[id]);\r\n delete models[id];\r\n " +
" sortModels();\r\n } else {\r\n " +
"var existing = models[id];\r\n models[id] = model;\r\n\r\n " +
" // Add\r\n model.htmlContent = $(\'<div>\').text(model" +
".DeviceDescription);\r\n if (!model.ReadyForReturn && model.Est" +
"imatedReturnTime) {\r\n model.htmlContent.append($(\'<span c" +
"lass=\"small\">\').text(\' (Expected: \' + model.EstimatedReturnTime + \')\'));\r\n " +
" }\r\n if (model.WaitingForUserAction) {\r\n " +
" model.htmlContent.append($(\'<span class=\"small\">\').text(\' (Since" +
" \' + model.WaitingForUserActionSince + \')\'));\r\n } else {\r\n " +
" if (model.ReadyForReturn && model.ReadyForReturnSince) {\r\n " +
" model.htmlContent.append($(\'<span class=\"small\">\').te" +
"xt(\' (Ready \' + model.ReadyForReturnSince + \')\'));\r\n }\r\n " +
" }\r\n\r\n if (existing) {\r\n " +
" if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForU" +
"serAction != model.WaitingForUserAction) {\r\n removeMo" +
"del(existing);\r\n model.htmlLi = $(\'<li>\').html(model." +
"htmlContent).data(\'ModelId\', id).hide();\r\n modelInser" +
"t(model);\r\n if (init) {\r\n " +
" model.htmlLi.fadeIn();\r\n } else {\r\n " +
" model.htmlLi.slideDown();\r\n }\r\n " +
" } else {\r\n model.htmlLi = existin" +
"g.htmlLi;\r\n model.htmlLi.slideUp(\'fast\', function () " +
"{\r\n model.htmlLi.html(model.htmlContent).slideDow" +
"n();\r\n });\r\n }\r\n " +
" } else {\r\n model.htmlLi = $(\'<li>\').html(model.html" +
"Content).data(\'ModelId\', id).hide();\r\n modelInsert(model)" +
";\r\n if (init) {\r\n model.htmlLi" +
".fadeIn();\r\n } else {\r\n model." +
"htmlLi.slideDown(\'slow\');\r\n }\r\n }\r\n " +
" if (model.htmlLi && model.IsAlert) {\r\n m" +
"odel.htmlLi.addClass(\'alert\');\r\n }\r\n }\r\n " +
" };\r\n\r\n var updatedModel = function (id) {\r\n var " +
"deviceSerialNumber = id.toString();\r\n\r\n $.ajax({\r\n " +
" dataType: \'json\',\r\n url: \'");
WriteLiteral(" id=\"item-template\"");
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
"\"text: DeviceDescription\"></span>\r\n <!-- ko if: !ReadyForReturn && Es" +
"timatedReturnTimeUnixEpoc -->\r\n <span class=\"small\">(Expected <span d" +
"ata-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>)</span>\r\n <" +
"!-- /ko -->\r\n <!-- ko if: WaitingForUserAction -->\r\n <span" +
" class=\"small\">(Since <span data-bind=\"livestamp: WaitingForUserActionSinceUnixE" +
"poc\"></span>)</span>\r\n <!-- /ko -->\r\n <!-- ko if: ReadyFor" +
"Return && !WaitingForUserAction -->\r\n <span class=\"small\">(Ready <spa" +
"n data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></span>)</span>\r\n " +
" <!-- /ko -->\r\n </li>\r\n </script>\r\n <script>\r\n ko.bindingHa" +
"ndlers.livestamp = {\r\n init: function (element, valueAccessor, allBin" +
"dings, viewModel, bindingContext) {\r\n var value = valueAccessor()" +
";\r\n var valueUnwrapped = ko.unwrap(value);\r\n\r\n if " +
"(valueUnwrapped)\r\n $(element).livestamp(valueUnwrapped);\r\n " +
" else\r\n $(element).livestamp(\'destroy\');\r\n " +
" }\r\n };\r\n </script>\r\n <script>\r\n $(function () {\r\n " +
" var hub;\r\n var viewModel;\r\n\r\n var rotateSpeed = 3000" +
";\r\n var itemFilters;\r\n\r\n var $inProcessList = $(\'#inProces" +
"s\').find(\'ul\');\r\n var $readyForReturnList = $(\'#readyForReturn\').find" +
"(\'ul\');\r\n var $waitingForUserActionList = $(\'#waitingForUserAction\')." +
"find(\'ul\');\r\n\r\n function noticeboardViewModel(inProcess, readyForRetu" +
"rn, waitingForUserAction) {\r\n var self = this;\r\n\r\n " +
" self.initialized = false;\r\n\r\n self.inProcess = ko.observableArra" +
"y(inProcess);\r\n self.readyForReturn = ko.observableArray(readyFor" +
"Return);\r\n self.waitingForUserAction = ko.observableArray(waiting" +
"ForUserAction);\r\n\r\n self.onRemove = function (element, index, dat" +
"a) {\r\n $(element).slideUp(400, function () {\r\n " +
" $(this).remove();\r\n });\r\n }\r\n " +
" self.onAdd = function (element, index, data) {\r\n if (" +
"self.initialized)\r\n $(element).hide().slideDown(400);\r\n " +
" }\r\n }\r\n\r\n function init() {\r\n " +
" // Connect to Hub\r\n hub = $.connection.noticeboardUpdates;\r\n\r\n " +
" // Map Functions\r\n hub.client.updateHeldDevice = up" +
"dateHeldDevice;\r\n\r\n $.connection.hub.qs = { Noticeboard: \'");
#line 432 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.HeldDevices.HeldDevice()));
#line 127 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Disco.Services.Jobs.Noticeboards.HeldDevices.Name);
#line default
#line hidden
WriteLiteral(@"',
data: { id: deviceSerialNumber },
success: function (data) {
processModel(deviceSerialNumber, data, false);
},
error: function (jqXHR, textStatus, errorThrown) {
if (textStatus == 'parsererror') // null Result
processModel(deviceSerialNumber, null, false);
}
})
};
WriteLiteral(@"' };
$.connection.hub.error(connectionError);
$.connection.hub.disconnected(connectionError);
$.connection.hub.reconnected(connectionError);
var connectionError = function () {
if (persistantConnection) {
persistantConnection.stop();
persistantConnection = null;
window.setTimeout(function () {
window.location.href = '");
// Start Connection
$.connection.hub.start().fail(connectionError).done(loadData);
}
// Called after SignalR is connected
function loadData() {
$.getJSON('");
#line 449 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.HeldDevices.Noticeboard()));
#line 138 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
#line default
#line hidden
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
" var init = function () {\r\n buildFilters();\r\n " +
" persistantConnection = $.connection(\'");
#line 456 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Url.Content("~/Public/HeldDevices/Notifications"));
#line default
#line hidden
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
" persistantConnection.error(connectionError);\r\n persistantConnec" +
"tion.start(function () {\r\n $.getJSON(\'");
#line 460 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
#line default
#line hidden
WriteLiteral(@"', null, function (data) {
for (var i = 0; i < data.length; i++) {
processModel(data[i].DeviceSerialNumber, data[i], true);
}
});
});
};
init();
});
</script>
<div");
WriteLiteral(" id=\"mainFooter\"");
WriteLiteral(">\r\n <img");
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
WriteAttribute("src", Tuple.Create(" src=\"", 22627), Tuple.Create("\"", 22677)
#line 472 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
, Tuple.Create(Tuple.Create("", 22633), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
#line default
#line hidden
, 22633), false)
);
WriteLiteral(" alt=\"Disco Logo\"");
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
" var readyForReturn = [];\r\n var waitingForUserAction" +
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
" return includeItem(heldDeviceItem)\r\n }).forEac" +
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
" readyForReturn.push(heldDeviceItem);\r\n " +
" else if (isInProcess(heldDeviceItem))\r\n inP" +
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
"orUserAction);\r\n\r\n ko.applyBindings(viewModel);\r\n " +
" viewModel.initialized = true;\r\n\r\n $(\'body\').removeCla" +
"ss(\'status-connecting\');\r\n\r\n window.setTimeout(scheduleRotati" +
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
" }\r\n\r\n // Called by SignalR\r\n function updateHeldDevic" +
"e(updates) {\r\n if (viewModel) {\r\n\r\n $.each(upd" +
"ates, function (deviceSerialNumber, heldDeviceItem) {\r\n /" +
"/ Remove Existing\r\n removeItem(deviceSerialNumber);\r\n\r\n " +
" // Add Item\r\n addItem(heldDeviceIte" +
"m);\r\n });\r\n }\r\n }\r\n\r\n fu" +
"nction removeItem(deviceSerialNumber) {\r\n removeItemFromArray(vie" +
"wModel.inProcess, deviceSerialNumber);\r\n removeItemFromArray(view" +
"Model.readyForReturn, deviceSerialNumber);\r\n removeItemFromArray(" +
"viewModel.waitingForUserAction, deviceSerialNumber);\r\n }\r\n\r\n " +
" function addItem(heldDeviceItem) {\r\n if (heldDeviceItem !== nu" +
"ll &&\r\n heldDeviceItem !== undefined &&\r\n " +
"includeItem(heldDeviceItem)) {\r\n\r\n var array;\r\n\r\n " +
" if (isWaitingForUserAction(heldDeviceItem))\r\n arr" +
"ay = viewModel.waitingForUserAction;\r\n else if (isReadyForRet" +
"urn(heldDeviceItem))\r\n array = viewModel.readyForReturn;\r" +
"\n else if (isInProcess(heldDeviceItem))\r\n " +
" array = viewModel.inProcess;\r\n\r\n if (array().length === 0" +
") {\r\n array.push(heldDeviceItem);\r\n } " +
"else {\r\n var index = findSortedInsertIndex(array, heldDev" +
"iceItem);\r\n if (index === -1)\r\n " +
" array.push(heldDeviceItem);\r\n else\r\n " +
" array.splice(index, 0, heldDeviceItem);\r\n }\r\n " +
" }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
" rotateArray(viewModel.inProcess, $inProcessList);\r\n rotateArr" +
"ay(viewModel.readyForReturn, $readyForReturnList);\r\n rotateArray(" +
"viewModel.waitingForUserAction, $waitingForUserActionList);\r\n }\r\n\r\n " +
" function scheduleRotation() {\r\n rotateArrays();\r\n\r\n " +
" window.setTimeout(scheduleRotation, rotateSpeed);\r\n }\r\n\r\n" +
" function includeItem(heldDeviceItem) {\r\n if (itemFilt" +
"ers == null || itemFilters.length == 0)\r\n return true;\r\n\r\n " +
" return itemFilters.reduce(function (previousValue, currentValue, in" +
"dex, array) {\r\n if (previousValue === false)\r\n " +
" return false;\r\n return currentValue(heldDeviceItem);" +
"\r\n }, true);\r\n }\r\n\r\n function buildFilters(" +
") {\r\n var filters = [];\r\n var queryStringParameter" +
"s = getQueryStringParameters();\r\n\r\n if (queryStringParameters !==" +
" null) {\r\n $.each(queryStringParameters, function (key, value" +
") {\r\n switch (key.toLowerCase()) {\r\n " +
" case \'deviceaddressinclude\':\r\n var deviceA" +
"ddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); });\r\n " +
" if (deviceAddresses.length > 0) {\r\n " +
" filters.push(function (heldDeviceItem) {\r\n " +
" // false if DeviceAddressShortName is null\r\n " +
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
" return false;\r\n\r\n " +
" // true if DeviceAddressShortName is included\r\n " +
" return $.inArray(heldDeviceItem.DeviceAddressShortName.toLower" +
"Case(), deviceAddresses) >= 0;\r\n });\r\n " +
" }\r\n break;\r\n " +
" case \'deviceaddressexclude\':\r\n va" +
"r deviceAddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); " +
"});\r\n if (deviceAddresses.length > 0) {\r\n " +
" filters.push(function (heldDeviceItem) {\r\n " +
" // true if DeviceAddressShortName is null\r\n " +
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
" return true;\r\n\r\n " +
" // true if DeviceAddressShortName is excluded\r\n " +
" return $.inArray(heldDeviceItem.DeviceAddressShortName." +
"toLowerCase(), deviceAddresses) < 0;\r\n });\r\n " +
" }\r\n break;\r\n " +
" case \'deviceprofileinclude\':\r\n " +
" var deviceProfiles = value.split(\",\");\r\n if (" +
"deviceProfiles.length > 0) {\r\n filters.push(f" +
"unction (heldDeviceItem) {\r\n // true if D" +
"eviceProfileId is included\r\n return $.inA" +
"rray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;\r\n " +
" });\r\n }\r\n " +
" break;\r\n case \'deviceprofileexclude\':\r\n " +
" var deviceProfiles = value.split(\",\");\r\n " +
" if (deviceProfiles.length > 0) {\r\n " +
" filters.push(function (heldDeviceItem) {\r\n " +
" // true if DeviceProfileId is excluded\r\n " +
" return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;\r" +
"\n });\r\n }\r\n " +
" break;\r\n }\r\n " +
" });\r\n }\r\n\r\n if (filters.length > 0)\r\n " +
" itemFilters = filters;\r\n else\r\n ite" +
"mFilters = null;\r\n }\r\n\r\n function connectionError() {\r\n " +
" try {\r\n $(\'body\').addClass(\'status-error\');\r\n " +
" $.connection.hub.stop();\r\n } catch (e) {\r\n " +
" // Ignore\r\n }\r\n\r\n window.setTimeout(" +
"function () {\r\n window.location.href = window.location.href;\r" +
"\n }, 10000);\r\n }\r\n\r\n // Helpers\r\n " +
" function rotateArray(koArray, element) {\r\n var items = koArray(" +
");\r\n\r\n if (items.length <= 1)\r\n return 0;\r\n\r\n " +
" if (element.height() < (element.parent().height() - 30)) {\r\n\r\n " +
" if (findUnsortedArrayTopIndex(items) !== 0)\r\n " +
" koArray.sort(sortFunction);\r\n\r\n // Don\'t rotate if smal" +
"l & sorted correctly\r\n return;\r\n }\r\n\r\n " +
" // Move Last Item to Top\r\n var item = koArray.pop();\r\n " +
" koArray.unshift(item);\r\n }\r\n function removeI" +
"temFromArray(koArray, deviceSerialNumber) {\r\n var items = koArray" +
"();\r\n for (var i = 0; i < items.length; i++) {\r\n " +
" if (items[i].DeviceSerialNumber == deviceSerialNumber) {\r\n " +
" koArray.splice(i, 1);\r\n items = koArray();\r\n " +
" i--;\r\n }\r\n }\r\n }\r\n " +
" function findUnsortedArrayTopIndex(items) {\r\n // Only " +
"one Item\r\n if (items.length <= 1)\r\n return 0;\r" +
"\n\r\n for (var i = 1; i < items.length; i++) {\r\n " +
" var s = sortFunction(items[i - 1], items[i]);\r\n if (s > 0)\r\n" +
" return i;\r\n }\r\n\r\n return 0" +
";\r\n }\r\n function findSortedInsertIndex(koArray, heldDevice" +
"Item) {\r\n var items = koArray();\r\n var startIndex " +
"= findUnsortedArrayTopIndex(items);\r\n for (var i = startIndex; i " +
"< items.length; i++) {\r\n var s = sortFunction(heldDeviceItem," +
" items[i]);\r\n if (s <= 0)\r\n return i;\r" +
"\n }\r\n if (startIndex !== 0) {\r\n " +
" for (var i = 0; i < startIndex; i++) {\r\n var s = sortFun" +
"ction(heldDeviceItem, items[i]);\r\n if (s <= 0)\r\n " +
" return i;\r\n }\r\n return " +
"startIndex;\r\n } else {\r\n return -1;\r\n " +
" }\r\n }\r\n function sortFunction(l, r) {\r\n " +
" return l.DeviceDescription.toLowerCase() == r.DeviceDescription.toLowerCase(" +
") ? 0 : (l.DeviceDescription.toLowerCase() < r.DeviceDescription.toLowerCase() ?" +
" -1 : 1)\r\n }\r\n function isInProcess(i) {\r\n " +
"return !i.ReadyForReturn && !i.WaitingForUserAction;\r\n }\r\n " +
" function isReadyForReturn(i) {\r\n return i.ReadyForReturn && !i.W" +
"aitingForUserAction;\r\n }\r\n function isWaitingForUserAction" +
"(i) {\r\n return i.WaitingForUserAction;\r\n }\r\n " +
" function getQueryStringParameters() {\r\n\r\n if (window.location.s" +
"earch.length === 0)\r\n return null;\r\n\r\n var par" +
"ams = {};\r\n window.location.search.substr(1).split(\"&\").forEach(f" +
"unction (pair) {\r\n if (pair === \"\") return;\r\n " +
" var parts = pair.split(\"=\");\r\n params[parts[0]] = parts[1" +
"] && decodeURIComponent(parts[1].replace(/\\+/g, \" \"));\r\n });\r\n " +
" return params;\r\n }\r\n\r\n init();\r\n });\r\n" +
" </script>\r\n</body>\r\n</html>");
}
}
@@ -1,4 +1,4 @@
@model IEnumerable<Disco.Web.Areas.Public.Models.UserHeldDevices.UserHeldDeviceModel>
@model IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>
@{
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices for Users", null);
Html.BundleDeferred("~/Style/Public/HeldDevices");
@@ -8,21 +8,19 @@
@{
var DevicesInProcess = Model.Where(i => !i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
}
<h2>
In Process (@DevicesInProcess.Length)</h2>
<h2>In Process (@DevicesInProcess.Length)</h2>
<table class="dataTable">
@foreach (var item in DevicesInProcess)
@foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
{
<tr>
<td class="id">
@item.UserId
@item.UserIdFriendly
</td>
<td class="description">
@item.UserDisplayName@{
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
{
<span class="smallMessage">(Expected: @item.EstimatedReturnTime)</span>
}
@item.UserDisplayName
@if (item.EstimatedReturnTime.HasValue)
{
<span class="smallMessage">(Expected: @CommonHelpers.FriendlyDate(item.EstimatedReturnTime))</span>
}
</td>
</tr>
@@ -33,20 +31,18 @@
@{
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
}
<h2>
Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
<table class="dataTable">
@foreach (var item in WaitingForUserActionJobs)
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
{
<tr>
<td class="id">
@item.UserId
@item.UserIdFriendly
</td>
<td class="description">
@item.UserDisplayName
</td>
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
Since @item.WaitingForUserActionSince
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @CommonHelpers.FriendlyDate(item.WaitingForUserActionSince)
</td>
</tr>
}
@@ -55,20 +51,18 @@
@{
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
}
<h2>
Ready for Return (@DevicesReadyForReturn.Length)</h2>
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
<table class="dataTable">
@foreach (var item in DevicesReadyForReturn)
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
{
<tr>
<td class="id">
@item.UserId
@item.UserIdFriendly
</td>
<td class="description">
@item.UserDisplayName
</td>
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
Ready @item.ReadyForReturnSince
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @CommonHelpers.FriendlyDate(item.ReadyForReturnSince)
</td>
</tr>
}
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -36,7 +36,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/UserHeldDevices/Index.cshtml")]
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Web.Areas.Public.Models.UserHeldDevices.UserHeldDeviceModel>>
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>>
{
public Index()
{
@@ -76,10 +76,10 @@ WriteLiteral(">\r\n");
#line default
#line hidden
WriteLiteral("\r\n <h2>\r\n In Process (");
WriteLiteral("\r\n <h2>In Process (");
#line 12 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 11 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(DevicesInProcess.Length);
@@ -92,14 +92,14 @@ WriteLiteral(" class=\"dataTable\"");
WriteLiteral(">\r\n");
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line default
#line hidden
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in DevicesInProcess)
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
{
@@ -114,8 +114,8 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 18 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserId);
#line 17 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserIdFriendly);
#line default
@@ -129,17 +129,24 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 20 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserDisplayName);
#line default
#line hidden
WriteLiteral("\r\n");
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
{
#line default
#line hidden
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
if (item.EstimatedReturnTime.HasValue)
{
#line default
@@ -151,8 +158,8 @@ WriteLiteral(" class=\"smallMessage\"");
WriteLiteral(">(Expected: ");
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.EstimatedReturnTime);
#line 23 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
#line default
@@ -160,16 +167,16 @@ WriteLiteral(">(Expected: ");
WriteLiteral(")</span>\r\n");
#line 25 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
}
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
WriteLiteral(" </td>\r\n </tr>\r\n");
#line 29 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 27 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
}
@@ -182,23 +189,23 @@ WriteLiteral(" class=\"column2\"");
WriteLiteral(">\r\n");
#line 33 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 31 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line default
#line hidden
#line 33 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 31 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
#line default
#line hidden
WriteLiteral("\r\n <h2>\r\n Waiting for User Action (");
WriteLiteral("\r\n <h2>Waiting for User Action (");
#line 37 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 34 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(WaitingForUserActionJobs.Length);
@@ -211,14 +218,14 @@ WriteLiteral(" class=\"dataTable\"");
WriteLiteral(">\r\n");
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line default
#line hidden
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in WaitingForUserActionJobs)
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
{
@@ -233,8 +240,8 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserId);
#line 40 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserIdFriendly);
#line default
@@ -248,7 +255,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 46 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserDisplayName);
@@ -256,22 +263,22 @@ WriteLiteral(" ");
#line hidden
WriteLiteral("\r\n </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 1795), Tuple.Create("\"", 1853)
, Tuple.Create(Tuple.Create("", 1803), Tuple.Create("timestamp", 1803), true)
WriteAttribute("class", Tuple.Create(" class=\"", 1845), Tuple.Create("\"", 1903)
, Tuple.Create(Tuple.Create("", 1853), Tuple.Create("timestamp", 1853), true)
#line 48 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 1812), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 1862), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line default
#line hidden
, 1812), false)
, 1862), false)
);
WriteLiteral(">\r\n Since ");
WriteLiteral(">Since ");
#line 49 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.WaitingForUserActionSince);
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
#line default
@@ -279,7 +286,7 @@ WriteLiteral(">\r\n Since ");
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
#line 52 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 48 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
}
@@ -288,23 +295,23 @@ WriteLiteral("\r\n </td>\r\n </tr>\r\n");
WriteLiteral(" </table>\r\n <hr />\r\n");
#line 55 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 51 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line default
#line hidden
#line 55 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 51 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
#line default
#line hidden
WriteLiteral("\r\n <h2>\r\n Ready for Return (");
WriteLiteral("\r\n <h2>Ready for Return (");
#line 59 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 54 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(DevicesReadyForReturn.Length);
@@ -317,14 +324,14 @@ WriteLiteral(" class=\"dataTable\"");
WriteLiteral(">\r\n");
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line default
#line hidden
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in DevicesReadyForReturn)
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
{
@@ -339,8 +346,8 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserId);
#line 60 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserIdFriendly);
#line default
@@ -354,7 +361,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 68 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 63 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.UserDisplayName);
@@ -362,22 +369,22 @@ WriteLiteral(" ");
#line hidden
WriteLiteral("\r\n </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 2612), Tuple.Create("\"", 2670)
, Tuple.Create(Tuple.Create("", 2620), Tuple.Create("timestamp", 2620), true)
WriteAttribute("class", Tuple.Create(" class=\"", 2689), Tuple.Create("\"", 2747)
, Tuple.Create(Tuple.Create("", 2697), Tuple.Create("timestamp", 2697), true)
#line 70 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 2629), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
, Tuple.Create(Tuple.Create("", 2706), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
#line default
#line hidden
, 2629), false)
, 2706), false)
);
WriteLiteral(">\r\n Ready ");
WriteLiteral(">Ready ");
#line 71 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(item.ReadyForReturnSince);
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
#line default
@@ -385,7 +392,7 @@ WriteLiteral(">\r\n Ready ");
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
#line 74 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
#line 68 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
}
@@ -1,5 +1,6 @@
@{
Layout = null;
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/ClientScripts/Core");
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
@@ -9,471 +10,397 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Disco - Technician Held Devices for Users</title>
<title>Disco ICT - Held Devices for Users</title>
@Html.BundleRenderDeferred()
</head>
<body>
<body class="status-connecting">
<div id="page">
<header id="mainHeader">
Technician Held Devices for Users
</header>
<header id="header">
<div id="heading">Held Devices for Users</div>
<div id="statusConnecting"><i class="fa fa-cog fa-spin"></i><span>connecting...</span></div>
<div id="statusError"><i class="fa fa-cog fa-spin"></i><span>disconnected, reconnecting...</span></div>
<div id="credits">
powered by Disco ICT <i title="Disco ICT - Jobs"></i>
</div>
</header>
<section id="mainSection">
<div id="inProcess" class="list">
<h3>
In Process <span id="inProcessCount"></span>
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: inProcess().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<div id="readyForReturn" class="list">
<h3>
Ready for Return <span id="readyForReturnCount"></span>
<h3>Ready for Return (<span data-bind="text: readyForReturn().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: readyForReturn().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<div id="waitingForUserAction" class="list">
<h3>
Waiting for User Action <span id="waitingForUserActionCount"></span>
<h3>Waiting for User Action (<span data-bind="text: waitingForUserAction().length"></span>)
</h3>
<div class="content">
<ul>
</ul>
<!-- ko if: waitingForUserAction().length == 0 -->
<div class="noContent">&lt;None&gt;</div>
<!-- /ko -->
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
</div>
</div>
<footer id="footer">
</footer>
</section>
<footer>
</footer>
</div>
<script type="text/javascript">
// Resizing
$(function () {
var $inProcess = $('#inProcess');
var $inProcessContent = $inProcess.find('.content');
var $inProcessHeader = $inProcess.find('.h3');
var $readyForReturn = $('#readyForReturn');
var $readyForReturnContent = $readyForReturn.find('.content');
var $readyForReturnHeader = $readyForReturn.find('.h3');
var $waitingForUserAction = $('#waitingForUserAction');
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
var $mainSection = $('#mainSection');
var $mainHeader = $('#mainHeader');
var $mainFooter = $('#mainFooter');
var onResize = function () {
var width = $mainSection.width();
var height = $(window).height() - $mainHeader.outerHeight() - $mainFooter.outerHeight() - 25;
$inProcess.height(height);
$inProcess.width((width * .28) - 11);
$inProcessContent.height(height - $inProcessHeader.outerHeight() - 56);
$readyForReturn.height(height);
$readyForReturn.width((width * .36) - 11);
$readyForReturnContent.height(height - $readyForReturnHeader.outerHeight() - 56);
$waitingForUserAction.height(height);
$waitingForUserAction.width((width * .36) - 11);
$waitingForUserActionContent.height(height - $waitingForUserActionHeader.outerHeight() - 56);
};
$(window).resize(onResize);
onResize();
});
<script type="text/html" id="item-template">
<li data-bind="css: { alert: IsAlert }">
<span data-bind="text: UserIdFriendly + ' - ' + UserDisplayName"></span>
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
<!-- /ko -->
<!-- ko if: WaitingForUserAction -->
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
<!-- /ko -->
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
<!-- /ko -->
</li>
</script>
<script type="text/javascript">
// Hide Mouse Mouse
$(function () {
var mouseVisible = true;
var mouseHideToken;
var documentBody = $('body');
<script>
ko.bindingHandlers.livestamp = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
var hideMouse = function () {
if (mouseVisible) {
documentBody.css('cursor', 'none');
mouseVisible = false;
}
};
var showMouse = function () {
if (!mouseVisible) {
documentBody.css('cursor', 'auto');
mouseVisible = true;
}
};
$(document).mousemove(function () {
showMouse();
if (mouseHideToken)
window.clearTimeout(mouseHideToken);
mouseHideToken = window.setTimeout(hideMouse, 2000);
});
});
</script>
<script type="text/javascript">
$(function () {
var models = {};
var modelsInProcessSorted = [];
var modelsInProcessCount = 0;
var modelsReadyForReturnSorted = [];
var modelsReadyForReturnCount = 0;
var modelsWaitingForUserActionSorted = [];
var modelsWaitingForUserActionCount = 0;
var $inProcess = $('#inProcess');
var $inProcessContent = $inProcess.find('.content ul');
var $readyForReturn = $('#readyForReturn');
var $readyForReturnContent = $readyForReturn.find('.content ul');
var $waitingForUserAction = $('#waitingForUserAction');
var $waitingForUserActionContent = $waitingForUserAction.find('.content ul');
var modelsInProcessIndexOffset = 0;
var scrollInProcessToken = null;
var modelsReadyForReturnIndexOffset = 0;
var scrollReadyForReturnToken = null;
var modelsWaitingForUserActionIndexOffset = 0;
var scrollWaitingForUserActionToken = null;
var scrollSpeed = 3000;
var persistantConnection = null;
var filterDeviceAddressInclude;
var filterDeviceAddressExclude;
var filterDeviceProfileInclude;
var filterDeviceProfileExclude;
var getParameterByName = function (name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if (results == null)
return "";
if (valueUnwrapped)
$(element).livestamp(valueUnwrapped);
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
$(element).livestamp('destroy');
}
};
</script>
<script>
$(function () {
var hub;
var viewModel;
var buildFilters = function () {
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
if (deviceAddressInclude) {
filterDeviceAddressInclude = {};
var split = deviceAddressInclude.split(",");
for (var i = 0; i < split.length; i++) {
filterDeviceAddressInclude[split[i].toLowerCase()] = true;
}
} else {
var deviceAddressExclude = getParameterByName('deviceAddressExclude');
if (deviceAddressExclude) {
filterDeviceAddressExclude = {};
var split = deviceAddressExclude.split(",");
for (var i = 0; i < split.length; i++) {
filterDeviceAddressExclude[split[i].toLowerCase()] = true;
}
} else {
var deviceProfileInclude = getParameterByName('deviceProfileInclude');
if (deviceProfileInclude) {
filterDeviceProfileInclude = {};
var deviceProfileIncludeSplit = deviceProfileInclude.split(",");
for (var i = 0; i < deviceProfileIncludeSplit.length; i++) {
filterDeviceProfileInclude[parseInt(deviceProfileIncludeSplit[i])] = true;
}
} else {
var deviceProfileExclude = getParameterByName('deviceProfileExclude');
if (deviceProfileExclude) {
filterDeviceProfileExclude = {};
var deviceProfileExcludeSplit = deviceProfileExclude.split(",");
for (var i = 0; i < deviceProfileExcludeSplit.length; i++) {
filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;
}
}
}
}
}
}
var calculateFilter = function (model) {
if (model) {
if (filterDeviceAddressInclude) {
return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)
}
if (filterDeviceAddressExclude) {
return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()])
}
if (filterDeviceProfileInclude) {
return (filterDeviceProfileInclude[model.DeviceProfileId] == true)
}
if (filterDeviceProfileExclude) {
return (!filterDeviceProfileExclude[model.DeviceProfileId])
}
return true;
}
return false;
}
var rotateSpeed = 3000;
var itemFilters;
var sortModels = function () {
modelsInProcessSorted = [];
modelsReadyForReturnSorted = [];
modelsWaitingForUserActionSorted = [];
var modelSortFunc = function (a, b) {
if (a.UserId.toUpperCase() == b.UserId.toUpperCase()) {
return 0;
} else {
if (a.UserId.toUpperCase() < b.UserId.toUpperCase()) {
return -1
} else {
return 1
}
}
};
for (var key in models) {
var model = models[key];
if (model) {
if (model.WaitingForUserAction) {
modelsWaitingForUserActionSorted.push(model);
} else {
if (model.ReadyForReturn) {
modelsReadyForReturnSorted.push(model);
} else {
modelsInProcessSorted.push(model);
}
}
}
}
modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortFunc);
modelsInProcessSorted = modelsInProcessSorted.sort(modelSortFunc);
modelsWaitingForUserActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);
var $inProcessList = $('#inProcess').find('ul');
var $readyForReturnList = $('#readyForReturn').find('ul');
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
if (modelsInProcessSorted.length != modelsInProcessCount) {
modelsInProcessCount = modelsInProcessSorted.length;
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
}
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
}
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
}
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
var self = this;
};
self.initialized = false;
var scrollReadyForReturn = function () {
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
modelsReadyForReturnIndexOffset++;
if (modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {
modelsReadyForReturnIndexOffset = 0;
}
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
};
var updateScrollReadyForReturn = function () {
var containerHeight = $readyForReturn.find('.content').height();
var contentHeight = $readyForReturnContent.height();
if (containerHeight >= contentHeight && scrollReadyForReturnToken) {
window.clearTimeout(scrollReadyForReturnToken);
return;
}
if (containerHeight < contentHeight && scrollReadyForReturnToken == null) {
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
}
};
var scrollInProcess = function () {
$inProcessContent.find('li').last().detach().prependTo($inProcessContent).hide().slideDown('slow');
modelsInProcessIndexOffset++;
if (modelsInProcessIndexOffset >= modelsInProcessSorted.length) {
modelsInProcessIndexOffset = 0;
}
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
};
var updateScrollInProcess = function () {
var containerHeight = $inProcess.find('.content').height();
var contentHeight = $inProcessContent.height();
if (containerHeight >= contentHeight && scrollInProcessToken) {
window.clearTimeout(scrollInProcessToken);
return;
}
if (containerHeight < contentHeight && scrollInProcessToken == null) {
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
}
};
var scrollWaitingForUserAction = function () {
$waitingForUserActionContent.find('li').last().detach().prependTo($waitingForUserActionContent).hide().slideDown('slow');
modelsInProcessIndexOffset++;
if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserActionSorted.length) {
modelsWaitingForUserActionIndexOffset = 0;
}
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
};
var updateScrollWaitingForUserAction = function () {
var containerHeight = $waitingForUserAction.find('.content').height();
var contentHeight = $waitingForUserActionContent.height();
if (containerHeight >= contentHeight && scrollWaitingForUserActionToken) {
window.clearTimeout(scrollWaitingForUserActionToken);
return;
}
if (containerHeight < contentHeight && scrollWaitingForUserActionToken == null) {
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
}
};
self.inProcess = ko.observableArray(inProcess);
self.readyForReturn = ko.observableArray(readyForReturn);
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
var modelInsertIndex = function (model) {
sortModels();
var findIndex = function (model, array, offset) {
for (var i = 0; i < array.length; i++) {
if (model.UserId == array[i].UserId) {
var index = i + offset;
if (index > (array.length - 1)) {
index = index - (array.length - 1);
}
return index;
}
};
};
if (model.WaitingForUserAction) {
return findIndex(model, modelsWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);
} else {
if (model.ReadyForReturn) {
return findIndex(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);
} else {
return findIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);
}
}
}
var modelInsert = function (model) {
var index = modelInsertIndex(model);
var insertTo = function (model, host) {
var hostLi = host.children('li');
if (hostLi.length == 0 || hostLi.length < index) {
host.append(model.htmlLi);
} else {
if (index == 0) {
host.prepend(model.htmlLi);
} else {
$(hostLi.get(index - 1)).after(model.htmlLi);
}
}
}
if (model.WaitingForUserAction) {
insertTo(model, $waitingForUserActionContent);
window.setTimeout(updateScrollWaitingForUserAction, 100);
} else {
if (model.ReadyForReturn) {
insertTo(model, $readyForReturnContent);
window.setTimeout(updateScrollReadyForReturn, 100);
} else {
insertTo(model, $inProcessContent);
window.setTimeout(updateScrollInProcess, 100);
}
}
}
var removeModel = function (model) {
if (model) {
model.htmlLi.slideUp('fast', function () {
model.htmlLi.remove();
self.onRemove = function (element, index, data) {
$(element).slideUp(400, function () {
$(this).remove();
});
}
};
var processModel = function (id, model, init) {
if (!calculateFilter(model)) {
removeModel(models[id]);
delete models[id];
sortModels();
} else {
var existing = models[id];
models[id] = model;
// Add
model.htmlContent = $('<div>').text(model.UserId + ' - ' + model.UserDisplayName);
if (!model.ReadyForReturn && model.EstimatedReturnTime) {
model.htmlContent.append($('<span class="small">').text(' (Expected: ' + model.EstimatedReturnTime + ')'));
}
if (model.WaitingForUserAction) {
model.htmlContent.append($('<span class="small">').text(' (Since ' + model.WaitingForUserActionSince + ')'));
} else {
if (model.ReadyForReturn && model.ReadyForReturnSince) {
model.htmlContent.append($('<span class="small">').text(' (Ready ' + model.ReadyForReturnSince + ')'));
}
}
if (existing) {
if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction) {
removeModel(existing);
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
modelInsert(model);
if (init) {
model.htmlLi.fadeIn();
} else {
model.htmlLi.slideDown();
}
} else {
model.htmlLi = existing.htmlLi;
model.htmlLi.slideUp('fast', function () {
model.htmlLi.html(model.htmlContent).slideDown();
});
}
} else {
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
modelInsert(model);
if (init) {
model.htmlLi.fadeIn();
} else {
model.htmlLi.slideDown('slow');
}
}
if (model.htmlLi && model.IsAlert) {
model.htmlLi.addClass('alert');
}
}
};
var updatedModel = function (id) {
var userId = id.toString();
$.ajax({
dataType: 'json',
url: '@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevice()))',
data: { id: userId },
success: function (data) {
processModel(userId, data, false);
},
error: function(jqXHR, textStatus, errorThrown){
if (textStatus == 'parsererror') // null Result
processModel(userId, null, false);
}
})
};
var connectionError = function () {
if (persistantConnection) {
persistantConnection.stop();
persistantConnection = null;
window.setTimeout(function () {
window.location.href = '@(Url.Action(MVC.Public.UserHeldDevices.Noticeboard()))';
}, 10000);
self.onAdd = function (element, index, data) {
if (self.initialized)
$(element).hide().slideDown(400);
}
}
var init = function () {
buildFilters();
persistantConnection = $.connection('@(Url.Content("~/Public/UserHeldDevices/Notifications"))');
persistantConnection.received(updatedModel);
persistantConnection.error(connectionError);
persistantConnection.start(function () {
$.getJSON('@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()))', null, function (data) {
for (var i = 0; i < data.length; i++) {
processModel(data[i].UserId, data[i], true);
}
function init() {
// Connect to Hub
hub = $.connection.noticeboardUpdates;
// Map Functions
hub.client.updateHeldDeviceForUser = updateHeldDevice;
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name)' };
$.connection.hub.error(connectionError);
$.connection.hub.disconnected(connectionError);
$.connection.hub.reconnected(connectionError);
// Start Connection
$.connection.hub.start().fail(connectionError).done(loadData);
}
// Called after SignalR is connected
function loadData() {
$.getJSON('@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()))', null, function (data) {
var inProcess = [];
var readyForReturn = [];
var waitingForUserAction = [];
data.filter(function (heldDeviceItem) {
return includeItem(heldDeviceItem)
}).forEach(function (heldDeviceItem) {
if (isWaitingForUserAction(heldDeviceItem))
waitingForUserAction.push(heldDeviceItem);
else if (isReadyForReturn(heldDeviceItem))
readyForReturn.push(heldDeviceItem);
else if (isInProcess(heldDeviceItem))
inProcess.push(heldDeviceItem);
});
inProcess.sort(sortFunction);
readyForReturn.sort(sortFunction);
waitingForUserAction.sort(sortFunction);
viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction);
ko.applyBindings(viewModel);
viewModel.initialized = true;
$('body').removeClass('status-connecting');
window.setTimeout(scheduleRotation, rotateSpeed);
});
};
init();
buildFilters();
}
// Called by SignalR
function updateHeldDevice(updates) {
if (viewModel) {
$.each(updates, function (UserId, heldDeviceItem) {
// Remove Existing
removeItem(UserId);
// Add Item
addItem(heldDeviceItem);
});
}
}
function removeItem(UserId) {
removeItemFromArray(viewModel.inProcess, UserId);
removeItemFromArray(viewModel.readyForReturn, UserId);
removeItemFromArray(viewModel.waitingForUserAction, UserId);
}
function addItem(heldDeviceItem) {
if (heldDeviceItem !== null &&
heldDeviceItem !== undefined &&
includeItem(heldDeviceItem)) {
var array;
if (isWaitingForUserAction(heldDeviceItem))
array = viewModel.waitingForUserAction;
else if (isReadyForReturn(heldDeviceItem))
array = viewModel.readyForReturn;
else if (isInProcess(heldDeviceItem))
array = viewModel.inProcess;
if (array().length === 0) {
array.push(heldDeviceItem);
} else {
var index = findSortedInsertIndex(array, heldDeviceItem);
if (index === -1)
array.push(heldDeviceItem);
else
array.splice(index, 0, heldDeviceItem);
}
}
}
function rotateArrays() {
rotateArray(viewModel.inProcess, $inProcessList);
rotateArray(viewModel.readyForReturn, $readyForReturnList);
rotateArray(viewModel.waitingForUserAction, $waitingForUserActionList);
}
function scheduleRotation() {
rotateArrays();
window.setTimeout(scheduleRotation, rotateSpeed);
}
function includeItem(heldDeviceItem) {
if (itemFilters == null || itemFilters.length == 0)
return true;
return itemFilters.reduce(function (previousValue, currentValue, index, array) {
if (previousValue === false)
return false;
return currentValue(heldDeviceItem);
}, true);
}
function buildFilters() {
var filters = [];
var queryStringParameters = getQueryStringParameters();
if (queryStringParameters !== null) {
$.each(queryStringParameters, function (key, value) {
switch (key.toLowerCase()) {
case 'deviceaddressinclude':
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
if (deviceAddresses.length > 0) {
filters.push(function (heldDeviceItem) {
// false if DeviceAddressShortName is null
if (!heldDeviceItem.DeviceAddressShortName)
return false;
// true if DeviceAddressShortName is included
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) >= 0;
});
}
break;
case 'deviceaddressexclude':
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
if (deviceAddresses.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceAddressShortName is null
if (!heldDeviceItem.DeviceAddressShortName)
return true;
// true if DeviceAddressShortName is excluded
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) < 0;
});
}
break;
case 'deviceprofileinclude':
var deviceProfiles = value.split(",");
if (deviceProfiles.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceProfileId is included
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;
});
}
break;
case 'deviceprofileexclude':
var deviceProfiles = value.split(",");
if (deviceProfiles.length > 0) {
filters.push(function (heldDeviceItem) {
// true if DeviceProfileId is excluded
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;
});
}
break;
}
});
}
if (filters.length > 0)
itemFilters = filters;
else
itemFilters = null;
}
function connectionError() {
try {
$('body').addClass('status-error');
$.connection.hub.stop();
} catch (e) {
// Ignore
}
window.setTimeout(function () {
window.location.href = window.location.href;
}, 10000);
}
// Helpers
function rotateArray(koArray, element) {
var items = koArray();
if (items.length <= 1)
return 0;
if (element.height() < (element.parent().height() - 30)) {
if (findUnsortedArrayTopIndex(items) !== 0)
koArray.sort(sortFunction);
// Don't rotate if small & sorted correctly
return;
}
// Move Last Item to Top
var item = koArray.pop();
koArray.unshift(item);
}
function removeItemFromArray(koArray, UserId) {
var items = koArray();
for (var i = 0; i < items.length; i++) {
if (items[i].UserId == UserId) {
koArray.splice(i, 1);
items = koArray();
i--;
}
}
}
function findUnsortedArrayTopIndex(items) {
// Only one Item
if (items.length <= 1)
return 0;
for (var i = 1; i < items.length; i++) {
var s = sortFunction(items[i - 1], items[i]);
if (s > 0)
return i;
}
return 0;
}
function findSortedInsertIndex(koArray, heldDeviceItem) {
var items = koArray();
var startIndex = findUnsortedArrayTopIndex(items);
for (var i = startIndex; i < items.length; i++) {
var s = sortFunction(heldDeviceItem, items[i]);
if (s <= 0)
return i;
}
if (startIndex !== 0) {
for (var i = 0; i < startIndex; i++) {
var s = sortFunction(heldDeviceItem, items[i]);
if (s <= 0)
return i;
}
return startIndex;
} else {
return -1;
}
}
function sortFunction(l, r) {
return l.UserIdFriendly.toLowerCase() == r.UserIdFriendly.toLowerCase() ? 0 : (l.UserIdFriendly.toLowerCase() < r.UserIdFriendly.toLowerCase() ? -1 : 1)
}
function isInProcess(i) {
return !i.ReadyForReturn && !i.WaitingForUserAction;
}
function isReadyForReturn(i) {
return i.ReadyForReturn && !i.WaitingForUserAction;
}
function isWaitingForUserAction(i) {
return i.WaitingForUserAction;
}
function getQueryStringParameters() {
if (window.location.search.length === 0)
return null;
var params = {};
window.location.search.substr(1).split("&").forEach(function (pair) {
if (pair === "") return;
var parts = pair.split("=");
params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace(/\+/g, " "));
});
return params;
}
init();
});
</script>
<div id="mainFooter">
<img style="width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;" src="@Links.ClientSource.Style.Images.Heading_png" alt="Disco Logo" />
powered by Disco
</div>
</body>
</html>
</html>
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices
#line 1 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Layout = null;
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
Html.BundleDeferred("~/ClientScripts/Core");
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
WriteLiteral(" content=\"IE=edge\"");
WriteLiteral(" />\r\n <title>Disco - Technician Held Devices for Users</title>\r\n");
WriteLiteral(" />\r\n <title>Disco ICT - Held Devices for Users</title>\r\n");
WriteLiteral(" ");
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Html.BundleRenderDeferred());
#line default
#line hidden
WriteLiteral("\r\n</head>\r\n<body>\r\n <div");
WriteLiteral("\r\n</head>\r\n<body");
WriteLiteral(" class=\"status-connecting\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"page\"");
WriteLiteral(">\r\n <header");
WriteLiteral(" id=\"mainHeader\"");
WriteLiteral(" id=\"header\"");
WriteLiteral(">\r\n Technician Held Devices for Users\r\n </header>\r\n <section");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"heading\"");
WriteLiteral(">Held Devices for Users</div>\r\n <div");
WriteLiteral(" id=\"statusConnecting\"");
WriteLiteral("><i");
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
WriteLiteral("></i><span>connecting...</span></div>\r\n <div");
WriteLiteral(" id=\"statusError\"");
WriteLiteral("><i");
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
WriteLiteral("></i><span>disconnected, reconnecting...</span></div>\r\n <div");
WriteLiteral(" id=\"credits\"");
WriteLiteral(">\r\n powered by Disco ICT <i");
WriteLiteral(" title=\"Disco ICT - Jobs\"");
WriteLiteral("></i>\r\n </div>\r\n </header>\r\n <section");
WriteLiteral(" id=\"mainSection\"");
@@ -93,402 +126,288 @@ WriteLiteral(" id=\"inProcess\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>\r\n In Process <span");
WriteLiteral(">\r\n <h3>In Process (<span");
WriteLiteral(" id=\"inProcessCount\"");
WriteLiteral(" data-bind=\"text: inProcess().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n <div");
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
" <div");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: inProcess, afterRender: o" +
"nAdd, beforeRemove: onRemove }\"");
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
WriteLiteral(" id=\"readyForReturn\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>\r\n Ready for Return <span");
WriteLiteral(">\r\n <h3>Ready for Return (<span");
WriteLiteral(" id=\"readyForReturnCount\"");
WriteLiteral(" data-bind=\"text: readyForReturn().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n <div");
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
" <div");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: readyForReturn, afterRend" +
"er: onAdd, beforeRemove: onRemove }\"");
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
WriteLiteral(" id=\"waitingForUserAction\"");
WriteLiteral(" class=\"list\"");
WriteLiteral(">\r\n <h3>\r\n Waiting for User Action <span");
WriteLiteral(">\r\n <h3>Waiting for User Action (<span");
WriteLiteral(" id=\"waitingForUserActionCount\"");
WriteLiteral(" data-bind=\"text: waitingForUserAction().length\"");
WriteLiteral("></span>\r\n </h3>\r\n <div");
WriteLiteral("></span>)\r\n </h3>\r\n <div");
WriteLiteral(" class=\"content\"");
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
"</div>\r\n <script");
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
" <div");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" class=\"noContent\"");
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
"#inProcess\');\r\n var $inProcessContent = $inProcess.find(\'.content\');\r" +
"\n var $inProcessHeader = $inProcess.find(\'.h3\');\r\n var $re" +
"adyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnContent = $" +
"readyForReturn.find(\'.content\');\r\n var $readyForReturnHeader = $ready" +
"ForReturn.find(\'.h3\');\r\n var $waitingForUserAction = $(\'#waitingForUs" +
"erAction\');\r\n var $waitingForUserActionContent = $waitingForUserActio" +
"n.find(\'.content\');\r\n var $waitingForUserActionHeader = $waitingForUs" +
"erAction.find(\'.h3\');\r\n var $mainSection = $(\'#mainSection\');\r\n " +
" var $mainHeader = $(\'#mainHeader\');\r\n var $mainFooter = $(\'#mai" +
"nFooter\');\r\n\r\n var onResize = function () {\r\n var widt" +
"h = $mainSection.width();\r\n var height = $(window).height() - $ma" +
"inHeader.outerHeight() - $mainFooter.outerHeight() - 25;\r\n\r\n $inP" +
"rocess.height(height);\r\n $inProcess.width((width * .28) - 11);\r\n " +
" $inProcessContent.height(height - $inProcessHeader.outerHeight() " +
"- 56);\r\n\r\n $readyForReturn.height(height);\r\n $read" +
"yForReturn.width((width * .36) - 11);\r\n $readyForReturnContent.he" +
"ight(height - $readyForReturnHeader.outerHeight() - 56);\r\n\r\n $wai" +
"tingForUserAction.height(height);\r\n $waitingForUserAction.width((" +
"width * .36) - 11);\r\n $waitingForUserActionContent.height(height " +
"- $waitingForUserActionHeader.outerHeight() - 56);\r\n };\r\n\r\n " +
" $(window).resize(onResize);\r\n onResize();\r\n });\r\n </scrip" +
"t>\r\n <script");
WriteLiteral(">&lt;None&gt;</div>\r\n <!-- /ko -->\r\n <ul");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
"erAdd: onAdd, beforeRemove: onRemove }\"");
WriteLiteral(@">
// Hide Mouse Mouse
$(function () {
var mouseVisible = true;
var mouseHideToken;
var documentBody = $('body');
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
var hideMouse = function () {
if (mouseVisible) {
documentBody.css('cursor', 'none');
mouseVisible = false;
}
};
var showMouse = function () {
if (!mouseVisible) {
documentBody.css('cursor', 'auto');
mouseVisible = true;
}
};
WriteLiteral(" id=\"footer\"");
$(document).mousemove(function () {
showMouse();
if (mouseHideToken)
window.clearTimeout(mouseHideToken);
mouseHideToken = window.setTimeout(hideMouse, 2000);
});
});
</script>
<script");
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" type=\"text/html\"");
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
" var persistantConnection = null;\r\n var filterDeviceAddress" +
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n \r\n " +
" var getParameterByName = function (name) {\r\n name = na" +
"me.replace(/[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS " +
"= \"[\\\\?&]\" + name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS)" +
";\r\n var results = regex.exec(window.location.search);\r\n " +
" if (results == null)\r\n return \"\";\r\n else" +
"\r\n return decodeURIComponent(results[1].replace(/\\+/g, \" \"));" +
"\r\n }\r\n\r\n var buildFilters = function () {\r\n " +
" var deviceAddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n " +
" if (deviceAddressInclude) {\r\n filterDeviceAddressInc" +
"lude = {};\r\n var split = deviceAddressInclude.split(\",\");\r\n " +
" for (var i = 0; i < split.length; i++) {\r\n " +
" filterDeviceAddressInclude[split[i].toLowerCase()] = true;\r\n " +
" }\r\n } else {\r\n var deviceAddressExclude = " +
"getParameterByName(\'deviceAddressExclude\');\r\n if (deviceAddre" +
"ssExclude) {\r\n filterDeviceAddressExclude = {};\r\n " +
" var split = deviceAddressExclude.split(\",\");\r\n " +
" for (var i = 0; i < split.length; i++) {\r\n filt" +
"erDeviceAddressExclude[split[i].toLowerCase()] = true;\r\n " +
"}\r\n } else {\r\n var deviceProfileInclud" +
"e = getParameterByName(\'deviceProfileInclude\');\r\n if (dev" +
"iceProfileInclude) {\r\n filterDeviceProfileInclude = {" +
"};\r\n var deviceProfileIncludeSplit = deviceProfileInc" +
"lude.split(\",\");\r\n for (var i = 0; i < deviceProfileI" +
"ncludeSplit.length; i++) {\r\n filterDeviceProfileI" +
"nclude[parseInt(deviceProfileIncludeSplit[i])] = true;\r\n " +
" }\r\n } else {\r\n var deviceP" +
"rofileExclude = getParameterByName(\'deviceProfileExclude\');\r\n " +
" if (deviceProfileExclude) {\r\n filterDevi" +
"ceProfileExclude = {};\r\n var deviceProfileExclude" +
"Split = deviceProfileExclude.split(\",\");\r\n for (v" +
"ar i = 0; i < deviceProfileExcludeSplit.length; i++) {\r\n " +
" filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] =" +
" true;\r\n }\r\n }\r\n " +
" }\r\n }\r\n }\r\n }\r\n " +
" var calculateFilter = function (model) {\r\n if (model) {" +
"\r\n if (filterDeviceAddressInclude) {\r\n " +
" return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)\r" +
"\n }\r\n if (filterDeviceAddressExclude) {\r\n " +
" return (!filterDeviceAddressExclude[model.DeviceAddress.t" +
"oLowerCase()])\r\n }\r\n if (filterDeviceProfi" +
"leInclude) {\r\n return (filterDeviceProfileInclude[model.D" +
"eviceProfileId] == true)\r\n }\r\n if (filterD" +
"eviceProfileExclude) {\r\n return (!filterDeviceProfileExcl" +
"ude[model.DeviceProfileId])\r\n }\r\n return t" +
"rue;\r\n }\r\n return false;\r\n }\r\n\r\n " +
" var sortModels = function () {\r\n modelsInProcessSorted = [];" +
"\r\n modelsReadyForReturnSorted = [];\r\n modelsWaitin" +
"gForUserActionSorted = [];\r\n var modelSortFunc = function (a, b) " +
"{\r\n if (a.UserId.toUpperCase() == b.UserId.toUpperCase()) {\r\n" +
" return 0;\r\n } else {\r\n " +
" if (a.UserId.toUpperCase() < b.UserId.toUpperCase()) {\r\n " +
" return -1\r\n } else {\r\n " +
" return 1\r\n }\r\n }\r\n " +
" };\r\n for (var key in models) {\r\n var model =" +
" models[key];\r\n if (model) {\r\n if (mod" +
"el.WaitingForUserAction) {\r\n modelsWaitingForUserActi" +
"onSorted.push(model);\r\n } else {\r\n " +
" if (model.ReadyForReturn) {\r\n modelsReadyFor" +
"ReturnSorted.push(model);\r\n } else {\r\n " +
" modelsInProcessSorted.push(model);\r\n " +
" }\r\n }\r\n }\r\n }\r\n " +
" modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortF" +
"unc);\r\n modelsInProcessSorted = modelsInProcessSorted.sort(modelS" +
"ortFunc);\r\n modelsWaitingForUserActionSorted = modelsWaitingForUs" +
"erActionSorted.sort(modelSortFunc);\r\n\r\n if (modelsInProcessSorted" +
".length != modelsInProcessCount) {\r\n modelsInProcessCount = m" +
"odelsInProcessSorted.length;\r\n $(\'#inProcessCount\').text(\'(\' " +
"+ modelsInProcessCount + \')\');\r\n }\r\n if (modelsRea" +
"dyForReturnSorted.length != modelsReadyForReturnCount) {\r\n mo" +
"delsReadyForReturnCount = modelsReadyForReturnSorted.length;\r\n " +
" $(\'#readyForReturnCount\').text(\'(\' + modelsReadyForReturnCount + \')\');\r\n " +
" }\r\n if (modelsWaitingForUserActionSorted.length != mode" +
"lsWaitingForUserActionCount) {\r\n modelsWaitingForUserActionCo" +
"unt = modelsWaitingForUserActionSorted.length;\r\n $(\'#waitingF" +
"orUserActionCount\').text(\'(\' + modelsWaitingForUserActionCount + \')\');\r\n " +
" }\r\n\r\n };\r\n\r\n var scrollReadyForReturn = function (" +
") {\r\n $readyForReturnContent.find(\'li\').last().detach().prependTo" +
"($readyForReturnContent).hide().slideDown(\'slow\');\r\n modelsReadyF" +
"orReturnIndexOffset++;\r\n if (modelsReadyForReturnIndexOffset >= m" +
"odelsReadyForReturnSorted.length) {\r\n modelsReadyForReturnInd" +
"exOffset = 0;\r\n }\r\n scrollReadyForReturnToken = wi" +
"ndow.setTimeout(scrollReadyForReturn, scrollSpeed);\r\n };\r\n " +
" var updateScrollReadyForReturn = function () {\r\n var containerHe" +
"ight = $readyForReturn.find(\'.content\').height();\r\n var contentHe" +
"ight = $readyForReturnContent.height();\r\n if (containerHeight >= " +
"contentHeight && scrollReadyForReturnToken) {\r\n window.clearT" +
"imeout(scrollReadyForReturnToken);\r\n return;\r\n " +
" }\r\n if (containerHeight < contentHeight && scrollReadyForReturnT" +
"oken == null) {\r\n scrollReadyForReturnToken = window.setTimeo" +
"ut(scrollReadyForReturn, scrollSpeed);\r\n }\r\n };\r\n " +
" var scrollInProcess = function () {\r\n $inProcessContent.fi" +
"nd(\'li\').last().detach().prependTo($inProcessContent).hide().slideDown(\'slow\');\r" +
"\n modelsInProcessIndexOffset++;\r\n if (modelsInProc" +
"essIndexOffset >= modelsInProcessSorted.length) {\r\n modelsInP" +
"rocessIndexOffset = 0;\r\n }\r\n scrollInProcessToken " +
"= window.setTimeout(scrollInProcess, scrollSpeed);\r\n };\r\n " +
"var updateScrollInProcess = function () {\r\n var containerHeight =" +
" $inProcess.find(\'.content\').height();\r\n var contentHeight = $inP" +
"rocessContent.height();\r\n if (containerHeight >= contentHeight &&" +
" scrollInProcessToken) {\r\n window.clearTimeout(scrollInProces" +
"sToken);\r\n return;\r\n }\r\n if (co" +
"ntainerHeight < contentHeight && scrollInProcessToken == null) {\r\n " +
" scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);\r\n " +
" }\r\n };\r\n var scrollWaitingForUserAction = f" +
"unction () {\r\n $waitingForUserActionContent.find(\'li\').last().det" +
"ach().prependTo($waitingForUserActionContent).hide().slideDown(\'slow\');\r\n " +
" modelsInProcessIndexOffset++;\r\n if (modelsWaitingForUser" +
"ActionIndexOffset >= modelsWaitingForUserActionSorted.length) {\r\n " +
" modelsWaitingForUserActionIndexOffset = 0;\r\n }\r\n " +
" scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserActi" +
"on, scrollSpeed);\r\n };\r\n var updateScrollWaitingForUserAct" +
"ion = function () {\r\n var containerHeight = $waitingForUserAction" +
".find(\'.content\').height();\r\n var contentHeight = $waitingForUser" +
"ActionContent.height();\r\n if (containerHeight >= contentHeight &&" +
" scrollWaitingForUserActionToken) {\r\n window.clearTimeout(scr" +
"ollWaitingForUserActionToken);\r\n return;\r\n }\r\n" +
" if (containerHeight < contentHeight && scrollWaitingForUserActio" +
"nToken == null) {\r\n scrollWaitingForUserActionToken = window." +
"setTimeout(scrollWaitingForUserAction, scrollSpeed);\r\n }\r\n " +
" };\r\n\r\n var modelInsertIndex = function (model) {\r\n " +
" sortModels();\r\n var findIndex = function (model, array, offset)" +
" {\r\n for (var i = 0; i < array.length; i++) {\r\n " +
" if (model.UserId == array[i].UserId) {\r\n va" +
"r index = i + offset;\r\n if (index > (array.length - 1" +
")) {\r\n index = index - (array.length - 1);\r\n " +
" }\r\n return index;\r\n " +
" }\r\n };\r\n };\r\n if (" +
"model.WaitingForUserAction) {\r\n return findIndex(model, model" +
"sWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);\r\n " +
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
" return findIndex(model, modelsReadyForReturnSorted, modelsReadyForRetur" +
"nIndexOffset);\r\n } else {\r\n return fin" +
"dIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);\r\n " +
" }\r\n }\r\n }\r\n var modelInsert = functi" +
"on (model) {\r\n var index = modelInsertIndex(model);\r\n " +
" var insertTo = function (model, host) {\r\n var hostLi = ho" +
"st.children(\'li\');\r\n if (hostLi.length == 0 || hostLi.length " +
"< index) {\r\n host.append(model.htmlLi);\r\n " +
" } else {\r\n if (index == 0) {\r\n " +
" host.prepend(model.htmlLi);\r\n } else {\r\n " +
" $(hostLi.get(index - 1)).after(model.htmlLi);\r\n " +
" }\r\n }\r\n }\r\n if (model.Wa" +
"itingForUserAction) {\r\n insertTo(model, $waitingForUserAction" +
"Content);\r\n window.setTimeout(updateScrollWaitingForUserActio" +
"n, 100);\r\n } else {\r\n if (model.ReadyForReturn" +
") {\r\n insertTo(model, $readyForReturnContent);\r\n " +
" window.setTimeout(updateScrollReadyForReturn, 100);\r\n " +
" } else {\r\n insertTo(model, $inProcessContent);\r\n " +
" window.setTimeout(updateScrollInProcess, 100);\r\n " +
" }\r\n }\r\n }\r\n\r\n var removeModel = " +
"function (model) {\r\n if (model) {\r\n model.html" +
"Li.slideUp(\'fast\', function () {\r\n model.htmlLi.remove();" +
"\r\n });\r\n }\r\n };\r\n\r\n var " +
"processModel = function (id, model, init) {\r\n if (!calculateFilte" +
"r(model)) {\r\n removeModel(models[id]);\r\n d" +
"elete models[id];\r\n sortModels();\r\n } else {\r\n" +
" var existing = models[id];\r\n models[id] =" +
" model;\r\n\r\n // Add\r\n model.htmlContent = $" +
"(\'<div>\').text(model.UserId + \' - \' + model.UserDisplayName);\r\n " +
" if (!model.ReadyForReturn && model.EstimatedReturnTime) {\r\n " +
" model.htmlContent.append($(\'<span class=\"small\">\').text(\' (Expected: \' + m" +
"odel.EstimatedReturnTime + \')\'));\r\n }\r\n if" +
" (model.WaitingForUserAction) {\r\n model.htmlContent.appen" +
"d($(\'<span class=\"small\">\').text(\' (Since \' + model.WaitingForUserActionSince + " +
"\')\'));\r\n } else {\r\n if (model.ReadyFor" +
"Return && model.ReadyForReturnSince) {\r\n model.htmlCo" +
"ntent.append($(\'<span class=\"small\">\').text(\' (Ready \' + model.ReadyForReturnSin" +
"ce + \')\'));\r\n }\r\n }\r\n\r\n " +
" if (existing) {\r\n if (existing.ReadyForReturn != mod" +
"el.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction" +
") {\r\n removeModel(existing);\r\n " +
" model.htmlLi = $(\'<li>\').html(model.htmlContent).data(\'ModelId\', id).hide()" +
";\r\n modelInsert(model);\r\n " +
"if (init) {\r\n model.htmlLi.fadeIn();\r\n " +
" } else {\r\n model.htmlLi.slideDow" +
"n();\r\n }\r\n } else {\r\n " +
" model.htmlLi = existing.htmlLi;\r\n " +
"model.htmlLi.slideUp(\'fast\', function () {\r\n mode" +
"l.htmlLi.html(model.htmlContent).slideDown();\r\n });\r\n" +
" }\r\n } else {\r\n " +
" model.htmlLi = $(\'<li>\').html(model.htmlContent).data(\'ModelId\', id).hide();\r\n " +
" modelInsert(model);\r\n if (init) {\r" +
"\n model.htmlLi.fadeIn();\r\n } e" +
"lse {\r\n model.htmlLi.slideDown(\'slow\');\r\n " +
" }\r\n }\r\n if (model.htmlLi && mo" +
"del.IsAlert) {\r\n model.htmlLi.addClass(\'alert\');\r\n " +
" }\r\n }\r\n };\r\n\r\n var updatedMode" +
"l = function (id) {\r\n var userId = id.toString();\r\n\r\n " +
" $.ajax({\r\n dataType: \'json\',\r\n url: \'");
WriteLiteral(" id=\"item-template\"");
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
"\"text: UserIdFriendly + \' - \' + UserDisplayName\"></span>\r\n <!-- ko if" +
": !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->\r\n <span class=\"s" +
"mall\">(Expected <span data-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>" +
")</span>\r\n <!-- /ko -->\r\n <!-- ko if: WaitingForUserAction" +
" -->\r\n <span class=\"small\">(Since <span data-bind=\"livestamp: Waiting" +
"ForUserActionSinceUnixEpoc\"></span>)</span>\r\n <!-- /ko -->\r\n " +
" <!-- ko if: ReadyForReturn && !WaitingForUserAction -->\r\n <span cl" +
"ass=\"small\">(Ready <span data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></sp" +
"an>)</span>\r\n <!-- /ko -->\r\n </li>\r\n </script>\r\n <script" +
">\r\n ko.bindingHandlers.livestamp = {\r\n init: function (element" +
", valueAccessor, allBindings, viewModel, bindingContext) {\r\n var " +
"value = valueAccessor();\r\n var valueUnwrapped = ko.unwrap(value);" +
"\r\n\r\n if (valueUnwrapped)\r\n $(element).livestam" +
"p(valueUnwrapped);\r\n else\r\n $(element).livesta" +
"mp(\'destroy\');\r\n }\r\n };\r\n </script>\r\n <script>\r\n " +
"$(function () {\r\n var hub;\r\n var viewModel;\r\n\r\n " +
" var rotateSpeed = 3000;\r\n var itemFilters;\r\n\r\n var $inPro" +
"cessList = $(\'#inProcess\').find(\'ul\');\r\n var $readyForReturnList = $(" +
"\'#readyForReturn\').find(\'ul\');\r\n var $waitingForUserActionList = $(\'#" +
"waitingForUserAction\').find(\'ul\');\r\n\r\n function noticeboardViewModel(" +
"inProcess, readyForReturn, waitingForUserAction) {\r\n var self = t" +
"his;\r\n\r\n self.initialized = false;\r\n\r\n self.inProc" +
"ess = ko.observableArray(inProcess);\r\n self.readyForReturn = ko.o" +
"bservableArray(readyForReturn);\r\n self.waitingForUserAction = ko." +
"observableArray(waitingForUserAction);\r\n\r\n self.onRemove = functi" +
"on (element, index, data) {\r\n $(element).slideUp(400, functio" +
"n () {\r\n $(this).remove();\r\n });\r\n " +
" }\r\n self.onAdd = function (element, index, data) {\r\n " +
" if (self.initialized)\r\n $(element).hid" +
"e().slideDown(400);\r\n }\r\n }\r\n\r\n function in" +
"it() {\r\n // Connect to Hub\r\n hub = $.connection.no" +
"ticeboardUpdates;\r\n\r\n // Map Functions\r\n hub.clien" +
"t.updateHeldDeviceForUser = updateHeldDevice;\r\n\r\n $.connection.hu" +
"b.qs = { Noticeboard: \'");
#line 435 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevice()));
#line 127 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name);
#line default
#line hidden
WriteLiteral(@"',
data: { id: userId },
success: function (data) {
processModel(userId, data, false);
},
error: function(jqXHR, textStatus, errorThrown){
if (textStatus == 'parsererror') // null Result
processModel(userId, null, false);
}
})
};
WriteLiteral(@"' };
$.connection.hub.error(connectionError);
$.connection.hub.disconnected(connectionError);
$.connection.hub.reconnected(connectionError);
var connectionError = function () {
if (persistantConnection) {
persistantConnection.stop();
persistantConnection = null;
window.setTimeout(function () {
window.location.href = '");
// Start Connection
$.connection.hub.start().fail(connectionError).done(loadData);
}
// Called after SignalR is connected
function loadData() {
$.getJSON('");
#line 452 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.UserHeldDevices.Noticeboard()));
#line 138 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
#line default
#line hidden
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
" var init = function () {\r\n buildFilters();\r\n pe" +
"rsistantConnection = $.connection(\'");
#line 459 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Url.Content("~/Public/UserHeldDevices/Notifications"));
#line default
#line hidden
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
" persistantConnection.error(connectionError);\r\n persistantConnec" +
"tion.start(function () {\r\n $.getJSON(\'");
#line 463 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
#line default
#line hidden
WriteLiteral(@"', null, function (data) {
for (var i = 0; i < data.length; i++) {
processModel(data[i].UserId, data[i], true);
}
});
});
};
init();
});
</script>
<div");
WriteLiteral(" id=\"mainFooter\"");
WriteLiteral(">\r\n <img");
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
WriteAttribute("src", Tuple.Create(" src=\"", 22642), Tuple.Create("\"", 22692)
#line 475 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
, Tuple.Create(Tuple.Create("", 22648), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
#line default
#line hidden
, 22648), false)
);
WriteLiteral(" alt=\"Disco Logo\"");
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
" var readyForReturn = [];\r\n var waitingForUserAction" +
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
" return includeItem(heldDeviceItem)\r\n }).forEac" +
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
" readyForReturn.push(heldDeviceItem);\r\n " +
" else if (isInProcess(heldDeviceItem))\r\n inP" +
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
"orUserAction);\r\n\r\n ko.applyBindings(viewModel);\r\n " +
" viewModel.initialized = true;\r\n\r\n $(\'body\').removeCla" +
"ss(\'status-connecting\');\r\n\r\n window.setTimeout(scheduleRotati" +
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
" }\r\n\r\n // Called by SignalR\r\n function updateHeldDevic" +
"e(updates) {\r\n if (viewModel) {\r\n\r\n $.each(upd" +
"ates, function (UserId, heldDeviceItem) {\r\n // Remove Exi" +
"sting\r\n removeItem(UserId);\r\n\r\n //" +
" Add Item\r\n addItem(heldDeviceItem);\r\n " +
" });\r\n }\r\n }\r\n\r\n function removeItem(UserId" +
") {\r\n removeItemFromArray(viewModel.inProcess, UserId);\r\n " +
" removeItemFromArray(viewModel.readyForReturn, UserId);\r\n " +
"removeItemFromArray(viewModel.waitingForUserAction, UserId);\r\n }\r\n\r\n " +
" function addItem(heldDeviceItem) {\r\n if (heldDeviceIte" +
"m !== null &&\r\n heldDeviceItem !== undefined &&\r\n " +
" includeItem(heldDeviceItem)) {\r\n\r\n var array;\r\n\r\n " +
" if (isWaitingForUserAction(heldDeviceItem))\r\n " +
" array = viewModel.waitingForUserAction;\r\n else if (isRea" +
"dyForReturn(heldDeviceItem))\r\n array = viewModel.readyFor" +
"Return;\r\n else if (isInProcess(heldDeviceItem))\r\n " +
" array = viewModel.inProcess;\r\n\r\n if (array().leng" +
"th === 0) {\r\n array.push(heldDeviceItem);\r\n " +
" } else {\r\n var index = findSortedInsertIndex(array," +
" heldDeviceItem);\r\n if (index === -1)\r\n " +
" array.push(heldDeviceItem);\r\n else\r\n " +
" array.splice(index, 0, heldDeviceItem);\r\n }\r" +
"\n }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
" rotateArray(viewModel.inProcess, $inProcessList);\r\n r" +
"otateArray(viewModel.readyForReturn, $readyForReturnList);\r\n rota" +
"teArray(viewModel.waitingForUserAction, $waitingForUserActionList);\r\n " +
" }\r\n\r\n function scheduleRotation() {\r\n rotateArrays();" +
"\r\n\r\n window.setTimeout(scheduleRotation, rotateSpeed);\r\n " +
" }\r\n\r\n function includeItem(heldDeviceItem) {\r\n if (" +
"itemFilters == null || itemFilters.length == 0)\r\n return true" +
";\r\n\r\n return itemFilters.reduce(function (previousValue, currentV" +
"alue, index, array) {\r\n if (previousValue === false)\r\n " +
" return false;\r\n return currentValue(heldDevi" +
"ceItem);\r\n }, true);\r\n }\r\n\r\n function build" +
"Filters() {\r\n var filters = [];\r\n var queryStringP" +
"arameters = getQueryStringParameters();\r\n\r\n if (queryStringParame" +
"ters !== null) {\r\n $.each(queryStringParameters, function (ke" +
"y, value) {\r\n switch (key.toLowerCase()) {\r\n " +
" case \'deviceaddressinclude\':\r\n var" +
" deviceAddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); }" +
");\r\n if (deviceAddresses.length > 0) {\r\n " +
" filters.push(function (heldDeviceItem) {\r\n " +
" // false if DeviceAddressShortName is null\r\n " +
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
" return false;\r\n\r\n " +
" // true if DeviceAddressShortName is included\r\n " +
" return $.inArray(heldDeviceItem.DeviceAddressShortName" +
".toLowerCase(), deviceAddresses) >= 0;\r\n });\r" +
"\n }\r\n break;\r\n " +
" case \'deviceaddressexclude\':\r\n " +
" var deviceAddresses = value.split(\",\").map(function (v) { return v.toLower" +
"Case(); });\r\n if (deviceAddresses.length > 0) {\r\n" +
" filters.push(function (heldDeviceItem) {\r\n " +
" // true if DeviceAddressShortName is null\r" +
"\n if (!heldDeviceItem.DeviceAddressShortN" +
"ame)\r\n return true;\r\n\r\n " +
" // true if DeviceAddressShortName is excluded\r\n " +
" return $.inArray(heldDeviceItem.DeviceAddressSh" +
"ortName.toLowerCase(), deviceAddresses) < 0;\r\n " +
" });\r\n }\r\n break;" +
"\r\n case \'deviceprofileinclude\':\r\n " +
" var deviceProfiles = value.split(\",\");\r\n " +
" if (deviceProfiles.length > 0) {\r\n filter" +
"s.push(function (heldDeviceItem) {\r\n // t" +
"rue if DeviceProfileId is included\r\n retu" +
"rn $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;\r\n " +
" });\r\n }\r\n " +
" break;\r\n case \'deviceprofileexclude\':" +
"\r\n var deviceProfiles = value.split(\",\");\r\n " +
" if (deviceProfiles.length > 0) {\r\n " +
" filters.push(function (heldDeviceItem) {\r\n " +
" // true if DeviceProfileId is excluded\r\n " +
" return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfile" +
"s) < 0;\r\n });\r\n " +
" }\r\n break;\r\n }\r\n " +
" });\r\n }\r\n\r\n if (filters.length > 0)\r\n " +
" itemFilters = filters;\r\n else\r\n " +
" itemFilters = null;\r\n }\r\n\r\n function connectionError(" +
") {\r\n try {\r\n $(\'body\').addClass(\'status-error" +
"\');\r\n $.connection.hub.stop();\r\n } catch (e) {" +
"\r\n // Ignore\r\n }\r\n\r\n window.set" +
"Timeout(function () {\r\n window.location.href = window.locatio" +
"n.href;\r\n }, 10000);\r\n }\r\n\r\n // Helpers\r\n " +
" function rotateArray(koArray, element) {\r\n var items = " +
"koArray();\r\n\r\n if (items.length <= 1)\r\n return" +
" 0;\r\n\r\n if (element.height() < (element.parent().height() - 30)) " +
"{\r\n\r\n if (findUnsortedArrayTopIndex(items) !== 0)\r\n " +
" koArray.sort(sortFunction);\r\n\r\n // Don\'t rotate" +
" if small & sorted correctly\r\n return;\r\n }\r\n\r\n" +
" // Move Last Item to Top\r\n var item = koArray.pop" +
"();\r\n koArray.unshift(item);\r\n }\r\n function" +
" removeItemFromArray(koArray, UserId) {\r\n var items = koArray();\r" +
"\n for (var i = 0; i < items.length; i++) {\r\n i" +
"f (items[i].UserId == UserId) {\r\n koArray.splice(i, 1);\r\n" +
" items = koArray();\r\n i--;\r\n " +
" }\r\n }\r\n }\r\n function findUnso" +
"rtedArrayTopIndex(items) {\r\n // Only one Item\r\n if" +
" (items.length <= 1)\r\n return 0;\r\n\r\n for (var " +
"i = 1; i < items.length; i++) {\r\n var s = sortFunction(items[" +
"i - 1], items[i]);\r\n if (s > 0)\r\n retu" +
"rn i;\r\n }\r\n\r\n return 0;\r\n }\r\n " +
" function findSortedInsertIndex(koArray, heldDeviceItem) {\r\n var" +
" items = koArray();\r\n var startIndex = findUnsortedArrayTopIndex(" +
"items);\r\n for (var i = startIndex; i < items.length; i++) {\r\n " +
" var s = sortFunction(heldDeviceItem, items[i]);\r\n " +
" if (s <= 0)\r\n return i;\r\n }\r\n " +
" if (startIndex !== 0) {\r\n for (var i = 0; i < startIn" +
"dex; i++) {\r\n var s = sortFunction(heldDeviceItem, items[" +
"i]);\r\n if (s <= 0)\r\n return i;" +
"\r\n }\r\n return startIndex;\r\n " +
" } else {\r\n return -1;\r\n }\r\n }\r\n " +
" function sortFunction(l, r) {\r\n return l.UserIdFriendly." +
"toLowerCase() == r.UserIdFriendly.toLowerCase() ? 0 : (l.UserIdFriendly.toLowerC" +
"ase() < r.UserIdFriendly.toLowerCase() ? -1 : 1)\r\n }\r\n fun" +
"ction isInProcess(i) {\r\n return !i.ReadyForReturn && !i.WaitingFo" +
"rUserAction;\r\n }\r\n function isReadyForReturn(i) {\r\n " +
" return i.ReadyForReturn && !i.WaitingForUserAction;\r\n }\r\n " +
" function isWaitingForUserAction(i) {\r\n return i.WaitingF" +
"orUserAction;\r\n }\r\n function getQueryStringParameters() {\r" +
"\n\r\n if (window.location.search.length === 0)\r\n " +
" return null;\r\n\r\n var params = {};\r\n window.locati" +
"on.search.substr(1).split(\"&\").forEach(function (pair) {\r\n if" +
" (pair === \"\") return;\r\n var parts = pair.split(\"=\");\r\n " +
" params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace" +
"(/\\+/g, \" \"));\r\n });\r\n return params;\r\n " +
" }\r\n\r\n init();\r\n });\r\n </script>\r\n</body>\r\n</html>");
}
}