Files
Disco/Disco.Web/Views/Job/JobParts/Resources.cshtml
T
Gary Sharp 3f63281dc4 Feature: Job Queues
Also UI style, theme and element changes
2014-02-03 14:50:08 +11:00

635 lines
27 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.ToString()</span>@if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.Id))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" title="@jl.Timestamp.ToFullDateTime()">@jl.Timestamp.FromNow()</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.ToString()</span>@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.Id))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" title="@ja.Timestamp.ToFullDateTime()">@ja.Timestamp.FromNow()</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="hiddenDialog" 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="hiddenDialog" title="Upload Attachment">
<div id="silverlightHostUploadAttachment">
</div>
</div>
}
@if (canShowAttachments && (canRemoveAnyAttachments || canRemoveOwnAttachments))
{
<div id="dialogRemoveAttachment" class="hiddenDialog" 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) {
if (key.JobId == jobId) {
$.ajax({
url: '@Url.Action(MVC.API.Job.Comment())',
dataType: 'json',
data: { id: key.Id },
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.Id)'));</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 () {
$(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.TimestampFuzzy).attr('title', c.TimestampFull);
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
//$this.hide(300).delay(300).queue(function () {
// var $this = $(this);
// if ($this.attr('data-mimetype').toLowerCase().indexOf('image/') == 0)
// Shadowbox.removeCache(this);
// $this.remove();
//});
} 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) {
if (key.JobId == jobId) {
var data = { id: key.Id };
$.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.Id)'), 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.Comments);
e.find('.author').text(a.Author);
e.find('.timestamp').text(a.TimestampFuzzy).attr('title', a.TimestampFull);
if (canRemove)
e.find('.remove').click(removeLocalAttachment);
if (!quick)
e.hide();
$attachmentOutput.append(e);
if (!quick)
e.show('slow');
if (a.MimeType.toLowerCase().indexOf('image/') == 0)
e.shadowbox({ gallery: 'attachments', player: 'img', title: a.Comments });
}
}
function removeAttachment(key) {
if (key.JobId == jobId) {
var $element = $attachmentOutput.find('a[data-attachmentid="' + key.Id + '"]');
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();
});
}
}
}
$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() });
});
// 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
function liveMessageRecieved(d) {
if (d) {
window.setTimeout(function () {
switch (d.EntityTypeName) {
case 'JobAttachment':
switch (d.EventType) {
case 0: // Added
document.DiscoFunctions.liveAddAttachment(d.EntityKey, false);
break;
case 1: // Removed
document.DiscoFunctions.liveRemoveAttachment(d.EntityKey);
break;
}
break;
case 'JobLog':
switch (d.EventType) {
case 0: // Added
document.DiscoFunctions.liveLoadComment(d.EntityKey);
break;
case 1: // Removed
if (d.EntityKey.JobId == jobId) {
document.DiscoFunctions.liveRemoveComment(d.EntityKey.Id);
}
break;
}
break;
}
}, 100);
}
}
var liveMessagesConnection = $.connection('@(Url.Content("~/API/Repository/Notifications"))', { addToGroups: 'JobLog,JobAttachment' })
liveMessagesConnection.received(liveMessageRecieved);
liveMessagesConnection.error(function (e) {
if (e)
alert('Error: ' + JSON.stringify(e));
});
liveMessagesConnection.start();
//#endregion
});
</script>
}
else if (canShowLogs)
{
<script>
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region LiveEvents
function liveMessageRecieved(d) {
if (d) {
window.setTimeout(function () {
switch (d.EventType) {
case 0: // Added
document.DiscoFunctions.liveLoadComment(d.EntityKey);
break;
case 1: // Removed
if (d.EntityKey.JobId == jobId) {
document.DiscoFunctions.liveRemoveComment(d.EntityKey.Id);
}
break;
}
}, 100);
}
}
var liveMessagesConnection = $.connection('@(Url.Content("~/API/Repository/Notifications"))', { addToGroups: 'JobLog' })
liveMessagesConnection.received(liveMessageRecieved);
liveMessagesConnection.error(function (e) {
if (e)
alert('Error: ' + JSON.stringify(e));
});
liveMessagesConnection.start();
//#endregion
});
</script>
}
else if (canShowAttachments)
{
<script>
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region LiveEvents
function liveMessageRecieved(d) {
if (d) {
window.setTimeout(function () {
switch (d.EventType) {
case 0: // Added
document.DiscoFunctions.liveAddAttachment(d.EntityKey, false);
break;
case 1: // Removed
document.DiscoFunctions.liveRemoveAttachment(d.EntityKey);
break;
}
}, 100);
}
}
var liveMessagesConnection = $.connection('@(Url.Content("~/API/Repository/Notifications"))', { addToGroups: 'JobAttachment' })
liveMessagesConnection.received(liveMessageRecieved);
liveMessagesConnection.error(function (e) {
if (e)
alert('Error: ' + JSON.stringify(e));
});
liveMessagesConnection.start();
//#endregion
});
</script>
}