Skip to content

Commit

Permalink
Make evaluation creation a full stepper
Browse files Browse the repository at this point in the history
Also change the edit page to lead back to a stepper.
  • Loading branch information
chvp committed Sep 9, 2021
1 parent 85012a4 commit e5742aa
Show file tree
Hide file tree
Showing 23 changed files with 368 additions and 393 deletions.
86 changes: 65 additions & 21 deletions app/assets/javascripts/evaluation.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
import { fetch } from "util.js";

export function interceptAddMultiUserClicks(): void {
let running = false;
document.querySelectorAll(".user-select-option a").forEach(option => {
option.addEventListener("click", async event => {
if (!running) {
running = true;
event.preventDefault();
const button = option.querySelector(".button");
const loader = option.querySelector(".loader");
button.classList.add("hidden");
loader.classList.remove("hidden");
const response = await fetch(option.getAttribute("href"), { method: "POST" });
eval(await response.text());
loader.classList.add("hidden");
button.classList.remove("hidden");
running = false;
}
});
});
}

export function initCheckboxes(): void {
document.querySelectorAll(".evaluation-users-table .user-row").forEach(el => initCheckbox(el));
}
Expand All @@ -39,3 +18,68 @@ export function initCheckbox(row: HTMLTableRowElement): void {
}
});
}

export function initEvaluationStepper(): void {
const evalPanelElement = document.querySelector("#info-panel .panel-collapse");
const evalPanel = new bootstrap.Collapse(evalPanelElement, { toggle: false });
const userPanelElement = document.querySelector("#users-panel .panel-collapse");
const userPanel = new bootstrap.Collapse(userPanelElement, { toggle: false });
const scorePanelElement = document.querySelector("#items-panel .panel-collapse");
const scorePanel = new bootstrap.Collapse(scorePanelElement, { toggle: false });

function init(): void {
window.dodona.toUsersStep = toUsersStep;

evalPanelElement.addEventListener("show.bs.collapse", function () {
userPanel.hide();
scorePanel.hide();
});
userPanelElement.addEventListener("show.bs.collapse", function () {
evalPanel.hide();
scorePanel.hide();
});
scorePanelElement.addEventListener("show.bs.collapse", function () {
evalPanel.hide();
userPanel.hide();
});

document.querySelector("#users-step-finish-button").addEventListener("click", function () {
userPanel.hide();
scorePanel.show();
});
}

function toUsersStep(): void {
interceptAddMultiUserClicks();
initCheckboxes();
document.querySelector("#deadline-group .btn").classList.add("disabled");
document.querySelector("#users-panel").classList.remove("hidden");
document.querySelector("#items-panel").classList.remove("hidden");
evalPanel.hide();
userPanel.show();
}

function interceptAddMultiUserClicks(): void {
let running = false;
document.querySelectorAll(".user-select-option a").forEach(option => {
option.addEventListener("click", async event => {
if (!running) {
running = true;
event.preventDefault();
const button = option.querySelector(".button");
const loader = option.querySelector(".loader");
button.classList.add("hidden");
loader.classList.remove("hidden");
const response = await fetch(option.getAttribute("href"), { method: "POST" });
eval(await response.text());
loader.classList.add("hidden");
button.classList.remove("hidden");
running = false;
}
});
});
}


init();
}
33 changes: 16 additions & 17 deletions app/controllers/evaluations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class EvaluationsController < ApplicationController
include SeriesHelper
include EvaluationHelper

before_action :set_evaluation, only: %i[show edit add_users update destroy overview set_multi_user add_user remove_user mark_undecided_complete export_grades modify_grading_visibility]
before_action :set_evaluation, only: %i[show edit update destroy overview set_multi_user add_user remove_user mark_undecided_complete export_grades modify_grading_visibility]
before_action :set_series, only: %i[new]

has_scope :by_institution, as: 'institution_id'
Expand All @@ -16,7 +16,7 @@ class EvaluationsController < ApplicationController
end

def show
redirect_to add_users_evaluation_path(@evaluation) if @evaluation.users.count == 0
redirect_to edit_evaluation_path(@evaluation) if @evaluation.users.count == 0
@feedbacks = @evaluation.evaluation_sheet
@users = apply_scopes(@evaluation.users)
@course_labels = CourseLabel.where(course: @evaluation.series.course)
Expand All @@ -36,6 +36,7 @@ def new
end

def edit
@should_confirm = params[:confirm].present?
@course = @evaluation.series.course
@course_labels = CourseLabel.where(course: @course)
@course_memberships = apply_scopes(@course.course_memberships)
Expand All @@ -57,30 +58,28 @@ def edit
@title = I18n.t('evaluations.edit.title')
end

def add_users
edit
@user_count_course = @evaluation.series.course.enrolled_members.count
@user_count_series = @evaluation.series.course.enrolled_members.where(id: Submission.where(exercise_id: @evaluation.exercises, course_id: @evaluation.series.course_id).select('DISTINCT user_id')).count
@crumbs = [
[@evaluation.series.course.name, course_url(@evaluation.series.course)],
[@evaluation.series.name, breadcrumb_series_path(@evaluation.series, current_user)],
[I18n.t('evaluations.show.evaluation'), evaluation_url(@evaluation)],
[I18n.t('evaluations.add_users.title'), '#']
]
@title = I18n.t('evaluations.add_users.title')
end

def create
@evaluation = Evaluation.new(permitted_attributes(Evaluation))
authorize @evaluation
@evaluation.exercises = @evaluation.series.exercises
@course = @evaluation.series.course
@course_labels = CourseLabel.where(course: @course)
@course_memberships = apply_scopes(@course.course_memberships)
.includes(:course_labels, user: [:institution])
.order(status: :asc)
.order(Arel.sql('users.permission ASC'))
.order(Arel.sql('users.last_name ASC'), Arel.sql('users.first_name ASC'))
.where(status: %i[course_admin student])
.paginate(page: parse_pagination_param(params[:page]))

respond_to do |format|
if @evaluation.save
format.html { redirect_to add_users_evaluation_path(@evaluation) }
@user_count_course = @evaluation.series.course.enrolled_members.count
@user_count_series = @evaluation.series.course.enrolled_members.where(id: Submission.where(exercise_id: @evaluation.exercises, course_id: @evaluation.series.course_id).select('DISTINCT user_id')).count
format.js {}
format.json { render :show, status: :created, location: @evaluation }
else
format.html { render :new }
format.js { render :new }
format.json { render json: @evaluation.errors, status: :unprocessable_entity }
end
end
Expand Down
15 changes: 1 addition & 14 deletions app/controllers/score_items_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@ class ScoreItemsController < ApplicationController
before_action :set_score_item, only: %i[destroy update]
before_action :set_evaluation

def index
@crumbs << [I18n.t('score_items.index.title'), '#']
@title = I18n.t('score_items.index.title')
end

def new
@crumbs << [I18n.t('score_items.new.title'), '#']
@title = I18n.t('score_items.new.title')
end

def copy
from = EvaluationExercise.find(params[:copy][:from])
to = EvaluationExercise.find(params[:copy][:to])
Expand Down Expand Up @@ -67,12 +57,9 @@ def add_all
@evaluation.transaction do
@evaluation.evaluation_exercises.each do |evaluation_exercise|
new_score_item = @score_item.dup
new_score_item.evaluation_exercise = evaluation_exercise
new_score_item.save
evaluation_exercise.score_items << new_score_item
end
end

redirect_back fallback_location: new_evaluation_score_item_path(@evaluation)
end

def destroy
Expand Down
5 changes: 2 additions & 3 deletions app/javascript/packs/evaluation.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { initDeadlinePicker } from "series.js";
import { interceptAddMultiUserClicks, initCheckboxes, initCheckbox } from "evaluation.ts";
import { initCheckbox, initEvaluationStepper } from "evaluation.ts";
import FeedbackActions from "feedback/actions";

window.dodona.initDeadlinePicker = initDeadlinePicker;
window.dodona.initCheckboxes = initCheckboxes;
window.dodona.initCheckbox = initCheckbox;
window.dodona.interceptAddMultiUserClicks = interceptAddMultiUserClicks;
window.dodona.FeedbackActions = FeedbackActions;
window.dodona.initEvaluationStepper = initEvaluationStepper;
62 changes: 62 additions & 0 deletions app/views/evaluations/_add_users.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<div class="stepper-part evaluation-user-select">
<div class="row">
<div class="col-lg-6 col-md-12 order-lg-1">
<div class="callout callout-info">
<h4><%= t('evaluations.add_users.explanation_title') %></h4>
<p><%= t('evaluations.add_users.explanation_part1') %></p>
<p><%= t('evaluations.add_users.explanation_part2') %></p>
</div>
</div>
<div class="col-lg-6 col-md-12 order-lg-0">
<div class="card-subtitle">
<h4><%= t('evaluations.edit_users.mass_edit') %></h4>
</div>
<div class="row">
<div class="col-6">
<div class="user-select-option">
<%= link_to set_multi_user_evaluation_path(@evaluation, type: 'enrolled', format: :js) do %>
<%= t('evaluations.add_users.users_in_course_html', count: @user_count_course) %>
<div class="clearfix"></div>
<i class="loader mdi mdi-spin mdi-loading hidden"></i>
<div class="button btn-text"><%= t('.select_users') %></div>
<% end %>
</div>
</div>
<div class="col-6">
<div class="user-select-option">
<%= link_to set_multi_user_evaluation_path(@evaluation, type: 'submitted', format: :js) do %>
<%= t('evaluations.add_users.users_submitted_html', count: @user_count_series) %>
<div class="clearfix"></div>
<i class="loader mdi mdi-spin mdi-loading hidden"></i>
<div class="button btn-text"><%= t('.select_users') %></div>
<% end %>
</div>
</div>
</div>
<p class="selected-users">
<span id="users-count-wrapper">
<%= t("evaluations.edit_users.users_selected_html", count: @evaluation.users.count) %>
</span>
<%= link_to t('evaluations.edit_users.clear'), set_multi_user_evaluation_path(@evaluation, type: 'none', format: :js), remote: true, method: :post %>.
</p>
</div>
</div>
</div>
<div class="stepper-part">
<div class="card-supporting-text">
<%= render partial: 'layouts/searchbar', locals: {
baseUrl: edit_evaluation_url(@evaluation),
eager: false,
course_labels: @course_labels,
institutions: Institution.of_course_by_members(@course),
} %>
<div id="users-table-wrapper">
<%= render partial: 'members_table',
locals: {
course_memberships: @course_memberships,
pagination_opts: @pagination_opts,
confirm: false
} %>
</div>
</div>
</div>
14 changes: 0 additions & 14 deletions app/views/evaluations/_edit_users.html.erb

This file was deleted.

4 changes: 2 additions & 2 deletions app/views/evaluations/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<% content_for :javascripts do %>
<%= javascript_pack_tag 'evaluation' %>
<% end %>
<%= form_for evaluation, html: { class: "form-horizontal feedback-form" } do |f| %>
<%= form_for evaluation, html: { class: "form-horizontal feedback-form" }, remote: true do |f| %>
<div>
<%= f.hidden_field :series_id %>
<h4 class="evaluation-form-title"><%= evaluation.series.name %> <span class="small"><%= evaluation.series.course.name %></span></h4>
Expand All @@ -17,7 +17,7 @@
<div class='col-sm-12'>
<div class="input-group" id='deadline-group' data-wrap=true data-enable-time=true data-time_24hr=true data-max-date="<%= Time.current.httpdate %>">
<%= f.text_field :deadline, class: "form-control", 'data-input': true %>
<button class="btn btn-secondary" type="button" data-toggle><i class='mdi mdi-calendar-blank mdi-18'></i></button>
<button class="btn btn-secondary" type="button" data-toggle <%= "disabled" if local_assigns[:readonly] %>><i class='mdi mdi-calendar-blank mdi-18'></i></button>
</div>
</div>
<span class="help-block col-sm-12"><%= t(".deadline-help_html") %></span>
Expand Down
2 changes: 1 addition & 1 deletion app/views/evaluations/_members_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
<p class="text-center text-muted lead table-placeholder"><%= t 'users.index.no_users' %></p>
<% end %>
<center>
<%= page_navigation_links course_memberships, true, 'evaluations', action: 'edit' %>
<%= page_navigation_links course_memberships, true, 'evaluations', { id: @evaluation.id }, 'edit' %>
</center>
56 changes: 56 additions & 0 deletions app/views/evaluations/_score_items.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<div class="panel-body">
<div class="stepper-part">
<div class="score-item-toolbar">
<div class="score-item-toolbar-tools">
<p class="description-text">
<%= t 'score_items.new.second_explanation' %><br>
<span class="summary-text">
<%= t('score_items.new.summary_html', count: @evaluation.score_items.count, score: format_score(@evaluation.maximum_score)) %>
</span>
</p>
<div class="btn-group actions">
<a class="btn btn-icon dropdown-toggle" data-bs-toggle="dropdown">
<i class="mdi mdi-dots-vertical"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<%= link_to modify_grading_visibility_evaluation_path(@evaluation, visible: true), method: :post, class: "dropdown-item" do %>
<i class="mdi mdi-eye mdi-18"></i>
<%= t("score_items.new.show_all") %>
<% end %>
</li>
<li>
<%= link_to modify_grading_visibility_evaluation_path(@evaluation, visible: false), method: :post, class: "dropdown-item" do %>
<i class="mdi mdi-eye-off mdi-18"></i>
<%= t("score_items.new.hide_all") %>
<% end %>
</li>
<li>
<a href="#add-score-item-to-all" data-bs-toggle="modal" class="dropdown-item">
<i class="mdi mdi-table-row-plus-after mdi-18"></i>
<%= t 'score_items.new.add_all' %>
</a>
</li>
</ul>
</div>
</div>
</div>
<% @evaluation.evaluation_exercises.each do |evaluation_exercise| %>
<div id="card-<%= evaluation_exercise.id %>">
<%= render 'score_items/exercise', evaluation_exercise: evaluation_exercise, new: nil %>
</div>
<% end %>
</div>
<div class="stepper-actions stepper-border">
<%= link_to t('score_items.new.to_evaluation'), evaluation_path(@evaluation), class: "btn btn-text btn-primary" %>
</div>
</div>
<div class="modal fade" id="add-score-item-to-all" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<%= render 'score_items/form',
score_item: ScoreItem.new,
evaluation_exercise: nil,
title: t("score_items.new.add_all"),
form_options: { url: add_all_evaluation_score_items_path(@evaluation), remote: true } %>
</div>
</div>
Loading

0 comments on commit e5742aa

Please sign in to comment.