Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[129, 60, 130] Evaluation Form Model, Migration, CRUD, Responsive List View #169

Merged
merged 20 commits into from
Sep 27, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 93 additions & 1 deletion app/controllers/evaluation_forms_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,97 @@
# frozen_string_literal: true

class EvaluationFormsController < ApplicationController
def index; end
before_action :set_evaluation_form, only: %i[show edit update destroy]

# GET /evaluation_forms or /evaluation_forms.json
def index
@evaluation_forms = EvaluationForm.all
end

# GET /evaluation_forms/1 or /evaluation_forms/1.json
def show; end

# GET /evaluation_forms/new
def new
@evaluation_form = EvaluationForm.new
end

# GET /evaluation_forms/1/edit
def edit; end

# POST /evaluation_forms or /evaluation_forms.json
def create
@evaluation_form = EvaluationForm.new(evaluation_form_params)

respond_to do |format|
if @evaluation_form.save
format.html do
redirect_to evaluation_form_url(@evaluation_form), notice: "Evaluation form was successfully created."
end
format.json { render :show, status: :created, location: @evaluation_form }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @evaluation_form.errors, status: :unprocessable_entity }
end
end
end

# NOTE: to reviewer: the following method works but it's impossible to use because there's a unique index on
# challenge_id and challenge_phase. So we can't clone evaluation forms without automatically advancing the challenge phase,
# or something along those lines. Also, we're leaving out the clone button which would trigger this for now,
# but I'm leaving it in case the button gets implemented later.

def create_from_existing
@existing_form = EvaluationForm.find(params[:evaluation_form])
@evaluation_form = EvaluationForm.new(@existing_form.attributes.except("id"))
respond_to do |format|
if @evaluation_form.save
format.html do
redirect_to evaluation_forms_url, notice: "Evaluation form was successfully cloned."
end
format.json { render :show, status: :created, location: @evaluation_form }
else
format.html { render :index, status: :unprocessable_entity }
format.json { render json: @evaluation_form.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /evaluation_forms/1 or /evaluation_forms/1.json
def update
respond_to do |format|
if @evaluation_form.update(evaluation_form_params)
format.html do
redirect_to evaluation_form_url(@evaluation_form), notice: "Evaluation form was successfully updated."
end
format.json { render :show, status: :ok, location: @evaluation_form }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @evaluation_form.errors, status: :unprocessable_entity }
end
end
end

# DELETE /evaluation_forms/1 or /evaluation_forms/1.json
def destroy
@evaluation_form.destroy!

respond_to do |format|
format.html { redirect_to evaluation_forms_url, notice: "Evaluation form was successfully destroyed." }
format.json { head(:no_content) }
end
end

private

# Use callbacks to share common setup or constraints between actions.
def set_evaluation_form
@evaluation_form = EvaluationForm.find(params[:id])
end

# Only allow a list of trusted parameters through.
def evaluation_form_params
params.require(:evaluation_form).permit(:title, :instructions, :challenge_phase, :status, :comments_required,
:weighted_scoring, :publication_date, :closing_date, :challenge_id)
end
end
11 changes: 11 additions & 0 deletions app/helpers/evaluation_forms_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# frozen_string_literal: true

module EvaluationFormsHelper
def status_colors
{
draft: "FireBrick",
ready: "DarkGoldenRod",
published: "green"
}
end
Comment on lines +4 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these stauts_colors aren't needed anymore, but if we do they should be matching the figma values, e.g. the green is #4d8055


def challenge_with_phase(evaluation_form)
"#{evaluation_form.challenge.title} - Phase #{evaluation_form.challenge_phase}"
end
end
11 changes: 11 additions & 0 deletions app/models/evaluation_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class EvaluationForm < ApplicationRecord
belongs_to :challenge

enum :status, { draft: 0, ready: 1, published: 2 }

validates :title, presence: true
validates :instructions, presence: true
validates :challenge_phase, presence: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can leave out the validations for now just to move this forward. based on the latest conversation with Renata, we will eventually run some validations only when the uses presses save, so it can't be tied to the Rails validation callbacks.

end
47 changes: 47 additions & 0 deletions app/views/evaluation_forms/_evaluation_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div id="<%= dom_id evaluation_form %>">
<p>
<strong>Title:</strong>
<%= evaluation_form.title %>
</p>

<p>
<strong>Instructions:</strong>
<%= evaluation_form.instructions %>
</p>

<p>
<strong>Challenge phase:</strong>
<%= evaluation_form.challenge_phase %>
</p>

<p>
<strong>Status:</strong>
<%= evaluation_form.status %>
</p>

<p>
<strong>Comments required:</strong>
<%= evaluation_form.comments_required %>
</p>

<p>
<strong>Weighted scoring:</strong>
<%= evaluation_form.weighted_scoring %>
</p>

<p>
<strong>Publication date:</strong>
<%= evaluation_form.publication_date %>
</p>

<p>
<strong>Closing date:</strong>
<%= evaluation_form.closing_date %>
</p>

<p>
<strong>Challenge:</strong>
<%= evaluation_form.challenge_id %>
</p>

</div>
5 changes: 5 additions & 0 deletions app/views/evaluation_forms/_evaluation_form.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

json.extract!(evaluation_form, :id, :title, :instructions, :challenge_phase, :status, :comments_required,
:weighted_scoring, :publication_date, :closing_date, :challenge_id, :created_at, :updated_at)
json.url(evaluation_form_url(evaluation_form, format: :json))
62 changes: 62 additions & 0 deletions app/views/evaluation_forms/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<%= form_with(model: evaluation_form) do |form| %>
<% if evaluation_form.errors.any? %>
<div style="color: red">
<h2><%= pluralize(evaluation_form.errors.count, "error") %> prohibited this evaluation_form from being saved:</h2>

<ul>
<% evaluation_form.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>

<div>
<%= form.label :title, style: "display: block" %>
<%= form.text_field :title %>
</div>

<div>
<%= form.label :instructions, style: "display: block" %>
<%= form.text_field :instructions %>
</div>

<div>
<%= form.label :challenge_phase, style: "display: block" %>
<%= form.number_field :challenge_phase %>
</div>

<div>
<%= form.label :status, style: "display: block" %>
<%= form.collection_select :status, EvaluationForm.statuses.map{ |a| [a.first,a.first] }, :first, :second %>
</div>

<div>
<%= form.label :comments_required, style: "display: block" %>
<%= form.check_box :comments_required %>
</div>

<div>
<%= form.label :weighted_scoring, style: "display: block" %>
<%= form.check_box :weighted_scoring %>
</div>

<div>
<%= form.label :publication_date, style: "display: block" %>
<%= form.date_field :publication_date %>
</div>

<div>
<%= form.label :closing_date, style: "display: block" %>
<%= form.date_field :closing_date %>
</div>

<div>
<%= form.label :challenge_id, style: "display: block" %>
<%= form.text_field :challenge_id %>
</div>

<div>
<%= form.submit %>
</div>
<% end %>
49 changes: 49 additions & 0 deletions app/views/evaluation_forms/_table.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<table class="usa-table usa-table--stacked-header usa-table--borderless width-full">
<thead>
<tr>
<th scope="col">Form Title</th>
<th scope="col">Assigned to Challenge:</th>
<th scope="col">Status:</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<% @evaluation_forms.each do |evaluation_form| %>
<tr>
<th data-label="Form Title" scope="row">
<%= link_to evaluation_form do %>
<%= evaluation_form.title %>
<% end %>
</th>
<td data-label="Assigned to Challenge:">
<%= challenge_with_phase(evaluation_form) %>
</td>
<td data-label="Status:">
<span style="<%="color: #{status_colors[evaluation_form.status.to_sym]}"%>">
<%= evaluation_form.status.capitalize %>
</span>
</td>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status table column can be removed

<td>
<div class="display-flex flex-wrap grid-row grid-gap-1">
<%= button_to edit_evaluation_form_path(evaluation_form), method: :get, class: "usa-button width-full", form: {class: "grid-col-6"} do %>
<%= image_tag(
"images/usa-icons/content_copy.svg",
class: "usa-icon icon-white",
alt: "evaluation forms"
)%>
Edit
<% end %>
<%= button_to evaluation_form, method: :delete, class: "usa-button usa-button--secondary width-full padding-x-1", form: {class: "grid-col-6"} do %>
<%= image_tag(
"images/usa-icons/content_copy.svg",
class: "usa-icon icon-white",
alt: "evaluation forms"
)%>
Delete
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
12 changes: 12 additions & 0 deletions app/views/evaluation_forms/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<% content_for :title, "Editing evaluation form" %>

<h1>Editing evaluation form</h1>

<%= render "form", evaluation_form: @evaluation_form %>

<br>

<div>
<%= link_to "Show this evaluation form", @evaluation_form %> |
<%= link_to "Back to evaluation forms", evaluation_forms_path %>
</div>
30 changes: 25 additions & 5 deletions app/views/evaluation_forms/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
<div class="usa-card__container col-md-6">
<div class="usa-card__body">
<h1>Evaluation Forms</h1>
<div class="usa-card__body">
<h1>Evaluation Forms</h1>
<div class="display-flex flex-wrap tablet:flex-justify width-full">
<span class="text-base margin-bottom-1">Manage existing evaluation forms and create new evaluation forms.</span>

<%= link_to new_evaluation_form_path, class: "width-full tablet:width-auto" do %>
<button class="usa-button font-body-2xs text-no-wrap" style="background-color: #4d8055">
<%= image_tag(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's avoid hard coding styles, especially for colors, and use a class such as bg-green-primary or something like that?

"images/usa-icons/content_copy.svg",
class: "usa-icon icon-white",
alt: "evaluation forms"
)%>
Create New Evaluation Form
</button>
<% end %>
</div>

<% if @evaluation_forms.empty? %>
<div class="text-base align-center text-center">
<p>You currently do not have any evaluation forms.</p>
<p>Please create an evaluation form for your challenge before it is published.</p>
</div>
<% else %>
<%= render partial: "table", locals: { evaluation_forms: @evaluation_forms } %>
<% end %>

<p>Placeholder text for Evaluation Forms.</p>
</div>
</div>
3 changes: 3 additions & 0 deletions app/views/evaluation_forms/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

json.array!(@evaluation_forms, partial: "evaluation_forms/evaluation_form", as: :evaluation_form)
11 changes: 11 additions & 0 deletions app/views/evaluation_forms/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% content_for :title, "New evaluation form" %>

<h1>New evaluation form</h1>

<%= render "form", evaluation_form: @evaluation_form %>

<br>

<div>
<%= link_to "Back to evaluation forms", evaluation_forms_path %>
</div>
10 changes: 10 additions & 0 deletions app/views/evaluation_forms/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<p style="color: green"><%= notice %></p>

<%= render @evaluation_form %>

<div>
<%= link_to "Edit this evaluation form", edit_evaluation_form_path(@evaluation_form) %> |
<%= link_to "Back to evaluation forms", evaluation_forms_path %>

<%= button_to "Destroy this evaluation form", @evaluation_form, method: :delete %>
</div>
3 changes: 3 additions & 0 deletions app/views/evaluation_forms/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

json.partial!("evaluation_forms/evaluation_form", evaluation_form: @evaluation_form)
3 changes: 2 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -11,7 +11,8 @@
get '/dashboard', to: "dashboard#index"

resources :evaluations, only: [:index]
resources :evaluation_forms, only: [:index]
resources :evaluation_forms
post '/evaluation_forms/clone', to: 'evaluation_forms#create_from_existing'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove the custom route for now

resources :manage_submissions, only: [:index]

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
19 changes: 19 additions & 0 deletions db/migrate/20240917010803_create_evaluation_forms.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class CreateEvaluationForms < ActiveRecord::Migration[7.2]
def change
create_table :evaluation_forms do |t|
t.string :title, null: false
t.string :instructions, null: false
t.integer :challenge_phase, null: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can leave off the null: false from these fields to allow them to be empty in the DB

t.integer :status, default: 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

t.boolean :comments_required, default: false
t.boolean :weighted_scoring, default: false
t.date :publication_date, null: true
t.date :closing_date, null: true
t.belongs_to :challenge, null: false, foreign_key: true

t.timestamps
end

add_index :evaluation_forms, [:challenge_id, :challenge_phase], unique: true
end
end
97 changes: 97 additions & 0 deletions db/structure.sql
Original file line number Diff line number Diff line change
@@ -98,6 +98,18 @@ CREATE SEQUENCE public.agency_members_id_seq
ALTER SEQUENCE public.agency_members_id_seq OWNED BY public.agency_members.id;


--
-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.ar_internal_metadata (
key character varying NOT NULL,
value character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);


--
-- Name: certification_log; Type: TABLE; Schema: public; Owner: -
--
@@ -310,6 +322,45 @@ CREATE SEQUENCE public.dap_reports_id_seq
ALTER SEQUENCE public.dap_reports_id_seq OWNED BY public.dap_reports.id;


--
-- Name: evaluation_forms; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.evaluation_forms (
id bigint NOT NULL,
title character varying NOT NULL,
instructions character varying NOT NULL,
challenge_phase integer NOT NULL,
status integer DEFAULT 0,
comments_required boolean DEFAULT false,
weighted_scoring boolean DEFAULT false,
publication_date date,
closing_date date,
challenge_id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);


--
-- Name: evaluation_forms_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--

CREATE SEQUENCE public.evaluation_forms_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;


--
-- Name: evaluation_forms_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--

ALTER SEQUENCE public.evaluation_forms_id_seq OWNED BY public.evaluation_forms.id;


--
-- Name: federal_partners; Type: TABLE; Schema: public; Owner: -
--
@@ -1088,6 +1139,13 @@ ALTER TABLE ONLY public.challenges ALTER COLUMN id SET DEFAULT nextval('public.c
ALTER TABLE ONLY public.dap_reports ALTER COLUMN id SET DEFAULT nextval('public.dap_reports_id_seq'::regclass);


--
-- Name: evaluation_forms id; Type: DEFAULT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.evaluation_forms ALTER COLUMN id SET DEFAULT nextval('public.evaluation_forms_id_seq'::regclass);


--
-- Name: federal_partners id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -1237,6 +1295,14 @@ ALTER TABLE ONLY public.agency_members
ADD CONSTRAINT agency_members_pkey PRIMARY KEY (id);


--
-- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.ar_internal_metadata
ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key);


--
-- Name: certification_log certification_log_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -1269,6 +1335,14 @@ ALTER TABLE ONLY public.dap_reports
ADD CONSTRAINT dap_reports_pkey PRIMARY KEY (id);


--
-- Name: evaluation_forms evaluation_forms_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.evaluation_forms
ADD CONSTRAINT evaluation_forms_pkey PRIMARY KEY (id);


--
-- Name: federal_partners federal_partners_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -1459,6 +1533,20 @@ CREATE UNIQUE INDEX agency_members_user_id_index ON public.agency_members USING
CREATE UNIQUE INDEX challenges_custom_url_index ON public.challenges USING btree (custom_url);


--
-- Name: index_evaluation_forms_on_challenge_id; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_evaluation_forms_on_challenge_id ON public.evaluation_forms USING btree (challenge_id);


--
-- Name: index_evaluation_forms_on_challenge_id_and_challenge_phase; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX index_evaluation_forms_on_challenge_id_and_challenge_phase ON public.evaluation_forms USING btree (challenge_id, challenge_phase);


--
-- Name: message_contexts_context_context_id_audience_parent_id_index; Type: INDEX; Schema: public; Owner: -
--
@@ -1619,6 +1707,14 @@ ALTER TABLE ONLY public.federal_partners
ADD CONSTRAINT federal_partners_sub_agency_id_fkey FOREIGN KEY (sub_agency_id) REFERENCES public.agencies(id);


--
-- Name: evaluation_forms fk_rails_28ad57fb81; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.evaluation_forms
ADD CONSTRAINT fk_rails_28ad57fb81 FOREIGN KEY (challenge_id) REFERENCES public.challenges(id);


--
-- Name: message_context_statuses message_context_statuses_message_context_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -1826,6 +1922,7 @@ ALTER TABLE ONLY public.winners
SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
(20240917010803),
(20231112151027),
(20231112151017),
(20231112151006),
2 changes: 1 addition & 1 deletion spec/helpers/evaluation_forms_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -10,6 +10,6 @@
# end
# end
# end
RSpec.describe EvaluationFormsHelper do
RSpec.describe EvaluationFormsHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
24 changes: 24 additions & 0 deletions spec/models/evaluation_form_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'rails_helper'

RSpec.describe EvaluationForm, type: :model do
describe 'validations' do
it 'validates presence of title' do
evaluation_form = described_class.new(title: nil)
expect(evaluation_form).not_to be_valid
expect(evaluation_form.errors[:title]).to include("can't be blank")
end

it 'validates presence of instructions' do
evaluation_form = described_class.new(instructions: nil)
expect(evaluation_form).not_to be_valid
expect(evaluation_form.errors[:instructions]).to include("can't be blank")
end
end

describe 'default values' do
it 'sets status to draft by default' do
evaluation_form = described_class.new
expect(evaluation_form.status).to eq('draft')
end
end
end