This repository has been archived by the owner on Oct 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
5.1 Squad CRUD refactor (after)
Barrie Hadfield edited this page Jan 5, 2017
·
1 revision
- We can get rid of the Controller, Representer, API and API tests
- Concept CRUD code will be refactored to be an Hyperloop Operation
- Concept test code will be refactored
We have to think about caching...
module Components
module Squad
class Admin < React::Component::Base
# following added to remove warning messages
param :route
param :history
param :location
param :routeParams
param :routes
param :params
define_state show_save: false
define_state errors: []
define_state show_modal: false
define_state show_save: false
before_mount do
@mandate = ""
@name = ""
@leader_id = 0
@tribe_id = 0
end
before_mount do
state.squads! ReactiveRecord::Squad.all
UIHelpers::UIHelper.clear_alert
end
def render
div.container {
if state.squads.nil? || state.squads.loading? # this is not working right yet
br {}
Shared::Spinner()
else
div.row {
h2.text_info {
i.fa.fa_th {}
" Squads ".span
small { Shared::Store.current_period[:name] } if Shared::Store.current_period
}
div.row {
div.panel.panel_default {
div.panel_body {
div.col_md_12 {
br
UIHelpers::AlertMessage()
modal_render
Bs.Button(bsStyle: :primary) { "New Squad" }.on(:click) do
reset_form
state.show_modal! true
end
table_render
}
}
}
}
}
end
}
end
def table_render
div.row {
div.col_md_12 {
br {}
table(class: "table table-hover") {
thead {
tr {
td.text_muted.small(width: '20%') { "SQUAD" }
td.text_muted.small(width: '20%') { "TRIBE" }
td.text_muted.small(width: '20%') { "LEADER" }
td.text_muted.small(width: '40%') { "MANDATE" }
}
}
tbody {
state.squads.each do |squad|
table_row squad
end
}
}
}
}
end
def table_row squad
tr {
td(width: '20%') { span.link {
squad.name }.on(:click) do
set_form squad
state.show_modal! true
end
}
td(width: '20%') { squad.tribe.name }
td(width: '20%') { squad.leader.full_name }
td(width: '60%') { squad.mandate }
}
end
def close
state.show_modal! false
end
def reset_form
@squad_id = 0
@delete_disabled = true
@name = ""
@mandate = ""
@leader_id = 0
@tribe_id = 0
state.show_save! false
state.show_delete_confirm! false
state.errors! []
state.show_spinner! false
end
def set_form squad
@squad_id = squad.id
@delete_disabled = squad.can_delete? ? false : true
@name = squad.name
@mandate = squad.mandate
@leader_id = squad.leader.id
@tribe_id = squad.tribe.id
state.show_delete_confirm! false
state.errors! []
state.show_spinner! false
end
def delete
HTTP.delete("/api/v3/squad/#{@squad_id}.json") do |response|
if response.ok?
# Shared::Store.get_squads
state.show_modal! false
UIHelpers::UIHelper.set_alert @name, "has been deleted"
else
puts response
alert "Unable to delete Squad"
end
end
end
def save
data = {squad: {name: @name,
mandate: @mandate, leader_id: @leader_id, tribe_id: @tribe_id}
}
if @squad_id == 0
HTTP.post("/api/v3/squad.json", payload: data) do |response|
if response.ok?
state.show_modal! false
UIHelpers::UIHelper.set_alert @name, "has been created"
else
alert "Unable to create Squad"
end
end
else
HTTP.patch("/api/v3/squad/#{@squad_id}.json", payload: data) do |response|
if response.ok?
# Shared::Store.get_squads
state.show_modal! false
UIHelpers::UIHelper.set_alert @name, "has been updated"
else
alert "Unable to update Squad"
end
end
end
end
def save_modal
state.errors! []
name_validation
mandate_validation
leader_validation
tribe_validation
unless state.errors.any?
state.show_spinner! true
state.errors! []
save
end
end
def name_validation
case
when @name.length < 5
state.errors! << "Name must be more than 5 chars"
when @name.length > 30
state.errors! << "Name must be less than 30 chars"
end
end
def mandate_validation
case
when @mandate.length < 10
state.errors! << "Mandate must be more than 10 chars"
when @mandate.length > 100
state.errors! << "Mandate must be less than 100 chars"
end
end
def leader_validation
case
when @leader_id.to_i == 0 || !@leader_id
state.errors! << "Please select a leader"
end
end
def tribe_validation
case
when @tribe_id.to_i == 0 || !@tribe_id
state.errors! << "Please select a Tribe"
end
end
def modal_render
Bs.Modal(show: state.show_modal, backdrop: 'static', onHide: lambda { close }) {
Bs.ModalHeader {
h4 { "Squad" }
}
Bs.ModalBody {
Bs.FormGroup {
Bs.ControlLabel { "* Tribe" }
Bs.FormControl(componentClass: "select", placeholder: "select", defaultValue: @tribe_id) {
option(value: 0) {"select"}
ReactiveRecord::Tribe.all.each do |tribe|
option(value: tribe.id) { tribe.name }
end
}.on(:change) do |e|
@tribe_id = e.target.value
end
}
Bs.FormGroup {
Bs.ControlLabel { "* Name" }
Bs.FormControl.Feedback(defaultValue: @name ,type: :text, placeholder: "(5 - 30 chars)").on(:change) do |e|
@name = e.target.value
end
}
Bs.FormGroup {
Bs.ControlLabel { "* Mandate" }
Bs.FormControl(componentClass: :textarea, defaultValue: @mandate,
placeholder: "What is the main purpose or mandate of this Squad? (5 - 200 chars)"
).on(:change) do |e|
@mandate = e.target.value
end
}
Bs.FormGroup {
Bs.ControlLabel { "* Leader" }
Bs.FormControl(componentClass: "select", placeholder: "select", defaultValue: @leader_id) {
option(value: 0) {"select"}
ReactiveRecord::Member.all.each do |member|
option(value: member.id) { member.full_name }
end
}.on(:change) do |e|
@leader_id = e.target.value
end
}
Bs.ModalFooter {
span.pull_right {
Bs.ButtonToolbar {
if !state.show_delete_confirm
if @squad_id != 0
Bs.Button(bsStyle: 'danger', class: 'danger-outline', disabled: @delete_disabled ? true : false) { 'Delete this Squad' }.on(:click) {
state.show_delete_confirm! true
}
end
Bs.Button(bsStyle: 'success') { 'Save' }.on(:click) { save_modal }
else
Bs.Button(bsStyle: :danger) { "Confirm Delete"}. on(:click) do
delete
end
end
Bs.Button { 'Cancel' }.on(:click) { close }
}
}
if state.errors.any?
br
br
div(class: "alert alert-danger") {
state.errors.each do |error|
para { "#{error}" }
end
}
end
if state.show_spinner
br
br
br
Shared::SpinnerSpan()
span { " working"}
end
}
}
}
end
end
end
end
Then the Squad CRUD concept (operation):
class Squad < ActiveRecord::Base
def can_delete?
(objective_count == 0 && key_result_count == 0 && score_count == 0) ? true : false
# false
end
class Create < Trailblazer::Operation
include Model
model Squad, :create
contract do
property :name
property :mandate
property :tribe_id
property :leader_id
validates :tribe_id, presence: true
validate :valid_tribe?
validates :leader_id, presence: true
validate :valid_leader?
validates :name, presence: true
validates :name, length: {in: 5..30}
validates :mandate, presence: true
validates :mandate, length: {in: 5..200}
def valid_tribe?
errors.add("tribe_id", "not valid") unless Tribe.find_by_id(tribe_id)
end
def valid_leader?
errors.add("leader_id", "not valid") unless Member.find_by_id(leader_id)
end
end
def process(params)
validate(params[:squad]) do |f|
f.save
Rails.cache.delete_matched("count/squads")
end
end
end
class Update < Create
action :update
end
class Show < Trailblazer::Operation
include Model
model ::Squad, :find
def process(params)
end
end
class Index < Trailblazer::Operation
include Collection
def process(params)
end
def model!(params)
# Squad.includes(:leader, :objectives, :key_results).order(:name)
Squad.order(:name)
end
end
class Delete < Trailblazer::Operation
include Model
model Squad, :find
def process(params)
if model.can_delete?
model.destroy
Rails.cache.delete_matched("count/squads")
else
return invalid!
end
end
end
end
Then the model:
class Squad < ActiveRecord::Base
belongs_to :leader, class_name: :Member
belongs_to :tribe
belongs_to :home_page, class_name: :Page
has_many :objectives, -> { where is_enabled: true }, as: :owner
has_many :squad_members
has_many :members, through: :squad_members
has_many :key_results, through: :objectives
has_many :scores, through: :key_results
has_many :stars, through: :scores
default_scope -> { where(period_id: Period.current.id) }
# pass 0 for all tribes
scope :for_tribe, (lambda do |id|
where(tribe_id: id) if id != 0
end)
scope :for_period, (lambda do |period_id|
unscoped.where(period_id: period_id)
end)
def last_score
self.scores.first
end
def last_scored_at
scores.first.created_at if scores.any?
end
def score_count
# tested ok
Rails.cache.fetch("count/scores/squad/#{self.id}") do
self.scores.count
end
end
def objective_count
# tested ok
Rails.cache.fetch("count/objectives/squad/#{self.id}") do
objectives.count
end
end
def key_result_count
# tested ok
Rails.cache.fetch("count/key_results/squad/#{self.id}") do
key_results.count
end
end
def parent
tribe
end
def children
nil
end
def set_period_on_create
self.period_id = Period.current.id
return true
end
def possible_parent_objectives
tribe.objectives
end
def name
db_name = read_attribute(:name)
if db_name && !db_name.downcase.include?("squad") && !db_name.downcase.include?("chapter")
db_name += " Squad"
end
db_name
end
end
Then the Squad concept tests:
require 'test_helper'
class SquadCrudTest < MiniTest::Spec
describe "Squad CRUD" do
before do
Rails.cache.delete_matched("current/company")
Rails.cache.delete_matched("count")
period = Period::Create.(period: {name: "Period valid 1", start_date: Date.today, end_date: Date.tomorrow}).model
Company::Create.(company: {name: "Test company 2"})
@member = Member::Create.(member: {first_name: "John", last_name: "Smith",
email: "john@smith.com", password: 'AComplicated88test'}).model
Period::SetAsCurrentPeriod.run(id: period.id)
Period.count.must_equal 1
Company.count.must_equal 1
Member.count.must_equal 1
@tribe = Tribe::Create.(tribe: {name: "Test tribe",
mandate: "A valid mandate",
leader_id: @member.id
}).model
@tribe.persisted?.must_equal true
@tribe.name.must_equal "Test tribe"
@company_objective = Objective::Create.(objective: {name: "Test objective", note: "A valid note",
owner_type: "Company", owner_id: Company.current.id
}).model
@company_objective.persisted?.must_equal true
end
describe "Create" do
it "persists valid" do
squad = Squad::Create.(squad: {name: "Test squad",
mandate: "A valid mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
squad.name.must_equal "Test squad"
end
it "invalid as too short" do
res, op = Squad::Create.run(squad: {name: "T", mandate: "A valid mandate", tribe_id: @tribe.id})
res.must_equal false
op.model.persisted?.must_equal false
end
end
describe "Update" do
it "persists valid after update" do
squad = Squad::Create.(squad: {name: "A name which is long enough",
mandate: "and a mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
Squad::Update.(
id: squad.id,
squad: {name: "A brand new name"}).model
squad.reload
squad.name.must_equal "A brand new name Squad"
end
end
describe "Delete" do
it "ok to delete" do
squad = Squad::Create.(squad: {name: "A name which is long enough",
mandate: "and a mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
res, op = Squad::Delete.run(squad)
res.must_equal true
op.model.persisted?.must_equal false
end
it "must fail to delete Tribe if it has Squads" do
squad = Squad::Create.(squad: {name: "Test tribe",
mandate: "A valid mandate", tribe_id: @tribe.id,
leader_id: @member.id}
).model
squad.persisted?.must_equal true
res, op = Tribe::Delete.run(@tribe)
res.must_equal false
op.model.persisted?.must_equal true
end
end
describe "Correct counts from cache" do
it "has correct Objective count" do
squad = Squad::Create.(squad: {name: "A name which is long enough",
mandate: "and a mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
squad.objective_count.must_equal 0
squad_objective = Objective::Create.(objective: {name: "Test objective for squad", note: "A valid note",
owner_type: "Squad", owner_id: squad.id, parent_id: @company_objective.id
}).model
squad_objective.persisted?.must_equal true
squad.objective_count.must_equal 1
squad_objective2 = Objective::Create.(objective: {name: "Test objective 2 for squad", note: "A valid note",
owner_type: "Squad", owner_id: squad.id, parent_id: @company_objective.id
}).model
squad_objective2.persisted?.must_equal true
squad.objective_count.must_equal 2
end
it "has correct KeyResult count" do
squad = Squad::Create.(squad: {name: "A name which is long enough",
mandate: "and a mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
squad_objective = Objective::Create.(objective: {name: "Test objective for squad", note: "A valid note",
owner_type: "Squad", owner_id: squad.id, parent_id: @company_objective.id
}).model
squad_objective.persisted?.must_equal true
squad.objective_count.must_equal 1
squad.key_result_count.must_equal 0
key_result = KeyResult::Create.(key_result: {name: "Test result", note: "A valid note",
objective_id: squad_objective.id
}).model
key_result.persisted?.must_equal true
squad.key_result_count.must_equal 1
end
it "has correct Score count" do
squad = Squad::Create.(squad: {name: "A name which is long enough",
mandate: "and a mandate", tribe_id: @tribe.id,
leader_id: @member.id
}).model
squad.persisted?.must_equal true
squad_objective = Objective::Create.(objective: {name: "Test objective for squad", note: "A valid note",
owner_type: "Squad", owner_id: squad.id, parent_id: @company_objective.id
}).model
squad_objective.persisted?.must_equal true
squad.objective_count.must_equal 1
squad.key_result_count.must_equal 0
key_result = KeyResult::Create.(key_result: {name: "Test result", note: "A valid note",
objective_id: squad_objective.id
}).model
key_result.persisted?.must_equal true
squad.key_result_count.must_equal 1
squad.score_count.must_equal 0
score = Score::Create.(score: {note: "Test note", key_result_id: key_result.id,
achievement: 1, confidence: 1, created_by_id: @member.id}).model
score.persisted?.must_equal true
squad.score_count.must_equal 1
score2 = Score::Create.(score: {note: "Test note2", key_result_id: key_result.id,
achievement: 1, confidence: 1, created_by_id: @member.id}).model
score2.persisted?.must_equal true
squad.score_count.must_equal 2
end
end
end
end