Drop boosts
Killed by design.
This commit is contained in:
@@ -471,37 +471,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.input.boost__input {
|
||||
--hover-size: 0;
|
||||
--input-border-radius: 0;
|
||||
--input-border-size: 0;
|
||||
--input-padding: 0;
|
||||
--outline-size: 0;
|
||||
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
inline-size: min-content;
|
||||
max-inline-size: 3ch;
|
||||
min-inline-size: 1ch;
|
||||
outline: none;
|
||||
|
||||
@supports (field-sizing: content) {
|
||||
field-sizing: content;
|
||||
max-inline-size: unset;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background-color: var(--color-highlight);
|
||||
}
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card__closed {
|
||||
align-items: center;
|
||||
aspect-ratio: 7/4;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
class Cards::BoostsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
def create
|
||||
count = if params[:boost_count].to_i == @card.boosts_count
|
||||
@card.boosts_count + 1
|
||||
else
|
||||
params[:boost_count].to_i
|
||||
end
|
||||
@card.boost!(count)
|
||||
end
|
||||
end
|
||||
@@ -19,13 +19,9 @@ module EventsTimeline
|
||||
end
|
||||
|
||||
def events_for_activity_day
|
||||
user_events.where(created_at: @activity_day.all_day).
|
||||
group_by { |event| [ event.created_at.hour, helpers.event_column(event) ] }.
|
||||
map { |hour_col, events|
|
||||
[ hour_col,
|
||||
events.uniq { |e| e.action == "boosted" ? [ e.creator_id, e.card_id ] : e.id }
|
||||
]
|
||||
}
|
||||
user_events.where(created_at: @activity_day.all_day)
|
||||
.group_by { |event| [ event.created_at.hour, helpers.event_column(event) ] }
|
||||
.map { |hour_col, events| [ hour_col, events.uniq { |e| e.id } ] }
|
||||
end
|
||||
|
||||
def latest_event_before_activity_day
|
||||
@@ -38,7 +34,7 @@ module EventsTimeline
|
||||
|
||||
def user_cards
|
||||
Current.user.accessible_cards
|
||||
.published_or_drafted_by(Current.user)
|
||||
.where(collection_id: collection_filter)
|
||||
.published_or_drafted_by(Current.user)
|
||||
.where(collection_id: collection_filter)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -72,8 +72,6 @@ module EventsHelper
|
||||
end
|
||||
when "unassigned"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } unassigned #{ event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence } from <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
when "boosted"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } boosted <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
when "commented"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } commented on <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
when "published"
|
||||
@@ -99,8 +97,6 @@ module EventsHelper
|
||||
case event.action
|
||||
when "assigned"
|
||||
"assigned"
|
||||
when "boosted"
|
||||
"thumb-up"
|
||||
when "staged"
|
||||
"bolt"
|
||||
when "unstaged"
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
class Card < ApplicationRecord
|
||||
include Assignable, Boostable, Colored, DraftCommenting, Engageable, Eventable, Golden,
|
||||
include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden,
|
||||
Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged,
|
||||
Statuses, Taggable, Watchable
|
||||
|
||||
@@ -22,7 +22,6 @@ class Card < ApplicationRecord
|
||||
scope :indexed_by, ->(index) do
|
||||
case index
|
||||
when "most_active" then ordered_by_activity
|
||||
when "most_boosted" then ordered_by_boosts
|
||||
when "newest" then reverse_chronologically
|
||||
when "oldest" then chronologically
|
||||
when "latest" then latest
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
module Card::Boostable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
scope :ordered_by_boosts, -> { order boosts_count: :desc }
|
||||
end
|
||||
|
||||
def boost!(count = 1)
|
||||
count = count.to_i
|
||||
count = 1 if count < 1
|
||||
|
||||
transaction do
|
||||
track_event :boosted, count: count
|
||||
update! boosts_count: count
|
||||
rescore
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -36,7 +36,6 @@ module Card::Scorable
|
||||
|
||||
def event_weight(event)
|
||||
case
|
||||
when event.boosted? then 1
|
||||
when event.comment&.first_by_author_on_card? then 20
|
||||
when event.comment&.follows_comment_by_another_author? then 15
|
||||
when event.commented? then 10
|
||||
@@ -60,6 +59,6 @@ module Card::Scorable
|
||||
end
|
||||
|
||||
def scorable_events
|
||||
events.where(action: [ :commented, :boosted ])
|
||||
events.where(action: :commented)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,15 +9,9 @@ class Event < ApplicationRecord
|
||||
has_one :comment, through: :message, source: :messageable, source_type: "Comment"
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
scope :non_boosts, -> { where.not action: :boosted }
|
||||
scope :boosts, -> { where action: :boosted }
|
||||
|
||||
after_create -> { card.touch_last_active_at }
|
||||
|
||||
def boosted?
|
||||
action == "boosted"
|
||||
end
|
||||
|
||||
def commented?
|
||||
action == "commented"
|
||||
end
|
||||
|
||||
@@ -5,16 +5,12 @@ class EventSummary < ApplicationRecord
|
||||
|
||||
# FIXME: Consider persisting the body and compute at write time.
|
||||
def body
|
||||
"#{main_summary} #{boosts_summary}".squish
|
||||
events.map { |event| summarize(event) }.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
delegate :time_ago_in_words, to: "ApplicationController.helpers"
|
||||
|
||||
def main_summary
|
||||
events.non_boosts.map { |event| summarize(event) }.join(" ")
|
||||
end
|
||||
|
||||
def summarize(event)
|
||||
case event.action
|
||||
when "published"
|
||||
@@ -39,12 +35,4 @@ class EventSummary < ApplicationRecord
|
||||
"#{event.creator.name} changed title from '#{event.particulars.dig('particulars', 'old_title')}' to '#{event.particulars.dig('particulars', 'new_title')}'."
|
||||
end
|
||||
end
|
||||
|
||||
def boosts_summary
|
||||
if tally = events.boosts.group(:creator).count.presence
|
||||
tally.map do |creator, count|
|
||||
"#{creator.name} +#{count}"
|
||||
end.to_sentence + "."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module Filter::Fields
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
INDEXES = %w[ most_boosted newest oldest latest stalled ]
|
||||
INDEXES = %w[ newest oldest latest stalled ]
|
||||
|
||||
delegate :default_value?, to: :class
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<%= form_with url: card_boosts_path(card), class: "pad-inline flex align-center gap" do %>
|
||||
<span class="overflow-ellipsis">
|
||||
<strong><%= number_field_tag :boost_count, card.boosts_count, min: 1, class: "boost__input input", autocomplete: "off" %></strong>
|
||||
<span><%= card.boosts_count == 1 ? "boost" : "boosts" %></span>
|
||||
</span>
|
||||
<%= tag.button class: "btn", type: :submit, style: "font-size: 0.4em" do %>
|
||||
<%= icon_tag "add" %>
|
||||
<span class="for-screen-reader">Boost</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -1,7 +0,0 @@
|
||||
<%= turbo_stream.update dom_id(@card, :boosts) do %>
|
||||
<%= render "cards/boosts/boosts", card: @card %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.replace dom_id(@card, :messages) do %>
|
||||
<%= render "cards/messages", card: @card %>
|
||||
<% end %>
|
||||
@@ -35,7 +35,6 @@ Rails.application.routes.draw do
|
||||
resource :goldness
|
||||
|
||||
resources :assignments
|
||||
resources :boosts
|
||||
resources :stagings
|
||||
resources :taggings
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class RemoveBoostsCountFromCards < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_column :cards, :boosts_count
|
||||
end
|
||||
end
|
||||
Generated
+1
-3
@@ -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_04_12_084635) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_04_12_162339) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.integer "collection_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
@@ -113,7 +113,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_12_084635) do
|
||||
t.float "activity_score", default: 0.0, null: false
|
||||
t.datetime "activity_score_at"
|
||||
t.float "activity_score_order", default: 0.0, null: false
|
||||
t.integer "boosts_count", default: 0, null: false
|
||||
t.integer "collection_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.integer "creator_id", null: false
|
||||
@@ -292,7 +291,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_12_084635) do
|
||||
t.datetime "created_at", null: false
|
||||
t.string "title"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id", "title"], name: "index_tags_on_account_id_and_title", unique: true
|
||||
t.index ["account_id"], name: "index_tags_on_account_id"
|
||||
end
|
||||
|
||||
|
||||
+1
-28
@@ -412,16 +412,6 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: boosts_count
|
||||
cast_type: *1
|
||||
sql_type_metadata: *2
|
||||
'null': false
|
||||
default: 0
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *24
|
||||
- *6
|
||||
- &25 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
@@ -2005,23 +1995,6 @@ indexes:
|
||||
comment:
|
||||
valid: true
|
||||
tags:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: tags
|
||||
name: index_tags_on_account_id_and_title
|
||||
unique: true
|
||||
columns:
|
||||
- account_id
|
||||
- title
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: tags
|
||||
name: index_tags_on_account_id
|
||||
@@ -2154,4 +2127,4 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
version: 20250412084635
|
||||
version: 20250412162339
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class Cards::BoostsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "create" do
|
||||
boost_count = cards(:logo).boosts_count
|
||||
|
||||
assert_difference "cards(:logo).reload.boosts_count", +1 do
|
||||
post card_boosts_path(cards(:logo), params: { boost_count: boost_count }, format: :turbo_stream)
|
||||
end
|
||||
|
||||
assert_turbo_stream action: :update, target: dom_id(cards(:logo), :boosts)
|
||||
end
|
||||
|
||||
test "create with value" do
|
||||
boost_count = 10
|
||||
|
||||
assert_changes "cards(:logo).reload.boosts_count", to: boost_count do
|
||||
post card_boosts_path(cards(:logo), params: { boost_count: boost_count }, format: :turbo_stream)
|
||||
end
|
||||
|
||||
assert_turbo_stream action: :update, target: dom_id(cards(:logo), :boosts)
|
||||
end
|
||||
end
|
||||
Vendored
-1
@@ -4,7 +4,6 @@ logo:
|
||||
title: The logo isn't big enough
|
||||
due_on: <%= 3.days.from_now %>
|
||||
created_at: <%= 1.week.ago %>
|
||||
boosts_count: 5
|
||||
activity_score: 7
|
||||
status: published
|
||||
last_active_at: <%= Time.current %>
|
||||
|
||||
Vendored
-35
@@ -13,13 +13,6 @@ logo_assignment_jz:
|
||||
particulars: <%= { assignee_ids: [ ActiveRecord::FixtureSet.identify(:jz) ] }.to_json %>
|
||||
created_at: <%= 1.week.ago + 1.hour %>
|
||||
|
||||
logo_boost_dhh:
|
||||
creator: david
|
||||
card: logo
|
||||
action: boosted
|
||||
summary: logo_initial_activity
|
||||
created_at: <%= 1.week.ago + 2.hours %>
|
||||
|
||||
logo_assignment_km:
|
||||
creator: david
|
||||
card: logo
|
||||
@@ -28,34 +21,6 @@ logo_assignment_km:
|
||||
particulars: <%= { assignee_ids: [ ActiveRecord::FixtureSet.identify(:kevin) ] }.to_json %>
|
||||
created_at: <%= 1.day.ago %>
|
||||
|
||||
logo_boost_km1:
|
||||
creator: kevin
|
||||
card: logo
|
||||
action: boosted
|
||||
summary: logo_second_activity
|
||||
created_at: <%= 1.day.ago + 1.hour %>
|
||||
|
||||
logo_boost_km2:
|
||||
creator: kevin
|
||||
card: logo
|
||||
action: boosted
|
||||
summary: logo_second_activity
|
||||
created_at: <%= 1.day.ago + 2.hours %>
|
||||
|
||||
logo_boost_jz1:
|
||||
creator: jz
|
||||
card: logo
|
||||
action: boosted
|
||||
summary: logo_second_activity
|
||||
created_at: <%= 1.day.ago + 3.hours %>
|
||||
|
||||
logo_boost_jz2:
|
||||
creator: jz
|
||||
card: logo
|
||||
action: boosted
|
||||
summary: logo_third_activity
|
||||
created_at: <%= 1.hour.ago %>
|
||||
|
||||
layout_published:
|
||||
creator: david
|
||||
card: layout
|
||||
|
||||
Vendored
+2
-2
@@ -2,5 +2,5 @@ jz_assignments:
|
||||
creator: david
|
||||
tags: mobile
|
||||
assignees: jz
|
||||
fields: <%= { indexed_by: :most_boosted }.to_json %>
|
||||
params_digest: <%= Filter.digest_params({ indexed_by: :most_boosted, tag_ids: [ ActiveRecord::FixtureSet.identify(:mobile) ], assignee_ids: [ ActiveRecord::FixtureSet.identify(:jz) ] }) %>
|
||||
fields: <%= { indexed_by: :newest }.to_json %>
|
||||
params_digest: <%= Filter.digest_params({ indexed_by: :newest, tag_ids: [ ActiveRecord::FixtureSet.identify(:mobile) ], assignee_ids: [ ActiveRecord::FixtureSet.identify(:jz) ] }) %>
|
||||
|
||||
@@ -13,13 +13,6 @@ class CardMessagesTest < ActionDispatch::IntegrationTest
|
||||
assert_predicate card.messages.last, :event_summary?
|
||||
assert_equal "created", card.messages.last.messageable.events.sole.action
|
||||
|
||||
# Boost it
|
||||
post card_boosts_path(card, format: :turbo_stream)
|
||||
assert_equal 1, card.messages.count
|
||||
assert_predicate card.messages.last, :event_summary?
|
||||
assert_equal 2, card.messages.last.event_summary.events.count
|
||||
assert_equal "boosted", card.messages.last.messageable.events.last.action
|
||||
|
||||
# Comment on it
|
||||
post collection_card_comments_url(collections(:writebook), card), params: { comment: { body: "Agreed." } }
|
||||
assert_equal 2, card.messages.count
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class BoostTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
||||
@@ -1,52 +1,6 @@
|
||||
require "test_helper"
|
||||
|
||||
class Card::ScorableTest < ActiveSupport::TestCase
|
||||
test "recent activity counts more than older activity in the ordering" do
|
||||
with_current_user :kevin do
|
||||
travel_to 5.days.ago
|
||||
card_old = collections(:writebook).cards.create! status: :published, title: "old"
|
||||
card_mid = collections(:writebook).cards.create! status: :published, title: "mid"
|
||||
card_new = collections(:writebook).cards.create! status: :published, title: "new"
|
||||
|
||||
card_old.boost!
|
||||
card_old.boost!
|
||||
|
||||
travel_back
|
||||
travel_to 2.days.ago
|
||||
card_mid.boost!
|
||||
|
||||
travel_back
|
||||
card_new.boost!
|
||||
|
||||
assert_equal %w[ new mid old ], Card.where(id: [ card_old, card_mid, card_new ]).ordered_by_activity.map(&:title)
|
||||
end
|
||||
end
|
||||
|
||||
test "items with old activity are more stale than those with none, or with new activity" do
|
||||
with_current_user :kevin do
|
||||
travel_to 20.days.ago
|
||||
card_old = collections(:writebook).cards.create! status: :published, title: "old"
|
||||
card_new = collections(:writebook).cards.create! status: :published, title: "new"
|
||||
card_none = collections(:writebook).cards.create! status: :published, title: "none"
|
||||
|
||||
card_old.boost!
|
||||
card_old.boost!
|
||||
|
||||
travel_back
|
||||
travel_to 2.days.ago
|
||||
card_new.boost!
|
||||
card_new.boost!
|
||||
|
||||
travel_back
|
||||
|
||||
assert_equal %w[ old new none ], Card.where(id: [ card_none, card_old, card_new ]).ordered_by_staleness.map(&:title)
|
||||
|
||||
card_old.boost!
|
||||
|
||||
assert_equal %w[ new old none ], Card.where(id: [ card_none, card_old, card_new ]).ordered_by_staleness.map(&:title)
|
||||
end
|
||||
end
|
||||
|
||||
test "cards with no activity have a valid activity_score_order" do
|
||||
card = Card.create! collection: collections(:writebook), creator: users(:kevin)
|
||||
|
||||
|
||||
@@ -13,14 +13,6 @@ class CardTest < ActiveSupport::TestCase
|
||||
assert_equal "Agreed.", cards(:logo).messages.comments.last.messageable.body.to_plain_text.chomp
|
||||
end
|
||||
|
||||
test "boosting" do
|
||||
assert_changes -> { cards(:logo).activity_score } do
|
||||
assert_difference -> { cards(:logo).boosts_count }, +1 do
|
||||
cards(:logo).boost!(cards(:logo).boosts_count+ 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "assignment states" do
|
||||
assert cards(:logo).assigned_to?(users(:kevin))
|
||||
assert_not cards(:logo).assigned_to?(users(:david))
|
||||
@@ -74,11 +66,6 @@ class CardTest < ActiveSupport::TestCase
|
||||
assert_includes Card.search("haggis"), card
|
||||
end
|
||||
|
||||
test "ordering by boosts" do
|
||||
cards(:layout).update! boosts_count: 1_000
|
||||
assert_equal cards(:layout, :logo, :shipping, :text), Card.ordered_by_boosts
|
||||
end
|
||||
|
||||
test "closed" do
|
||||
assert_equal [ cards(:shipping) ], Card.closed
|
||||
end
|
||||
|
||||
@@ -2,9 +2,8 @@ require "test_helper"
|
||||
|
||||
class EventSummaryTest < ActiveSupport::TestCase
|
||||
test "body" do
|
||||
assert_equal "Added by David. Assigned to JZ. David +1.", event_summaries(:logo_initial_activity).body
|
||||
assert_equal "Assigned to Kevin. Kevin +2 and JZ +1.", event_summaries(:logo_second_activity).body
|
||||
assert_equal "JZ +1.", event_summaries(:logo_third_activity).body
|
||||
assert_equal "Added by David. Assigned to JZ.", event_summaries(:logo_initial_activity).body
|
||||
assert_equal "Assigned to Kevin.", event_summaries(:logo_second_activity).body
|
||||
assert_equal "Added by Kevin.", event_summaries(:text_initial_activity).body
|
||||
end
|
||||
end
|
||||
|
||||
@@ -101,13 +101,13 @@ class FilterTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "summary" do
|
||||
assert_equal "Most boosted, tagged #mobile, and assigned to JZ ", filters(:jz_assignments).summary
|
||||
assert_equal "Newest, tagged #mobile, and assigned to JZ ", filters(:jz_assignments).summary
|
||||
|
||||
filters(:jz_assignments).update!(stages: workflow_stages(:qa_triage, :qa_in_progress))
|
||||
assert_equal "Most boosted, tagged #mobile, assigned to JZ, and staged in Triage or In progress ", filters(:jz_assignments).summary
|
||||
assert_equal "Newest, tagged #mobile, assigned to JZ, and staged in Triage or In progress ", filters(:jz_assignments).summary
|
||||
|
||||
filters(:jz_assignments).update!(stages: [], assignees: [], tags: [], collections: [ collections(:writebook) ])
|
||||
assert_equal "Most boosted in Writebook", filters(:jz_assignments).summary
|
||||
assert_equal "Newest in Writebook", filters(:jz_assignments).summary
|
||||
|
||||
filters(:jz_assignments).update!(indexed_by: "stalled")
|
||||
assert_equal "Stalled in Writebook", filters(:jz_assignments).summary
|
||||
|
||||
@@ -5,14 +5,6 @@ class NotifierTest < ActiveSupport::TestCase
|
||||
assert_kind_of Notifier::Published, Notifier.for(events(:logo_published))
|
||||
end
|
||||
|
||||
test "for does not raise an error when the event is not notifiable" do
|
||||
assert_nothing_raised do
|
||||
assert_no_difference -> { Notification.count } do
|
||||
Notifier.for(events(:logo_boost_dhh))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "generate does not create notifications if the event was system-generated" do
|
||||
cards(:logo).drafted!
|
||||
events(:logo_published).update!(creator: accounts("37s").users.system)
|
||||
|
||||
Reference in New Issue
Block a user