Skip to content

Commit

Permalink
Merge pull request #4485 from dodona-edu/enhance/preload-last-submission
Browse files Browse the repository at this point in the history
Preload the latest submission in the editor on the activity show page
  • Loading branch information
jorg-vr authored Mar 22, 2023
2 parents 7669014 + f6bd47d commit 2b60f04
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 4 deletions.
17 changes: 16 additions & 1 deletion app/assets/javascripts/exercise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function initExerciseDescription(): void {
initCodeFragments();
}

function initExerciseShow(exerciseId: number, programmingLanguage: string, loggedIn: boolean, editorShown: boolean, courseId: number, _deadline: string, baseSubmissionsUrl: string): void {
function initExerciseShow(exerciseId: number, programmingLanguage: string, loggedIn: boolean, editorShown: boolean, courseId: number, _deadline: string, baseSubmissionsUrl: string, boilerplate: string): void {
let editor: AceAjax.Editor;
let lastSubmission: string;
let lastTimeout: number;
Expand All @@ -140,6 +140,7 @@ function initExerciseShow(exerciseId: number, programmingLanguage: string, logge
initDeadlineTimeout();
enableSubmissionTableLinks();
swapActionButtons();
initRestoreBoilerplateButton(boilerplate);
}

// submit source code if button is clicked on editor panel
Expand Down Expand Up @@ -444,6 +445,20 @@ function initExerciseShow(exerciseId: number, programmingLanguage: string, logge
showDeadlineAlerts();
}

function initRestoreBoilerplateButton(boilerplate: string): void {
const restoreWarning = document.getElementById("restore-boilerplate");
if (!restoreWarning) {
return;
}

const resetButton = restoreWarning.querySelector("a");
resetButton.addEventListener("click", () => {
editor.setValue(boilerplate);
editor.focus();
restoreWarning.hidden = true;
});
}

init();
}

Expand Down
6 changes: 6 additions & 0 deletions app/assets/stylesheets/models/activities.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ center img {
}
}

#restore-boilerplate {
a {
cursor: pointer;
}
}

pre {
position: relative;

Expand Down
7 changes: 5 additions & 2 deletions app/controllers/activities_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,20 @@ def show
@submissions = @activity.submissions.includes(:annotations)
@submissions = @submissions.in_course(@course) if @course.present? && current_user&.member_of?(@course)
@submissions = @submissions.of_user(current_user) if current_user
@submissions = policy_scope(@submissions).paginate(page: parse_pagination_param(params[:page]))
@submissions = policy_scope(@submissions)
if params[:edit_submission]
@edit_submission = Submission.find(params[:edit_submission])
authorize @edit_submission, :edit?
elsif @submissions.any?
@last_submission = @submissions.first
end
@submissions = @submissions.paginate(page: parse_pagination_param(params[:page]))
if params[:from_solution]
@solution = @activity.solutions[params[:from_solution]]
authorize @activity, :info?
end

@code = @edit_submission.try(:code) || @solution || @activity.boilerplate
@code = @edit_submission.try(:code) || @solution || @last_submission.try(:code) || @activity.boilerplate
elsif @activity.content_page?
@read_state = if current_user&.member_of?(@course)
@activity.activity_read_states.find_by(user: current_user, course: @course)
Expand Down
11 changes: 10 additions & 1 deletion app/views/activities/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ end %>
<%= t('.deadline_passed', deadline: @series.deadline.today? ? @series.deadline.strftime('%R') : @series.deadline.strftime('%F %R')) %>
</div>
<% end %>
<% if !@edit_submission && !@solution && @last_submission %>
<div class="alert alert-info" id="restore-boilerplate">
<%= t ".preloaded_info" %>
<a >
<%= t(@activity.boilerplate ? ".preloaded_restore" : ".preloaded_clear") %>
</a>
</div>
<% end %>
<div id="editor-window" class='tex2jax_ignore'>
<div id="editor-text"><%= @code %></div>
</div>
Expand Down Expand Up @@ -173,7 +181,8 @@ end %>
<%= policy(@activity).submit? || !user_signed_in? %>,
<%= @course&.id || "null" %>,
<%= raw "\"#{@series&.deadline&.httpdate}\"" || "null" %>,
"<%= submissions_url %>"
"<%= submissions_url %>",
`<%= (@activity.exercise? && raw(@activity.boilerplate&.gsub!('`', '\\\\`')))|| "" %>`,
);
});
</script>
3 changes: 3 additions & 0 deletions config/locales/views/activities/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ en:
back_to_course_actionable: Go back to course
mark_as_read: Mark as read
read_at: "Marked as read on %{timestamp}"
preloaded_info: "We have preloaded your latest submission into the editor."
preloaded_clear: Clear editor.
preloaded_restore: Restore the boilerplate code.
series_activities_add_table:
course_added_to_usable: "Adding this exercise will allow this course to use all of the private exercises in this exercise's repository. Are you sure?"
edit:
Expand Down
3 changes: 3 additions & 0 deletions config/locales/views/activities/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ nl:
back_to_course_actionable: Ga terug naar de cursus
mark_as_read: Markeren als gelezen
read_at: "Gelezen op %{timestamp}"
preloaded_info: We hebben jouw laatste oplossing ingeladen in de editor.
preloaded_clear: Maak de editor leeg.
preloaded_restore: Herstel de boilerplate-code.
series_activities_add_table:
course_added_to_usable: "Deze oefening toevoegen zal deze cursus toegang geven tot alle privΓ© oefeningen in de repository van deze oefening. Ben je zeker?"
edit:
Expand Down
60 changes: 60 additions & 0 deletions test/system/activities_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'capybara/minitest'
require 'application_system_test_case'

class ActivitiesTest < ApplicationSystemTestCase
include Devise::Test::IntegrationHelpers
# Make the Capybara DSL available in all integration tests
include Capybara::DSL
# Make `assert_*` methods behave like Minitest assertions
include Capybara::Minitest::Assertions

setup do
@instance = exercises(:python_exercise)
@user = users(:zeus)
sign_in @user
end

test 'should show exercise' do
visit exercise_path(id: @instance.id)
assert_text @instance.name_en
end

test 'should show boilerplate in code editor' do
@instance.stubs(:boilerplate).returns('boilerplate') do
visit exercise_path(id: @instance.id)
assert_text 'boilerplate'
end
end

test 'show latest submission in code editor' do
create(:submission, exercise: @instance, user: @user, status: :correct, code: 'print("hello")')
visit exercise_path(id: @instance.id)
assert_text 'print("hello")'
end

test 'should show message to clear editor if latest submission is shown' do
create(:submission, exercise: @instance, user: @user, status: :correct, code: 'print("hello")')
visit exercise_path(id: @instance.id)
assert_text 'Clear editor'
end

test 'should show message to restore boilerplate if latest submission is shown' do
@instance.stubs(:boilerplate).returns('boilerplate') do
create(:submission, exercise: @instance, user: @user, status: :correct, code: 'print("hello")')
visit exercise_path(id: @instance.id)
assert_text 'Restore boilerplate'
end
end

test 'should not break on complex unicode characters' do
@instance.stubs(:boilerplate).returns('`<script>alert("πŸ˜€")</script>`') do
visit exercise_path(id: @instance.id)
assert_text '`<script>alert("πŸ˜€")</script>`'

create(:submission, exercise: @instance, user: @user, status: :correct, code: 'print("πŸ˜€")')
visit exercise_path(id: @instance.id)
assert_text 'print("πŸ˜€")'
assert_text 'Restore boilerplate'
end
end
end

0 comments on commit 2b60f04

Please sign in to comment.