Files
Disco/Disco.Web/Views/Job/JobParts/Resources.cshtml
T
Gary Sharp a0e18ef963 SignalR Bug Fixes & Minor UI Changes
Document Template import status and Device Enrolment status fixes.
Attachment download fixes for SignalR foreverFrame transport. Database
queries for Devices, Jobs and Users updated. Device attributes (model,
profile, batch) now shown in various places.
2014-06-03 12:36:48 +10:00

580 lines
25 KiB
Plaintext

@model Disco.Web.Models.Job.ShowModel
@{
Authorization.RequireAny(Claims.Job.ShowLogs, Claims.Job.ShowAttachments);
var canShowLogs = Authorization.Has(Claims.Job.ShowLogs);
var canShowAttachments = Authorization.Has(Claims.Job.ShowAttachments);
var canAddLogs = Authorization.Has(Claims.Job.Actions.AddLogs);
var canRemoveAnyLogs = Authorization.Has(Claims.Job.Actions.RemoveAnyLogs);
var canRemoveOwnLogs = Authorization.Has(Claims.Job.Actions.RemoveOwnLogs);
var canAddAttachments = Authorization.Has(Claims.Job.Actions.AddAttachments);
var canRemoveAnyAttachments = Authorization.Has(Claims.Job.Actions.RemoveAnyAttachments);
var canRemoveOwnAttachments = Authorization.Has(Claims.Job.Actions.RemoveOwnAttachments);
if (canShowAttachments)
{
Html.BundleDeferred("~/Style/Shadowbox");
Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox");
}
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
}
<table id="jobShowResources">
<tr class="@(canShowLogs ? "canShowLogs" : "cannotShowLogs") @(canShowAttachments ? "canShowAttachments" : "cannotShowAttachments")">
@if (canShowLogs)
{
<td id="Comments" class="@(canAddLogs ? "canAddLogs" : "cannotAddLogs")">
<div class="commentOutput">
@foreach (var jl in Model.Job.JobLogs.OrderBy(m => m.Timestamp))
{
<div data-logid="@jl.Id">
<span class="author">@jl.TechUser.ToStringFriendly()</span>@if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.UserId))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" data-livestamp="@(jl.Timestamp.ToUnixEpoc())" title="@jl.Timestamp.ToFullDateTime()">@jl.Timestamp.ToFullDateTime()</span>
<span class="comment">@jl.Comments.ToMultilineJobRefString()</span>
</div>
}
</div>
@if (canAddLogs)
{
<div class="commentInput clearfix">
<textarea class="commentInput" placeholder="write comment..." accesskey="l"></textarea>
<span class="action post commentInputPost fa fa-comment" title="Post Comment"></span>
</div>
}
</td>
}
@if (canShowAttachments)
{
<td id="Attachments" class="@(canAddAttachments ? "canAddAttachments" : "cannotAddAttachments")">
<div class="attachmentOutput">
@foreach (var ja in Model.Job.JobAttachments)
{
<a href="@Url.Action(MVC.API.Job.AttachmentDownload(ja.Id))" data-attachmentid="@ja.Id" data-mimetype="@ja.MimeType">
<span class="icon" title="@ja.Filename">
<img alt="Attachment Thumbnail" src="@(Url.Action(MVC.API.Job.AttachmentThumbnail(ja.Id)))" /></span>
<span class="comments" title="@ja.Comments">
@{if (!string.IsNullOrEmpty(ja.DocumentTemplateId))
{ @ja.DocumentTemplate.Description}
else
{ @ja.Comments }}
</span><span class="author">@ja.TechUser.ToStringFriendly()</span>@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.UserId))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" data-livestamp="@(ja.Timestamp.ToUnixEpoc())" title="@ja.Timestamp.ToFullDateTime()">@ja.Timestamp.ToFullDateTime()</span>
</a>
}
</div>
@if (canAddAttachments)
{
<div class="attachmentInput clearfix">
<span class="action upload fa fa-upload" title="Attach File"></span><span class="action photo fa fa-camera" title="Capture Image"></span>
</div>
}
</td>
}
</tr>
</table>
@if (canShowLogs && (canRemoveAnyLogs || canRemoveOwnLogs))
{
<div id="dialogRemoveLog" class="dialog" title="Remove this Comment?">
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
</p>
</div>
}
@if (canShowAttachments && canAddAttachments)
{
<div id="dialogUpload" class="dialog" title="Upload Attachment">
<div id="silverlightHostUploadAttachment">
</div>
</div>
}
@if (canShowAttachments && (canRemoveAnyAttachments || canRemoveOwnAttachments))
{
<div id="dialogRemoveAttachment" class="dialog" title="Remove this Attachment?">
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
</p>
</div>
}
@if (canShowLogs)
{
<script>
if (!document.DiscoFunctions) {
document.DiscoFunctions = {};
}
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region Comments
var $Comments = $('#Comments');
var $CommentOutput = $Comments.find('.commentOutput');
var $CommentOutputContainer = $Comments.find('.commentOutputContainer');
window.setTimeout(function () {
$CommentOutput[0].scrollTop = $CommentOutput[0].scrollHeight; // Scroll to Bottom
}, 0);
$('#jobDetailTabs').on('tabsactivate', function (event, ui) {
if (ui.newPanel && ui.newPanel.is('#jobDetailTab-Resources')) {
$CommentOutput[0].scrollTop = $CommentOutput[0].scrollHeight; // Scroll to Bottom
}
});
@if (canAddLogs)
{<text>
//#region Add Logs
var $CommentInput = $Comments.find('textarea.commentInput');
$Comments.find('.commentInputPost').click(postComment);
$CommentInput.keypress(function (e) {
if (e.which == 13 && !e.shiftKey) {
postComment();
return false;
}
});
function postComment() {
var comment = $CommentInput.val();
if (comment != '') {
var data = { comment: comment }
$.ajax({
url: '@Url.Action(MVC.API.Job.CommentPost(Model.Job.Id, null))',
dataType: 'json',
data: data,
success: function (d) {
if (d.Result == 'OK') {
// Should be added via Repository Notifications
// addComment(d.Comment, false);
$CommentInput.val('').attr('disabled', false).focus();
} else {
alert('Unable to post comment: ' + d.Result);
$CommentInput.attr('disabled', false);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to post comment: ' + textStatus);
$CommentInput.attr('disabled', false);
}
});
}
}
//#endregion
</text>}
@if (canRemoveAnyLogs || canRemoveOwnLogs)
{<text>
//#region Remove Logs
var $dialogRemoveLog;
$CommentOutput.find('span.remove').click(removePost);
function removePost() {
$this = $(this);
var data = { id: $this.closest('div').attr('data-logid') };
if (!$dialogRemoveLog) {
$dialogRemoveLog = $('#dialogRemoveLog').dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
}
$dialogRemoveLog.dialog("enable").dialog('option', 'buttons', {
"Remove": function () {
$dialogRemoveLog.dialog("disable");
$dialogRemoveLog.dialog("option", "buttons", null);
$.ajax({
url: '@Url.Action(MVC.API.Job.CommentRemove())',
dataType: 'json',
data: data,
success: function (d) {
if (d == 'OK') {
// Should be removed via Repository Notifications
//$this.closest('div').slideUp(300).delay(300).queue(function () {
// $(this).remove();
//});
} else {
alert('Unable to remove comment: ' + d);
}
$dialogRemoveLog.dialog("close");
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to remove comment: ' + textStatus);
$dialogRemoveLog.dialog("close");
}
});
},
"Cancel": function () {
$dialogRemoveLog.dialog("close");
}
}).dialog('open');
return false;
}
//#endregion
</text>}
function loadLiveComment(key) {
$.ajax({
url: '@Url.Action(MVC.API.Job.Comment())',
dataType: 'json',
data: { id: key },
success: function (d) {
if (d && d.JobId == jobId) {
@if (canRemoveAnyLogs)
{<text>addComment(d, false, true);</text>}
else if (canRemoveOwnLogs)
{<text>addComment(d, false, (d.AuthorId === '@(CurrentUser.UserId)'));</text>}
else
{<text>addComment(d, false, false);</text>}
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to load live comment ' + id + ': ' + textStatus);
}
});
}
function liveRemoveComment(key) {
$CommentOutput.children('div[data-logid="' + key + '"]').slideUp(300).delay(300).queue(function () {
var $this = $(this);
$this.find('.timestamp').livestamp('destroy');
$this.remove();
});
}
function addComment(c, quick, canRemove) {
var t = '<div><span class="author" />';
if (canRemove)
t += '<span class="remove fa fa-times-circle" />';
t += '<span class="timestamp" /><span class="comment" /></div>';
var e = $(t);
e.attr('data-logid', c.Id);
e.find('.author').text(c.Author);
e.find('.timestamp').text(c.TimestampFull).attr('title', c.TimestampFull).livestamp(c.TimestampUnixEpoc);
if (canRemove)
e.find('.remove').click(removePost);
var eComment = e.find('.comment').text(c.Comments);
var commentHtml = eComment.text().replace(/\r\n|\r|\n/g, '<br />');
commentHtml = commentHtml.replace(/\#(\d+)/g, '<a href="@Url.Action(MVC.Job.Show(null))?id=$1">#$1</a>');
eComment.html(commentHtml);
$CommentOutput.append(e);
if (!quick) {
e.animate({ backgroundColor: '#ffff99' }, 500, function () {
e.animate({ backgroundColor: '#fafafa' }, 500, function () {
e.css('background-color', '');
});
});
$CommentOutput.animate({ scrollTop: $CommentOutput[0].scrollHeight }, 250)
}
}
// Add Globally Available Functions
document.DiscoFunctions.liveLoadComment = loadLiveComment;
document.DiscoFunctions.liveRemoveComment = liveRemoveComment;
//#endregion
});
</script>
}
@if (canShowAttachments)
{
<script>
Shadowbox.init({
skipSetup: true,
modal: true
});
if (!document.DiscoFunctions) {
document.DiscoFunctions = {};
}
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region Attachments
var $Attachments = $('#Attachments');
var $attachmentOutput = $Attachments.find('.attachmentOutput');
@if (canAddAttachments)
{<text>
//#region Add Attachments
// For Silverlight Backwards-compatibility
// - Repository notifications now handles this
document.DiscoFunctions.addAttachment = function () { };
var $dialogUpload;
var onLoadNavigation = null;
var isLoaded = null;
var $attachmentInput = $Attachments.find('.attachmentInput');
$attachmentInput.find('.photo').click(function () {
showDialog('/WebCam');
});
$attachmentInput.find('.upload').click(function () {
showDialog('/File');
});
function showDialog(navigationPath) {
if (!$dialogUpload) {
Silverlight.createObject(
'@(Links.ClientBin.Disco_Silverlight_AttachmentUpload_xap)',
$('#silverlightHostUploadAttachment').get(0),
'silverlightUploadAttachment',
{ width: '840px', height: '500px', background: 'white', version: '4.0.60310.0' },
{
onLoad: function () {
if (onLoadNavigation) {
$('#silverlightUploadAttachment').get(0).content.Navigator.Navigate(onLoadNavigation);
isLoaded = true;
}
}
},
'UploadUrl=@(Url.Action(MVC.API.Job.AttachmentUpload(Model.Job.Id, null)))');
$dialogUpload = $('#dialogUpload').dialog({
autoOpen: false,
draggable: false,
modal: true,
resizable: false,
width: 860,
height: 550,
close: function () {
var sl = $('#silverlightUploadAttachment').get(0);
if (sl.content)
sl.content.Navigator.Navigate('/Hidden');
}
});
}
$dialogUpload.dialog('open');
if (isLoaded) {
$('#silverlightUploadAttachment').get(0).content.Navigator.Navigate(navigationPath);
} else {
onLoadNavigation = navigationPath;
}
};
//#endregion
</text>}
@if (canRemoveAnyAttachments || canRemoveOwnAttachments)
{<text>
//#region Remove Attachments
var $dialogRemoveAttachment;
$attachmentOutput.find('span.remove').click(removeLocalAttachment);
function removeLocalAttachment() {
$this = $(this).closest('a');
var data = { id: $this.attr('data-attachmentid') };
if (!$dialogRemoveAttachment) {
$dialogRemoveAttachment = $('#dialogRemoveAttachment').dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
}
$dialogRemoveAttachment.dialog("enable").dialog('option', 'buttons', {
"Remove": function () {
$dialogRemoveAttachment.dialog("disable");
$dialogRemoveAttachment.dialog("option", "buttons", null);
$.ajax({
url: '@Url.Action(MVC.API.Job.AttachmentRemove())',
dataType: 'json',
data: data,
success: function (d) {
if (d == 'OK') {
// Should be removed via Repository Notifications
} else {
alert('Unable to remove attachment: ' + d);
}
$dialogRemoveAttachment.dialog("close");
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to remove attachment: ' + textStatus);
$dialogRemoveAttachment.dialog("close");
}
});
},
"Cancel": function () {
$dialogRemoveAttachment.dialog("close");
}
}).dialog('open');
return false;
}
//#endregion
</text>}
function addAttachment(key, quick) {
var data = { id: key };
$.ajax({
url: '@Url.Action(MVC.API.Job.Attachment())',
dataType: 'json',
data: data,
success: function (d) {
if (d.Result == 'OK') {
var a = d.Attachment;
@if (canRemoveAnyAttachments)
{
<text>buildAttachment(a, true, quick);</text>
}
else if (canRemoveOwnAttachments)
{
<text>buildAttachment(a, (a.AuthorId === '@(CurrentUser.UserId)'), quick);</text>
}
else
{
<text>buildAttachment(a, false, quick);</text>
}
} else {
alert('Unable to add attachment: ' + d.Result);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to add attachment: ' + textStatus);
}
});
}
function buildAttachment(a, canRemove, quick) {
if (parseInt(a.ParentId) == jobId) {
var t = '<a><span class="icon"><img alt="Attachment Thumbnail" /></span><span class="comments"></span><span class="author"></span>';
if (canRemove)
t += '<span class="remove fa fa-times-circle"></span>';
t += '<span class="timestamp"></span></a>';
var e = $(t);
e.attr('data-attachmentid', a.Id).attr('data-mimetype', a.MimeType).attr('href', '@(Url.Action(MVC.API.Job.AttachmentDownload()))/' + a.Id);
e.find('.icon img').attr('src', '@(Url.Action(MVC.API.Job.AttachmentThumbnail()))/' + a.Id);
e.find('.comments').text(a.Description);
e.find('.author').text(a.Author);
e.find('.timestamp').text(a.TimestampFull).attr('title', a.TimestampFull).livestamp(a.TimestampUnixEpoc);
if (canRemove)
e.find('.remove').click(removeLocalAttachment);
if (!quick)
e.hide();
$attachmentOutput.append(e);
document.DiscoFunctions.liveAfterUpdate();
if (!quick)
e.show('slow');
if (a.MimeType.toLowerCase().indexOf('image/') == 0)
e.shadowbox({ gallery: 'attachments', player: 'img', title: a.Description });
else
e.click(onDownload);
}
}
function onDownload() {
var $this = $(this);
var url = $this.attr('href');
if ($.connection && $.connection.hub && $.connection.hub.transport &&
$.connection.hub.transport.name == 'foreverFrame') {
// SignalR active with foreverFrame transport - use popup window
window.open(url, '_blank', 'height=150,width=250,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no');
} else {
// use iFrame
if (!$attachmentDownloadHost) {
$attachmentDownloadHost = $('<iframe>')
.attr({ 'src': url, 'title': 'Attachment Download Host' })
.addClass('hidden')
.appendTo('body')
.contents();
} else {
$attachmentDownloadHost[0].location.href = url;
}
}
return false;
}
function removeAttachment(key) {
var $element = $attachmentOutput.find('a[data-attachmentid="' + key + '"]');
if ($element.length > 0) {
$element.hide(300).delay(300).queue(function () {
if ($element.attr('data-mimetype').toLowerCase().indexOf('image/') == 0)
Shadowbox.removeCache(this);
$element.remove();
document.DiscoFunctions.liveAfterUpdate();
});
}
}
$attachmentOutput.children('a').each(function () {
$this = $(this);
if ($this.attr('data-mimetype').toLowerCase().indexOf('image/') == 0)
$this.shadowbox({ gallery: 'attachments', player: 'img', title: $this.find('.comments').text() });
else
$this.click(onDownload);
});
// Add Globally Available Functions
document.DiscoFunctions.liveAddAttachment = addAttachment;
document.DiscoFunctions.liveRemoveAttachment = removeAttachment;
//#endregion
});
</script>
}
@if (canShowLogs || canShowAttachments)
{
<script>
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region LiveEvents
var hub = $.connection.jobUpdates;
// Map Functions
@if (canShowLogs)
{<text>
hub.client.addLog = document.DiscoFunctions.liveLoadComment;
hub.client.removeLog = document.DiscoFunctions.liveRemoveComment;
</text>}
@if (canShowAttachments)
{<text>
hub.client.addAttachment = document.DiscoFunctions.liveAddAttachment;
hub.client.removeAttachment = document.DiscoFunctions.liveRemoveAttachment;
document.DiscoFunctions.liveAfterUpdate = function () {
var tabLink = $('#jobDetailTab-ResourcesLink');
var attachmentCount = $('#Attachments').find('.attachmentOutput').children('a').length;
var tabHeading = tabLink.text();
tabHeading = tabHeading.substr(0, tabHeading.indexOf('[') + 1) + attachmentCount + ']';
tabLink.text(tabHeading);
}
</text>}
$.connection.hub.qs = { JobId: jobId };
$.connection.hub.error(onHubError);
// Start Connection
$.connection.hub.start().fail(onHubError);
function onHubError(error) {
alert('Live-update Error: ' + error);
}
//#endregion
});
</script>
}