Add postponable concern
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
class Card < ApplicationRecord
|
||||
include Assignable, Attachments, Cacheable, Closeable, Colored, Engageable, Entropic, Eventable,
|
||||
Golden, Mentions, Multistep, Pinnable, Promptable, Readable, Searchable,
|
||||
Golden, Mentions, Multistep, Pinnable, Postponable, Promptable, Readable, Searchable,
|
||||
Staged, Stallable, Statuses, Taggable, Watchable
|
||||
|
||||
belongs_to :collection, touch: true
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
module Card::Engageable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_one :engagement, dependent: :destroy, class_name: "Card::Engagement"
|
||||
|
||||
scope :considering, -> { published_or_drafted_by(Current.user).open.where.missing(:engagement) }
|
||||
scope :on_deck, -> { published.open.joins(:engagement).where(engagement: { status: "on_deck" }) }
|
||||
scope :doing, -> { published.open.joins(:engagement).where(engagement: { status: "doing" }) }
|
||||
|
||||
scope :by_engagement_status, ->(status) do
|
||||
case status.to_s
|
||||
when "considering" then considering.with_golden_first
|
||||
when "on_deck" then on_deck.with_golden_first
|
||||
when "doing" then doing.with_golden_first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def doing?
|
||||
open? && published? && engagement&.status == "doing"
|
||||
end
|
||||
|
||||
def on_deck?
|
||||
open? && published? && engagement&.status == "on_deck"
|
||||
end
|
||||
|
||||
def considering?
|
||||
open? && published? && engagement.blank?
|
||||
end
|
||||
|
||||
def engagement_status
|
||||
if doing?
|
||||
"doing"
|
||||
elsif on_deck?
|
||||
"on_deck"
|
||||
elsif considering?
|
||||
"considering"
|
||||
end
|
||||
end
|
||||
|
||||
def engage
|
||||
unless doing?
|
||||
reengage(status: "doing")
|
||||
end
|
||||
end
|
||||
|
||||
def move_to_on_deck
|
||||
unless on_deck?
|
||||
reengage(status: "on_deck")
|
||||
end
|
||||
end
|
||||
|
||||
def reconsider
|
||||
transaction do
|
||||
reopen
|
||||
engagement&.destroy
|
||||
activity_spike&.destroy
|
||||
update!(stage: nil)
|
||||
touch_last_active_at
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def reengage(status:)
|
||||
transaction do
|
||||
reopen
|
||||
engagement&.destroy
|
||||
create_engagement!(status:)
|
||||
if status == "doing" && stage.blank?
|
||||
update!(stage: collection.initial_workflow_stage)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
class Card::NotNow < ApplicationRecord
|
||||
belongs_to :card, class_name: "::Card", touch: true
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
module Card::Postponable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_one :not_now, dependent: :destroy, class_name: "Card::NotNow"
|
||||
|
||||
scope :not_now, -> { joins(:not_now) }
|
||||
scope :active, -> { where.missing(:not_now) }
|
||||
end
|
||||
|
||||
def postponed?
|
||||
not_now.present?
|
||||
end
|
||||
|
||||
def active?
|
||||
!postponed?
|
||||
end
|
||||
|
||||
def postpone
|
||||
unless postponed?
|
||||
create_not_now!
|
||||
end
|
||||
end
|
||||
|
||||
def resume
|
||||
if postponed?
|
||||
not_now.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
class CreateCardNotNows < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
create_table :card_not_nows do |t|
|
||||
t.references :card, null: false, foreign_key: true, index: { unique: true }
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
Generated
+9
-1
@@ -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_09_24_100149) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_09_24_123001) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.datetime "accessed_at"
|
||||
t.integer "collection_id", null: false
|
||||
@@ -131,6 +131,13 @@ ActiveRecord::Schema[8.1].define(version: 2025_09_24_100149) do
|
||||
t.index ["card_id"], name: "index_card_goldnesses_on_card_id", unique: true
|
||||
end
|
||||
|
||||
create_table "card_not_nows", force: :cascade do |t|
|
||||
t.integer "card_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["card_id"], name: "index_card_not_nows_on_card_id", unique: true
|
||||
end
|
||||
|
||||
create_table "cards", force: :cascade do |t|
|
||||
t.integer "collection_id", null: false
|
||||
t.integer "column_id"
|
||||
@@ -519,6 +526,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_09_24_100149) do
|
||||
add_foreign_key "ai_quotas", "users"
|
||||
add_foreign_key "card_activity_spikes", "cards"
|
||||
add_foreign_key "card_goldnesses", "cards"
|
||||
add_foreign_key "card_not_nows", "cards"
|
||||
add_foreign_key "cards", "columns"
|
||||
add_foreign_key "cards", "workflow_stages", column: "stage_id"
|
||||
add_foreign_key "closures", "cards"
|
||||
|
||||
+25
-1
@@ -433,6 +433,11 @@ columns:
|
||||
- *5
|
||||
- *6
|
||||
- *9
|
||||
card_not_nows:
|
||||
- *23
|
||||
- *5
|
||||
- *6
|
||||
- *9
|
||||
cards:
|
||||
- *24
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
@@ -1514,6 +1519,7 @@ primary_keys:
|
||||
card_activity_spikes: id
|
||||
card_engagements: id
|
||||
card_goldnesses: id
|
||||
card_not_nows: id
|
||||
cards: id
|
||||
closers_filters:
|
||||
closure_reasons: id
|
||||
@@ -1569,6 +1575,7 @@ data_sources:
|
||||
card_activity_spikes: true
|
||||
card_engagements: true
|
||||
card_goldnesses: true
|
||||
card_not_nows: true
|
||||
cards: true
|
||||
closers_filters: true
|
||||
closure_reasons: true
|
||||
@@ -2000,6 +2007,23 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
card_not_nows:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: card_not_nows
|
||||
name: index_card_not_nows_on_card_id
|
||||
unique: true
|
||||
columns:
|
||||
- card_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
cards:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: cards
|
||||
@@ -3252,4 +3276,4 @@ indexes:
|
||||
comment:
|
||||
valid: true
|
||||
workflows: []
|
||||
version: 20250924100149
|
||||
version: 20250924123001
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class Card::EngageableTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
Current.session = sessions(:david)
|
||||
end
|
||||
|
||||
test "check the engagement status of a card" do
|
||||
assert cards(:logo).doing?
|
||||
assert_not cards(:text).doing?
|
||||
|
||||
assert_not cards(:logo).considering?
|
||||
assert cards(:text).considering?
|
||||
|
||||
assert_not cards(:logo).on_deck?
|
||||
assert_not cards(:text).on_deck?
|
||||
|
||||
assert_equal "doing", cards(:logo).engagement_status
|
||||
assert_equal "considering", cards(:text).engagement_status
|
||||
end
|
||||
|
||||
test "change the engagement" do
|
||||
assert_changes -> { cards(:text).reload.doing? }, to: true do
|
||||
cards(:text).engage
|
||||
end
|
||||
|
||||
assert_changes -> { cards(:logo).reload.doing? }, to: false do
|
||||
cards(:logo).reconsider
|
||||
end
|
||||
end
|
||||
|
||||
test "engaging with closed cards" do
|
||||
cards(:text).close
|
||||
|
||||
assert_not cards(:text).considering?
|
||||
assert_not cards(:text).doing?
|
||||
assert_not cards(:text).on_deck?
|
||||
|
||||
cards(:text).engage
|
||||
assert_not cards(:text).reload.closed?
|
||||
assert cards(:text).doing?
|
||||
|
||||
cards(:text).close
|
||||
cards(:text).reconsider
|
||||
assert_not cards(:text).reload.closed?
|
||||
assert cards(:text).considering?
|
||||
end
|
||||
|
||||
test "scopes" do
|
||||
assert_includes Card.doing, cards(:logo)
|
||||
assert_not_includes Card.doing, cards(:text)
|
||||
|
||||
assert_includes Card.considering, cards(:text)
|
||||
assert_not_includes Card.considering, cards(:logo)
|
||||
|
||||
cards(:text).move_to_on_deck
|
||||
assert_includes Card.on_deck, cards(:text)
|
||||
assert_not_includes Card.on_deck, cards(:logo)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
require "test_helper"
|
||||
|
||||
class Card::PostponableTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
Current.session = sessions(:david)
|
||||
end
|
||||
|
||||
test "check the postponed status of a card" do
|
||||
card = cards(:logo)
|
||||
|
||||
assert_not card.postponed?
|
||||
assert card.active?
|
||||
|
||||
card.postpone
|
||||
assert card.postponed?
|
||||
assert_not card.active?
|
||||
end
|
||||
|
||||
test "postpone and resume a card" do
|
||||
card = cards(:text)
|
||||
|
||||
assert_changes -> { card.reload.postponed? }, to: true do
|
||||
card.postpone
|
||||
end
|
||||
|
||||
assert_changes -> { card.reload.postponed? }, to: false do
|
||||
card.resume
|
||||
end
|
||||
end
|
||||
|
||||
test "scopes" do
|
||||
logo = cards(:logo)
|
||||
text = cards(:text)
|
||||
|
||||
logo.postpone
|
||||
|
||||
assert_includes Card.not_now, logo
|
||||
assert_not_includes Card.not_now, text
|
||||
|
||||
assert_includes Card.active, text
|
||||
assert_not_includes Card.active, logo
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user