<%= alert_heading %>
diff --git a/app/views/submissions/_assigned_evaluators.html.erb b/app/views/submissions/_assigned_evaluators.html.erb
new file mode 100644
index 00000000..d10f2dea
--- /dev/null
+++ b/app/views/submissions/_assigned_evaluators.html.erb
@@ -0,0 +1,58 @@
+
+ <% rand = SecureRandom.hex(8) %>
+
">
+
+ Assigned Evaluators
+
+
+
+
+ <% assigned_evaluators = @submission.evaluators.where("evaluator_submission_assignments.status" => ["assigned", "recused"]) %>
+ <% if assigned_evaluators.any? %>
+
+ <% else %>
+
+
+
+ You currently do not have any evaluators assigned to this submission. Please use the section below to review and assign available evaluators.
+
+
+
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/submissions/_available_evaluators.html.erb b/app/views/submissions/_available_evaluators.html.erb
new file mode 100644
index 00000000..dd2d4fc6
--- /dev/null
+++ b/app/views/submissions/_available_evaluators.html.erb
@@ -0,0 +1,53 @@
+
+ <% rand = SecureRandom.hex(8) %>
+
">
+
+ Available Evaluators
+
+
+
+
+ <% if @submission.available_evaluators.any? %>
+ <% @submission.available_evaluators.each_with_index do |evaluator, i| %>
+
+
+ <%= "#{evaluator.first_name} #{evaluator.last_name}" %>
+ <%= evaluator.email %>
+
+
+ <% assignment = evaluator.evaluator_submission_assignments.where(submission_id: @submission.id).first %>
+ <% if assignment %>
+ <%= form_with url: phase_evaluator_submission_assignment_path(@submission.phase, assignment.id), method: "PATCH" do |f| %>
+ <%= f.hidden_field :phase_id, value: @submission.phase.id %>
+ <%= f.hidden_field :status, value: "assigned" %>
+ <%= f.submit "Reassign", class: "usa-button font-body-2xs margin-top-1" %>
+ <% end %>
+ <% else %>
+ <%= form_with url: phase_evaluator_submission_assignments_path(@submission.phase) do |f| %>
+ <%= f.hidden_field :evaluator_id, value: evaluator.id %>
+ <%= f.hidden_field :submission_id, value: @submission.id %>
+ <%= f.submit "Assign", class: "usa-button font-body-2xs margin-top-1" %>
+ <% end %>
+ <% end %>
+
+
+ <% if i < @submission.available_evaluators.length - 1 %>
+
+ <% end %>
+ <% end %>
+ <% else %>
+
+
+
+ There are no evaluators available for this submission. Please visit Evaluation Panel section to manage your list of available evaluators.
+
+
+
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/submissions/_details_form.html.erb b/app/views/submissions/_details_form.html.erb
new file mode 100644
index 00000000..cee25d68
--- /dev/null
+++ b/app/views/submissions/_details_form.html.erb
@@ -0,0 +1,53 @@
+
+ <% rand = SecureRandom.hex(8) %>
+ <%= form_with(model: @submission, url: submission_path(@submission), class: "maxw-mobile-lg") do |form| %>
+
+ "
+ value="selected"
+ <%= "disabled" if @submission.evaluators_assigned? %>
+ <%= "checked" if @submission.judging_status.in?(["selected", "winner"]) %>
+ data-action="change->submission-details#eligibleCheck"
+ data-submission-details-target="eligibleCheckbox"
+ />
+ "
+ >This submission is eligible for evaluation.
+ Check the box if the submission is pre-screened and is eligible for the evaluation process.
+
+
+ "
+ type="checkbox"
+ <%= "disabled" if @submission.evaluations_missing_or_incomplete? %>
+ <%= "checked" if @submission.judging_status == "winner" %>
+ data-action="change->submission-details#selectedCheck"
+ data-submission-details-target="winnerCheckbox"
+ />
+ "
+ >This submission is selected to advance.
+ Check the box to select this submission to advance or for award after all evaluations are completed.
+
+
+
+ <%= form.label :comments, "Comments and notes:", class: "usa-label", for: "#{rand}-comments" %>
+ <%= form.text_area :comments, class: "usa-textarea", default: @submission.comments, id: "#{rand}-comments" %>
+
+
+ Save
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/submissions/_submission_details.html.erb b/app/views/submissions/_submission_details.html.erb
index d71ae715..34726d5b 100644
--- a/app/views/submissions/_submission_details.html.erb
+++ b/app/views/submissions/_submission_details.html.erb
@@ -1,53 +1,4 @@
-
- <% rand = SecureRandom.hex(8) %>
- <%= form_with(model: @submission, url: submission_path(@submission), class: "maxw-mobile-lg") do |form| %>
-
- "
- value="selected"
- <%= if @submission.judging_status == "winner" then "disabled" end %>
- <%= "checked" if @submission.judging_status.in?(["selected", "winner"]) %>
- data-action="change->submission-details#eligibleCheck"
- data-submission-details-target="eligibleCheckbox"
- />
- "
- >This submission is eligible for evaluation.
- Check the box if the submission is pre-screened and is eligible for the evaluation process.
-
-
- "
- type="checkbox"
- <%= "disabled" unless @submission.judging_status.in?(["selected", "winner"]) %>
- <%= "checked" if @submission.judging_status == "winner" %>
- data-action="change->submission-details#selectedCheck"
- data-submission-details-target="winnerCheckbox"
- />
- "
- >This submission is selected to advance.
- Check the box to select this submission to advance or for award after all evaluations are completed.
-
-
-
- <%= form.label :comments, "Comments and notes:", class: "usa-label" %>
- <%= form.text_area :comments, class: "usa-textarea", default: @submission.comments %>
-
-
- Save
-
- <% end %>
-
\ No newline at end of file
+<%= render partial: 'details_form' %>
+<% if @submission.judging_status.in?(["selected", "winner"]) %>
+ <%= render partial: 'submission_evaluation' %>
+<% end %>
diff --git a/app/views/submissions/_submission_evaluation.html.erb b/app/views/submissions/_submission_evaluation.html.erb
new file mode 100644
index 00000000..3331348d
--- /dev/null
+++ b/app/views/submissions/_submission_evaluation.html.erb
@@ -0,0 +1,10 @@
+
Submission Evaluation
+<% if @submission.phase.evaluation_form.nil? %>
+ <%= render 'shared/alert_error', alert_heading: t('alerts.no_evaluation_form.heading'), alert_text: t('alerts.no_evaluation_form.text') %>
+<% else %>
+ <%= render partial: 'assigned_evaluators' %>
+ <%= render partial: 'available_evaluators' %>
+
+ <%= link_to "Manage Evaluators", phase_evaluators_path(@submission.phase), class: "margin-y-1" %>
+
+<% end %>
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a3839cf4..89b314dd 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -32,6 +32,7 @@ en:
already_logged_in_notice: "You are already logged in."
evaluation_form_destroyed: "Evaluation form was successfully destroyed."
evaluation_form_saved: "Evaluation form was saved successfully."
+ evaluator_submission_assignment_saved: "Submission assignment was saved succesfully."
comments_saved: "Comments saved succesfully."
submission_updated: "Submission was updated successfully."
login_error: "There was an issue with logging in. Please try again."
@@ -75,11 +76,14 @@ en:
unassigned_submissions: "A list of recused and unassigned submissions. Reassigning a user to a submission will make the submission available for the user to evaluate."
empty_state: "There currently are no assigned submissions to this evaluator. Please assign submissions to this evaluator to view."
assigned:
- success: "Evaluator reassigned successfully"
- failure: "Failed to reassign evaluator"
+ success: "Evaluator assigned successfully"
+ failure: "Failed to assign evaluator"
unassigned:
success: "Evaluator unassigned successfully"
- failure: "Failed to unassign evaluator"
+ failure: "Failed to unassign evaluator"
+ recused_unassigned:
+ success: "Recused evaluator unassigned successfully"
+ failure: "Failed to unassign evaluator"
evaluations:
unique_user_for_evaluation_form_and_submission_error: "already has an evaluation for this form and submission"
unique_evaluator_submission_assignment: "already has an evaluation"
diff --git a/config/routes.rb b/config/routes.rb
index a2c4adfd..43a0f0a4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -26,7 +26,7 @@
post 'resend_invite'
end
end
- resources :evaluator_submission_assignments, only: [:index, :update]
+ resources :evaluator_submission_assignments, only: [:index, :update, :create]
end
resources :submissions, only: [:index, :show, :update]
diff --git a/db/structure.sql b/db/structure.sql
index 3fbc90c6..fb9cf75d 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -1109,7 +1109,7 @@ CREATE TABLE public.submissions (
description_delta text,
brief_description_delta text,
pdf_reference character varying(255),
- comments text
+ comments character varying
);
diff --git a/spec/models/submission_spec.rb b/spec/models/submission_spec.rb
index fc3e416f..b8acf1c1 100644
--- a/spec/models/submission_spec.rb
+++ b/spec/models/submission_spec.rb
@@ -69,4 +69,42 @@
end
end
end
+
+ describe "#available_evaluators" do
+ let(:challenge) { create(:challenge) }
+ let(:phase) { create(:phase, challenge:) }
+ let(:evaluator) do
+ evaluator = create(:user, role: "evaluator")
+ evaluator.challenge_phases_evaluators.create(challenge:, phase:)
+ evaluator
+ end
+ let(:submission) { create(:submission, challenge:, phase:) }
+
+ it "includes evaluators that have not been assigned yet" do
+ expect(submission.phase.evaluators).to include(evaluator)
+ expect(EvaluatorSubmissionAssignment.find_by(evaluator:, submission:)).to be_nil
+ expect(submission.available_evaluators).to include(evaluator)
+ end
+
+ it "includes evaluators that have been unassigned from the submission" do
+ expect(submission.phase.evaluators).to include(evaluator)
+ submission.evaluator_submission_assignments.create(evaluator:, submission:, status: "unassigned")
+ expect(submission.available_evaluators).to include(evaluator)
+ end
+
+ it "does not include evaluators that have been assigned" do
+ expect(submission.phase.evaluators).to include(evaluator)
+ submission.evaluator_submission_assignments.create(evaluator:, submission:, status: "assigned")
+ expect(submission.available_evaluators).not_to include(evaluator)
+ end
+
+ it "does not include evaluators that have recused" do
+ expect(submission.phase.evaluators).to include(evaluator)
+ esa = submission.evaluator_submission_assignments.create(evaluator:, submission:, status: "recused")
+ expect(submission.available_evaluators).not_to include(evaluator)
+ # unassigned after recusing
+ esa.update!(status: "recused_unassigned")
+ expect(submission.available_evaluators).not_to include(evaluator)
+ end
+ end
end
diff --git a/spec/requests/pages_spec.rb b/spec/requests/pages_spec.rb
index a8952447..02c272ae 100644
--- a/spec/requests/pages_spec.rb
+++ b/spec/requests/pages_spec.rb
@@ -2,40 +2,40 @@
RSpec.describe "PagesController" do
it "get root renders successfully" do
- stub_request(:get, PagesController::HOST + PagesController::BASE_URL + "/").
- to_return(status: 200, body: "", headers: {})
+ stub_request(:get, "#{PagesController::HOST}#{PagesController::BASE_URL}/").
+ to_return(status: 200, body: "", headers: {})
get "/"
expect(response).to be_ok
end
it "removes full paths to assets so they proxy too" do
- stub_request(:get, PagesController::HOST + PagesController::BASE_URL + "/").
- to_return(status: 200, body: PagesController::HOST + PagesController::BASE_URL, headers: {})
+ stub_request(:get, "#{PagesController::HOST}#{PagesController::BASE_URL}/").
+ to_return(status: 200, body: PagesController::HOST + PagesController::BASE_URL, headers: {})
get "/"
expect(response.body).to eq("/")
end
it "works for minified js assets" do
- stub_request(:get, PagesController::HOST + PagesController::BASE_URL + "/assets/uswds.min.js").
- to_return(status: 200, body: "", headers: {})
+ stub_request(:get, "#{PagesController::HOST}#{PagesController::BASE_URL}/assets/uswds.min.js").
+ to_return(status: 200, body: "", headers: {})
get "/assets/uswds.min.js"
expect(response).to be_ok
end
it "works for image assets" do
- stub_request(:get, PagesController::HOST + PagesController::BASE_URL + "/assets/logo.svg").
- to_return(status: 200, body: "", headers: {})
+ stub_request(:get, "#{PagesController::HOST}#{PagesController::BASE_URL}/assets/logo.svg").
+ to_return(status: 200, body: "", headers: {})
get "/assets/logo.svg"
expect(response).to be_ok
end
it "404s to the dashboard" do
- stub_request(:get, PagesController::HOST + PagesController::BASE_URL + "/not_found/").
- to_return(status: 404, body: "", headers: {})
+ stub_request(:get, "#{PagesController::HOST}#{PagesController::BASE_URL}/not_found/").
+ to_return(status: 404, body: "", headers: {})
get "/not_found"
expect(response).to redirect_to("/dashboard")
diff --git a/spec/system/submission_details_spec.rb b/spec/system/submission_details_spec.rb
index c58a9e16..c10e3962 100644
--- a/spec/system/submission_details_spec.rb
+++ b/spec/system/submission_details_spec.rb
@@ -7,7 +7,7 @@
let(:user) { create_user(role: "challenge_manager") }
let(:challenge) { create_challenge(user: user, title: "Boston Tea Party Cleanup") }
let(:phase) { create(:phase, challenge: challenge) }
- let(:submission) { create(:submission, manager: user, challenge:, phase:) }
+ let(:submission) { create(:submission, challenge:, phase:, manager: user, status: "submitted") }
let(:fake_comments) { Faker::Lorem.sentence }
before do
@@ -60,5 +60,55 @@
expect(page).to have_css("p.usa-alert__text", text: "Submission was updated successfully.")
assert_text(fake_comments)
end
+
+ it "displays a list of available evaluators" do
+ evaluator1 = create_user(role: "evaluator")
+ evaluator2 = create_user(role: "evaluator")
+ challenge.challenge_phases_evaluators.create(user: evaluator1, phase: phase)
+ challenge.challenge_phases_evaluators.create(user: evaluator2, phase: phase)
+ evaluation_form = create(:evaluation_form, phase: phase, challenge: challenge)
+ visit submission_path(submission)
+ find_by_id('eligible-for-evaluation').click
+ click_on('Save')
+
+ expect(page).to have_content("Available Evaluators")
+ expect(page).to have_content(evaluator1.email)
+ expect(page).to have_content(evaluator2.email)
+ end
+
+ it "assigns and unassigns an evaluator to the submission" do
+ evaluator = create_user(role: "evaluator")
+ challenge.challenge_phases_evaluators.create(user: evaluator, phase: phase)
+ evaluation_form = create(:evaluation_form, phase: phase, challenge: challenge)
+ visit submission_path(submission)
+ find_by_id('eligible-for-evaluation').click
+ click_on('Save')
+
+ expect(page).to have_content("You currently do not have any evaluators assigned to this submission.")
+
+ click_on('Assign')
+ expect(page).to have_css("p.usa-alert__text", text: "Evaluator assigned successfully")
+
+ click_on('Unassign')
+ expect(page).to have_css("p.usa-alert__text", text: "Evaluator unassigned successfully")
+ end
+
+ it "unassigns a recused evaluator from the submission" do
+ evaluator = create_user(role: "evaluator")
+ challenge.challenge_phases_evaluators.create(user: evaluator, phase: phase)
+ evaluation_form = create(:evaluation_form, phase: phase, challenge: challenge)
+ visit submission_path(submission)
+ find_by_id('eligible-for-evaluation').click
+ click_on('Save')
+
+ click_on('Assign')
+ expect(page).to have_css("p.usa-alert__text", text: "Evaluator assigned successfully")
+
+ EvaluatorSubmissionAssignment.where(user_id: evaluator.id, submission_id: submission.id).update!(status: "recused")
+
+ visit submission_path(submission)
+ click_on('Unassign')
+ expect(page).to have_css("p.usa-alert__text", text: "Recused evaluator unassigned successfully")
+ end
end
-end
+end
\ No newline at end of file