Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 9 additions & 0 deletions app/assets/stylesheets/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@
}
}

.popup__footer {
border-block-start: 1px solid var(--color-ink-lightest);
color: var(--card-color);
margin-block-start: var(--popup-item-padding-inline);
padding: var(--popup-item-padding-inline) var(--popup-item-padding-inline) 0;
text-align: center;
text-transform: initial;
}

.popup__title {
font-weight: 800;
white-space: nowrap;
Expand Down
15 changes: 10 additions & 5 deletions app/controllers/cards/assignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ def new
end

def create
@card.toggle_assignment @board.users.active.find(params[:assignee_id])

respond_to do |format|
format.turbo_stream
format.json { head :no_content }
if @card.toggle_assignment @board.users.active.find(params[:assignee_id])
respond_to do |format|
format.turbo_stream
format.json { head :no_content }
end
else
respond_to do |format|
format.turbo_stream
format.json { head :unprocessable_entity }
end
end
end
end
26 changes: 26 additions & 0 deletions app/javascript/controllers/assignment_limit_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static values = { limit: Number, count: Number }
static targets = ["unassigned", "limitMessage"]

connect() {
this.updateState()
}

countValueChanged() {
this.updateState()
}

updateState() {
const atLimit = this.countValue >= this.limitValue

this.unassignedTargets.forEach(el => {
el.hidden = atLimit
})

if (this.hasLimitMessageTarget) {
this.limitMessageTarget.hidden = !atLimit
}
}
}
11 changes: 11 additions & 0 deletions app/models/assignment.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
class Assignment < ApplicationRecord
LIMIT = 100

belongs_to :account, default: -> { card.account }
belongs_to :card, touch: true

belongs_to :assignee, class_name: "User"
belongs_to :assigner, class_name: "User"

validate :within_limit, on: :create

private
def within_limit
if card.assignments.count >= LIMIT
errors.add(:base, "Card already has the maximum of #{LIMIT} assignees")
end
end
end
8 changes: 5 additions & 3 deletions app/models/card/assignable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ def assigned?

private
def assign(user)
assignments.create! assignee: user, assigner: Current.user
watch_by user
assignment = assignments.create assignee: user, assigner: Current.user

track_event :assigned, assignee_ids: [ user.id ]
if assignment.persisted?
watch_by user
track_event :assigned, assignee_ids: [ user.id ]
end
rescue ActiveRecord::RecordNotUnique
# Already assigned
end
Expand Down
16 changes: 13 additions & 3 deletions app/views/cards/assignments/new.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<%= turbo_frame_tag @card, :assignment do %>
<%= tag.div class: "max-width full-width", data: {
action: "turbo:before-cache@document->dialog#close dialog:show@document->navigable-list#reset keydown->navigable-list#navigate filter:changed->navigable-list#reset",
controller: "filter navigable-list",
controller: "filter navigable-list assignment-limit",
dialog_target: "dialog",
navigable_list_focus_on_selection_value: false,
navigable_list_actionable_items_value: true } do %>
navigable_list_actionable_items_value: true,
assignment_limit_limit_value: Assignment::LIMIT,
assignment_limit_count_value: @card.assignments.count } do %>

<div class="flex align-start justify-space-between">
<strong class="popup__title">Assign this to…</strong>
Expand All @@ -19,7 +21,15 @@
<span class="visually-hidden"><%= Current.user.name %></span>
<% end %>
<%= render collection: @assigned_to, partial: "user", locals: { card: @card } %>
<%= render collection: @users, partial: "user", locals: { card: @card } %>
<% @users.each do |user| %>
<span data-assignment-limit-target="unassigned">
<%= render "user", card: @card, user: user %>
</span>
<% end %>
</ul>

<div class="popup__footer" hidden data-assignment-limit-target="limitMessage">
Maxium <%= Assignment::LIMIT %> assignees
Copy link
Collaborator

Choose a reason for hiding this comment

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

Typo here! Maximum vs Maxium

Copy link
Member

Choose a reason for hiding this comment

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

Doh! Thanks for catching that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this critical failure here 52bdc8d

</div>
<% end %>
<% end %>
37 changes: 34 additions & 3 deletions test/models/assignment_test.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
require "test_helper"

class AssignmentTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
test "create" do
card = cards(:text)
assignment = card.assignments.create!(assignee: users(:david), assigner: users(:jason))

assert_equal users(:david), assignment.assignee
assert_equal users(:jason), assignment.assigner
assert_equal card, assignment.card
end

test "create cannot exceed assignee limit" do
card = cards(:logo)
board = card.board
account = card.account

card.assignments.delete_all

Assignment::LIMIT.times do |i|
identity = Identity.create!(email_address: "limit_test_#{i}@example.com")
user = account.users.create!(identity: identity, name: "Limit Test User #{i}", role: :member)
user.accesses.find_or_create_by!(board: board)
card.assignments.create!(assignee: user, assigner: users(:david))
end

assert_equal Assignment::LIMIT, card.assignments.count

identity = Identity.create!(email_address: "[email protected]")
extra_user = account.users.create!(identity: identity, name: "Over Limit User", role: :member)
extra_user.accesses.find_or_create_by!(board: board)

assignment = card.assignments.build(assignee: extra_user, assigner: users(:david))

assert_not assignment.valid?
assert_includes assignment.errors[:base], "Card already has the maximum of #{Assignment::LIMIT} assignees"
end
end
27 changes: 27 additions & 0 deletions test/models/card/assignable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,31 @@ class Card::AssignableTest < ActiveSupport::TestCase
assert cards(:layout).assigned_to?(users(:kevin))
assert cards(:layout).watched_by?(users(:kevin))
end

test "toggle_assignment does not add assignee when at limit" do
card = cards(:logo)
board = card.board
account = card.account

card.assignments.delete_all

Assignment::LIMIT.times do |i|
identity = Identity.create!(email_address: "toggle_test_#{i}@example.com")
user = account.users.create!(identity: identity, name: "Toggle Test User #{i}", role: :member)
user.accesses.find_or_create_by!(board: board)
card.assignments.create!(assignee: user, assigner: users(:david))
end

identity = Identity.create!(email_address: "[email protected]")
extra_user = account.users.create!(identity: identity, name: "Toggle Over User", role: :member)
extra_user.accesses.find_or_create_by!(board: board)

with_current_user(:david) do
assert_no_difference "card.assignments.count" do
card.toggle_assignment(extra_user)
end
end

assert_not card.reload.assigned_to?(extra_user)
end
end