Merge pull request #266 from basecamp/assigners-=-creators

"Added by…" is a more useful filter than "Assigned by…"
This commit is contained in:
Jason Zimdars
2025-02-20 16:34:57 -06:00
committed by GitHub
12 changed files with 64 additions and 44 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ module FiltersHelper
end
def any_filters?(filter)
filter.tags.any? || filter.assignees.any? || filter.assigners.any? ||
filter.tags.any? || filter.assignees.any? || filter.creators.any? ||
filter.stages.any? || filter.terms.any? ||
filter.assignment_status.unassigned? || !filter.default_indexed_by?
end
+1 -1
View File
@@ -22,7 +22,7 @@ class Filter < ApplicationRecord
result = result.active unless indexed_by.popped?
result = result.unassigned if assignment_status.unassigned?
result = result.assigned_to(assignees.ids) if assignees.present?
result = result.assigned_by(assigners.ids) if assigners.present?
result = result.where(creator_id: creators.ids) if creators.present?
result = result.in_bucket(buckets.ids) if buckets.present?
result = result.in_stage(stages.ids) if stages.present?
result = result.tagged_with(tags.ids) if tags.present?
+2 -2
View File
@@ -5,7 +5,7 @@ module Filter::Params
:assignment_status,
:indexed_by,
assignee_ids: [],
assigner_ids: [],
creator_ids: [],
bucket_ids: [],
stage_ids: [],
tag_ids: [],
@@ -41,7 +41,7 @@ module Filter::Params
params[:bucket_ids] = buckets.ids
params[:stage_ids] = stages.ids
params[:assignee_ids] = assignees.ids
params[:assigner_ids] = assigners.ids
params[:creator_ids] = creators.ids
end.compact_blank.reject(&method(:default_value?))
end
+1 -1
View File
@@ -6,7 +6,7 @@ module Filter::Resources
has_and_belongs_to_many :buckets
has_and_belongs_to_many :stages, class_name: "Workflow::Stage", join_table: "filters_stages"
has_and_belongs_to_many :assignees, class_name: "User", join_table: "assignees_filters", association_foreign_key: "assignee_id"
has_and_belongs_to_many :assigners, class_name: "User", join_table: "assigners_filters", association_foreign_key: "assigner_id"
has_and_belongs_to_many :creators, class_name: "User", join_table: "creators_filters", association_foreign_key: "creator_id"
end
def resource_removed(resource)
+7 -7
View File
@@ -1,6 +1,6 @@
module Filter::Summarized
def summary
[ index_summary, tag_summary, assignee_summary, assigner_summary, stage_summary, terms_summary ].compact.to_sentence + " #{bucket_summary}"
[ index_summary, tag_summary, assignee_summary, creator_summary, stage_summary, terms_summary ].compact.to_sentence + " #{bucket_summary}"
end
private
@@ -22,12 +22,6 @@ module Filter::Summarized
end
end
def assigner_summary
if assigners.any?
"assigned by #{assigners.pluck(:name).to_choice_sentence}"
end
end
def stage_summary
if stages.any?
"staged in #{stages.pluck(:name).to_choice_sentence}"
@@ -45,4 +39,10 @@ module Filter::Summarized
"matching #{terms.map { |term| %Q("#{term}") }.to_sentence}"
end
end
def creator_summary
if creators.any?
"added by #{creators.pluck(:name).to_choice_sentence}"
end
end
end
@@ -1,47 +1,49 @@
<% if filter.assigners.any? %>
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<% if filter.creators.any? %>
<div class="quick-filter position-relative" data-controller="dialog"
data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.assigners.any? %>
<%= "By #{filter.assigners.map(&:name).to_sentence}" %>
<% if filter.creators.any? %>
<%= "Added by #{filter.creators.map(&:name).to_sentence}" %>
<% else %>
Assigned by…
Added by…
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Assigned by…</strong>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow"
data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Added by…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:assigner_ids).each do |key, value| %>
<% filter.as_params.except(:creator_ids).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:assigner_ids)), class: "btn popup__item" do %>
<%= link_to bubbles_path(filter.as_params.except(:creator_ids)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<div class="btn popup__item">
<%= form.check_box "assigner_ids[]", {
checked: filter.assigners.include?(Current.user),
<%= form.check_box "creator_ids[]", {
checked: filter.creators.include?(Current.user),
data: { action: "change->form#submit" },
include_hidden: false,
}, Current.user.id %>
<%= form.label "assigner_ids[]", "Me", for: dom_id(Current.user, :assigner_filter), class: "overflow-ellipsis" %>
<%= form.label "creator_ids[]", "Me", for: dom_id(Current.user, :creator_filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
<div class="btn popup__item">
<%= form.check_box "assigner_ids[]", {
checked: filter.assigners.include?(user),
<%= form.check_box "creator_ids[]", {
checked: filter.creators.include?(user),
data: { action: "change->form#submit" },
include_hidden: false,
}, user.id %>
<%= form.label "assigner_ids[]", user.name, for: dom_id(user, :assigner_filter), class: "overflow-ellipsis" %>
<%= form.label "creator_ids[]", user.name, for: dom_id(user, :creator_filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
+7 -7
View File
@@ -121,20 +121,20 @@
</menu>
<menu class="filter__menu">
<li class="filter__label"><strong>Assigned by…</strong></li>
<li class="filter__label"><strong>Added by…</strong></li>
<li>
<%= label_tag "assigner_ids_me", class: "btn filter__button" do %>
<%= check_box_tag "assigner_ids[]", Current.user.id, filter.assigners.include?(Current.user), id: "assigner_ids_me",
hidden: true, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignment_status" } %>
<%= label_tag "creator_ids_me", class: "btn filter__button" do %>
<%= check_box_tag "creator_ids[]", Current.user.id, filter.creators.include?(Current.user), id: "creator_ids_me",
hidden: true %>
<span>Me</span>
<%= image_tag "close.svg", aria: { hidden: true }, size: 24 %>
<% end %>
</li>
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
<li>
<%= label_tag "assigner_ids_#{user.id}", class: "btn filter__button" do %>
<%= check_box_tag "assigner_ids[]", user.id, filter.assigners.include?(user), id: "assigner_ids_#{user.id}",
hidden: true, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignment_status" } %>
<%= label_tag "creator_ids_#{user.id}", class: "btn filter__button" do %>
<%= check_box_tag "creator_ids[]", user.id, filter.creators.include?(user), id: "creator_ids_#{user.id}",
hidden: true %>
<span><%= user.name %></span>
<%= image_tag "close.svg", aria: { hidden: true }, size: 24 %>
<% end %>
+1 -1
View File
@@ -9,7 +9,7 @@
<%= render "filters/buckets", filter: filter %>
<%= render "filters/tags", filter: filter %>
<%= render "filters/assignees", filter: filter %>
<%= render "filters/assigners", filter: filter %>
<%= render "filters/creators", filter: filter %>
<%= render "filters/stages", filter: filter %>
<% filter.terms.each do |term| %>
@@ -0,0 +1,11 @@
class CreateCreatorsFiltersJoinTable < ActiveRecord::Migration[8.1]
def change
create_table :creators_filters, id: false do |t|
t.integer :filter_id, null: false
t.integer :creator_id, null: false
end
add_index :creators_filters, :filter_id
add_index :creators_filters, :creator_id
end
end
@@ -0,0 +1,7 @@
class DropAssignersFiltersJoinTable < ActiveRecord::Migration[8.1]
class DropAssignersFiltersJoinTable < ActiveRecord::Migration[7.1]
def change
drop_table :assigners_filters if table_exists?(:assigners_filters)
end
end
end
Generated
+8 -8
View File
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.1].define(version: 2025_02_14_222911) do
ActiveRecord::Schema[8.1].define(version: 2025_02_20_220424) do
create_table "accesses", force: :cascade do |t|
t.integer "bucket_id", null: false
t.integer "user_id", null: false
@@ -77,13 +77,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_02_14_222911) do
t.index ["filter_id"], name: "index_assignees_filters_on_filter_id"
end
create_table "assigners_filters", id: false, force: :cascade do |t|
t.integer "filter_id", null: false
t.integer "assigner_id", null: false
t.index ["assigner_id"], name: "index_assigners_filters_on_assigner_id"
t.index ["filter_id"], name: "index_assigners_filters_on_filter_id"
end
create_table "assignments", force: :cascade do |t|
t.integer "assignee_id", null: false
t.integer "bubble_id", null: false
@@ -137,6 +130,13 @@ ActiveRecord::Schema[8.1].define(version: 2025_02_14_222911) do
t.datetime "updated_at", null: false
end
create_table "creators_filters", id: false, force: :cascade do |t|
t.integer "filter_id", null: false
t.integer "creator_id", null: false
t.index ["creator_id"], name: "index_creators_filters_on_creator_id"
t.index ["filter_id"], name: "index_creators_filters_on_filter_id"
end
create_table "event_summaries", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+1 -1
View File
@@ -16,7 +16,7 @@ class FilterTest < ActiveSupport::TestCase
filter = users(:david).filters.new indexed_by: "most_discussed", assignee_ids: [ users(:jz).id ], tag_ids: [ tags(:mobile).id ]
assert_equal [ bubbles(:layout) ], filter.bubbles
filter = users(:david).filters.new assigner_ids: [ users(:david).id ], tag_ids: [ tags(:mobile).id ]
filter = users(:david).filters.new creator_ids: [ users(:david).id ], tag_ids: [ tags(:mobile).id ]
assert_equal [ bubbles(:layout) ], filter.bubbles
filter = users(:david).filters.new stage_ids: [ workflow_stages(:qa_triage).id ]