app/views/reviews/submission_index.html.erb
<h1>
<% if @submission.reviews.count == 1 %>Code review<% else %>Code reviews<% end %>,
<%= @submission.exercise_name %>,
submission <%= @submission.id %>
</h1>
<div class="row">
<div class="col-md-12">
<% if !@new_review && can?(:create_review, @course) %>
<p><%= link_to 'Open review editor', new_submission_review_path(@submission) %></p>
<% end %>
<% if @submission.reviews.empty? %>
<p>Submission not reviewed yet.</p>
<% end %>
<% newest_sub = @submission.newest_of_same_kind %>
<% if newest_sub %>
<div class="alert alert-danger">
<button type="button" class="close" data-dismiss="alert">×</button>
<p> NOTE: There is a <%= link_to "newer submission", new_submission_review_path(newest_sub) %>.</p>
</div>
<% end %>
<% other_subs = @submission.exercise.reviewed_submissions_for(@submission.user) - [@submission] %>
<% unless other_subs.empty? %>
<h3>Other reviewed submissions of this exercise</h3>
<section>
<%=
options = {
:table_id => 'previously_reviewed',
:show_student_column => false,
:show_exercise_column => false,
:show_awarded_points => true,
:show_review_column => true,
:show_files_column => false,
:show_details_column => true
}
show_submission_list(other_subs, options)
%>
</section>
<% end %>
<% for review in @submission.reviews %>
<%= content_tag :div, :id => "code-review-#{review.id}", :class => 'code-review', :data => {:path => review_path(review)} do %>
<% if review.reviewer %>
<div class="reviewer">Review by <span class="reviewer"><%= review.reviewer.username %></span></div>
<% end %>
<% unless review.points_list.empty? %>
<div class="points-by-review">
<span class="label">Points added:</span>
<% for point in review.points_list %>
<%= content_tag :span, raw(h(point)) + raw(' '), :class => 'success' %>
<% end %>
</div>
<% end %>
<div class="review-body"><%= simple_format(review.review_body) %></div>
<div class="buttons">
<% if action_name == 'new' && can?(:update, review) %>
<button class="edit-review btn btn-warning"><span class="glyphicon-pencil"></span> Edit</button>
<% end %>
<% if action_name == 'new' && can?(:delete, review) %>
<button class="delete-review btn btn-danger"><span class="glyphicon-remove"></span> Delete</button>
<div class="ui-helper-hidden">
<%= link_to 'Delete', review_path(review), :method => :delete, :class => 'dangerous', :confirm => "Really delete this review?\nAny points will not be redacted." %>
</div>
<% end %>
</div>
<div class="ui-helper-clearfix">
<% if @submission.user_id == current_user.id %>
<div class="status-buttons">
<%= form_tag review_path(review), :method => 'put' do %>
<% if review.marked_as_read? %>
<input type="hidden" name="mark_as_unread" value="1" />
<button type="submit" class="btn btn-primary"><i class="glyphicon-eye-close"></i> Mark as unread</button>
<% else %>
<input type="hidden" name="mark_as_read" value="1" />
<button type="submit" class="btn btn-primary"><i class="glyphicon-eye-close"></i> Mark as read</button>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
<% end %>
</div>
</div>
<% if @new_review %>
<div class="row">
<div class="col-md-12">
<div id="review-form-dialog" class="ui-helper-hidden">
<div id="review-form">
<%= form_for @new_review, :url => submission_reviews_path(@submission) do |f| %>
<%= f.text_area :review_body, :rows => nil, :cols => nil, :placeholder => 'Write a code review here' %>
<%# this is changed by JS when switching between editing and creating %>
<input name="_method" type="hidden" value="post" />
<% unless @submission.exercise.available_review_points.empty? %>
<div class="points">
<h5>Points</h5>
<% for point in @submission.exercise.available_review_points %>
<% has_point = @submission.user.has_point?(@submission.course, point) %>
<%=
check_box_tag(
"review[points][#{point}]", 1, false, :class => 'point',
:checked => has_point,
:disabled => has_point,
:title => has_point ? "Already awarded" : nil
)
%>
<%= label_tag "review_points_#{point}", point, :title => has_point ? "Already awarded" : nil %>
<% end %>
<p class="fine-print">(note: points cannot be removed after saving)</p>
</div>
<% end %>
<div class="notification-options">
<h5>Notification</h5>
<%= check_box_tag :send_email, '1', SiteSetting.value('emails')['email_code_reviews_by_default'] %>
<label for="send_email">Notify by e-mail</label>
<%= check_box_tag :send_notification, '1', true, :disabled => true %>
<label for="send_notification">Notify in IDE</label>
</div>
<div class="buttons">
<button type="submit" class="btn btn-primary"><span class="glyphicon-hdd"></span> Save review</button>
</div>
<% end %>
</div>
</div>
</div>
</div>
<% unless @submission.message_for_reviewer.blank? %>
<h3>Message from student to reviewer</h3>
<section>
<div class="message-for-reviewer">
<%= simple_format @submission.message_for_reviewer %>
</div>
</section>
<% end %>
<div class="row">
<div class="col-md-12">
<div class="panel-group" id="testResultspanel-group">
<div class="panel panel-default">
<div class="panel-heading">
<a class="panel-group-toggle" data-toggle="collapse" data-parent="#testResultspanel-group" href="#collapseOne">
<h3>Test results</h3>
</a>
</div>
<div id="collapseOne" style="overflow: scroll;" class="panel-collapse collapse out">
<div class="panel-body">
<%= render 'submissions/details' %>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<% new_button_text = if @submission.reviews.count == 0 then 'Start code review' else 'Add another code review' end %>
<button id="new-review" class="btn btn-primary"><i class="glyphicon-file"></i> <%= new_button_text %></button>
<% if @submission.review_dismissable? %>
<div id="dismiss-review-form">
<% if @submission.reviews.count == 0 %>
<%= form_tag submission_path(@submission), :method => :put do %>
<input type="hidden" name="dismiss_review" value="1" />
<button type="submit" id="dismiss-review" data-confirm="Confirm removing submission from list of pending reviews? Note that you don't need to do this manually for old submissions."><span class="glyphicon-remove"></span> Dismiss</button>
<% end %>
<% end %>
</div>
<% end %>
<div id="review-form-reopen-handle" class="ui-helper-hidden">
<button>
<i class="glyphicon-hdd"></i> Code review
</button>
</div>
</div>
</div>
<% end %>
<div class="row">
<div class="col-md-12">
<%= render :partial => 'files/files', :locals => {:files => @files} %>
</div>
</div>
<% if @new_review %>
<script type="text/javascript">
$(document).ready(function() {
var $newReviewButton = $('#new-review');
var $reopenHandle = $('#review-form-reopen-handle');
var $dialog = $('#review-form-dialog');
var postAction = $dialog.find('form').attr('action');
<%= raw('var pointsAlreadyAwarded = ' + @submission.user.awarded_points.where(:course_id => @submission.course_id).map(&:name).to_json) + ';' %>
function doTransferEffect($from, $to, callback) {
$from.effect('transfer', {to: $to, className: 'transfer-effect'}, 500, callback);
}
function openDialog($from, afterTransfer) {
$dialog.dialog({
title: 'Code review',
width: 450,
height: 520,
dialogClass: 'big-drop-shadow',
beforeClose: function() {
$reopenHandle.show();
doTransferEffect($dialog, $reopenHandle);
}
});
$('#ui-dialog-title-review-form-dialog').
parent().
find('.ui-icon-closethick').
removeClass('ui-icon-closethick').
addClass('ui-icon-minusthick');
doTransferEffect($from, $dialog, afterTransfer);
}
function idOfCodeReview($reviewDiv) {
return $reviewDiv.attr('id').replace(/^code-review-/, '');
}
function makeDialogView($reviewDiv) {
var $textarea = $dialog.find('textarea#review_review_body');
if ($reviewDiv) { // Editing
$dialog.find('form').removeClass('editing-new-review').addClass('editing-existing-review');
$textarea.val($reviewDiv.find('.review-body').text().trim());
$('.code-review.being-edited').removeClass('being-edited');
$reviewDiv.addClass('being-edited');
$dialog.find('form').attr('action', $reviewDiv.data('path'));
$dialog.find('input[type=hidden][name=_method]').val('put');
} else {
$dialog.find('form').removeClass('editing-existing-review').addClass('editing-new-review');
$textarea.val('');
$('.code-review.being-edited').removeClass('being-edited');
$dialog.find('form').attr('action', postAction);
$dialog.find('input[type=hidden][name=_method]').val('post');
}
$dialog.find(':checkbox.point:not(:disabled)').attr('checked', false);
}
$newReviewButton.click(function() {
makeDialogView(null);
openDialog($newReviewButton, function() {
$newReviewButton.hide();
});
$reopenHandle.hide();
});
$('button.edit-review').click(function() {
var $review = $(this).parents('div.code-review');
makeDialogView($review);
var id = idOfCodeReview($review);
openDialog($review);
$newReviewButton.show();
$reopenHandle.hide();
});
$('button.delete-review').click(function() {
$(this).parents('div.code-review').find('a[data-method=delete]').click();
return false;
});
$reopenHandle.find('button').
addClass('medium-drop-shadow').
button().
click(function() {
openDialog($reopenHandle, function() {
$reopenHandle.hide();
});
});
$dialog.find('button[type=submit]').click(function() {
ReviewNotifications.disable();
return true;
});
// PagePresence.initial(function(users) {
// var otherUsers = _.without(users, getMeta('username'));
// if (otherUsers.length > 0) {
// alert('Note: ' + _.first(otherUsers) + ' is already on this page.');
// }
// });
});
</script>
<% end %>