From 7406a1039f5d4d3ee9ff7ac6fb3ffb7c54f8123f Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 16:48:12 +0200 Subject: [PATCH 01/16] Add models to track gold cards and implement basic toggle behavior --- app/assets/stylesheets/cards.css | 4 + .../cards/goldenesses_controller.rb | 13 + app/models/card.rb | 5 +- app/models/card/golden.rb | 22 ++ app/models/card/goldness.rb | 3 + app/views/cards/_golden_toggle.html.erb | 11 + app/views/cards/display/_perma.html.erb | 2 +- app/views/cards/show.html.erb | 6 +- config/routes.rb | 1 + .../20250410141409_create_card_goldnesses.rb | 9 + db/schema.rb | 10 +- db/schema_cache.yml | 288 ++++++++++-------- 12 files changed, 233 insertions(+), 141 deletions(-) create mode 100644 app/controllers/cards/goldenesses_controller.rb create mode 100644 app/models/card/golden.rb create mode 100644 app/models/card/goldness.rb create mode 100644 app/views/cards/_golden_toggle.html.erb create mode 100644 db/migrate/20250410141409_create_card_goldnesses.rb diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css index 4a5e318d7..1ffc3f740 100644 --- a/app/assets/stylesheets/cards.css +++ b/app/assets/stylesheets/cards.css @@ -97,6 +97,10 @@ } } + .card--golden { + outline: 5px solid orange; + } + .card__actions { position: absolute; inset: var(--actions-block-inset) auto auto calc(var(--actions-inline-inset) * -1); diff --git a/app/controllers/cards/goldenesses_controller.rb b/app/controllers/cards/goldenesses_controller.rb new file mode 100644 index 000000000..974610569 --- /dev/null +++ b/app/controllers/cards/goldenesses_controller.rb @@ -0,0 +1,13 @@ +class Cards::GoldenessesController < ApplicationController + include CardScoped + + def create + @card.promote_to_golden + redirect_to @card + end + + def destroy + @card.demote_from_golden + redirect_to @card + end +end diff --git a/app/models/card.rb b/app/models/card.rb index c58507125..46907bf3d 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,6 +1,7 @@ class Card < ApplicationRecord - include Assignable, Boostable, Colored, Commentable, Engageable, Eventable, - Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged, Statuses, Taggable, Watchable + include Assignable, Boostable, Colored, Commentable, Engageable, Eventable, Golden, + Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged, + Statuses, Taggable, Watchable belongs_to :collection, touch: true belongs_to :creator, class_name: "User", default: -> { Current.user } diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb new file mode 100644 index 000000000..339b8cab6 --- /dev/null +++ b/app/models/card/golden.rb @@ -0,0 +1,22 @@ +module Card::Golden + extend ActiveSupport::Concern + + included do + scope :golden, -> { joins(:goldness) } + scope :non_golden, -> { where.missing(:goldness) } + + has_one :goldness, dependent: :destroy, class_name: "Card::Goldness" + end + + def golden? + goldness.present? + end + + def promote_to_golden + create_goldness! unless golden? + end + + def demote_from_golden + goldness&.destroy + end +end diff --git a/app/models/card/goldness.rb b/app/models/card/goldness.rb new file mode 100644 index 000000000..5ef88fc0b --- /dev/null +++ b/app/models/card/goldness.rb @@ -0,0 +1,3 @@ +class Card::Goldness < ApplicationRecord + belongs_to :card +end diff --git a/app/views/cards/_golden_toggle.html.erb b/app/views/cards/_golden_toggle.html.erb new file mode 100644 index 000000000..e1c475484 --- /dev/null +++ b/app/views/cards/_golden_toggle.html.erb @@ -0,0 +1,11 @@ +<% if @card.golden? %> + <%= button_to card_goldeness_path(@card), method: :delete, class: "btn btn--reversed" do %> + <%= icon_tag "star" %> + Demote to normal + <% end %> +<% else %> + <%= button_to card_goldeness_path(@card), class: "btn" do %> + <%= icon_tag "star" %> + Promote to golden + <% end %> +<% end %> diff --git a/app/views/cards/display/_perma.html.erb b/app/views/cards/display/_perma.html.erb index 4b205e33b..309a6dd86 100644 --- a/app/views/cards/display/_perma.html.erb +++ b/app/views/cards/display/_perma.html.erb @@ -1,5 +1,5 @@ <% cache card do %> -
diff --git a/app/views/cards/show.html.erb b/app/views/cards/show.html.erb index 753c2e464..d7a122b37 100644 --- a/app/views/cards/show.html.erb +++ b/app/views/cards/show.html.erb @@ -55,11 +55,7 @@ <%= render "cards/display/perma", card: @card %>
- + <%= render "cards/golden_toggle" %> <%= render "cards/image", card: @card %> <%= button_to collection_card_path(@card.collection, @card), diff --git a/config/routes.rb b/config/routes.rb index cf2b5fe76..25e6a0f62 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,7 @@ Rails.application.routes.draw do resource :reading resource :recover resource :watch + resource :goldeness resources :assignments resources :boosts diff --git a/db/migrate/20250410141409_create_card_goldnesses.rb b/db/migrate/20250410141409_create_card_goldnesses.rb new file mode 100644 index 000000000..f8268c243 --- /dev/null +++ b/db/migrate/20250410141409_create_card_goldnesses.rb @@ -0,0 +1,9 @@ +class CreateCardGoldnesses < ActiveRecord::Migration[8.1] + def change + create_table :card_goldnesses do |t| + t.references :card, null: false, foreign_key: true, index: { unique: true } + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b7e50d935..4fa6fa273 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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_09_201424) do +ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do create_table "accesses", force: :cascade do |t| t.integer "collection_id", null: false t.datetime "created_at", null: false @@ -102,6 +102,13 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_09_201424) do t.index ["card_id"], name: "index_card_engagements_on_card_id" end + create_table "card_goldnesses", 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_goldnesses_on_card_id", unique: true + end + create_table "cards", force: :cascade do |t| t.float "activity_score", default: 0.0, null: false t.datetime "activity_score_at" @@ -333,6 +340,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_09_201424) do add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + add_foreign_key "card_goldnesses", "cards" add_foreign_key "cards", "workflow_stages", column: "stage_id" add_foreign_key "closures", "cards" add_foreign_key "closures", "users" diff --git a/db/schema_cache.yml b/db/schema_cache.yml index 592648228..3233fb2f6 100644 --- a/db/schema_cache.yml +++ b/db/schema_cache.yml @@ -21,7 +21,7 @@ columns: default_function: collation: comment: - - &23 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + - &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: collection_id cast_type: *1 @@ -341,7 +341,7 @@ columns: - *5 - *19 - *20 - - &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + - &21 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: card_id cast_type: *1 @@ -367,16 +367,21 @@ columns: comment: - *6 - *9 + card_goldnesses: + - *5 + - *21 + - *6 + - *9 cards: - *5 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: activity_score - cast_type: &21 !ruby/object:ActiveModel::Type::Float + cast_type: &22 !ruby/object:ActiveModel::Type::Float precision: scale: limit: - sql_type_metadata: &22 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata + sql_type_metadata: &23 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata sql_type: float type: :float limit: @@ -400,8 +405,8 @@ columns: - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: activity_score_order - cast_type: *21 - sql_type_metadata: *22 + cast_type: *22 + sql_type_metadata: *23 'null': false default: 0.0 default_function: @@ -417,7 +422,7 @@ columns: default_function: collation: comment: - - *23 + - *24 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: comments_count @@ -525,7 +530,7 @@ columns: - *9 closures: - *5 - - *24 + - *21 - *6 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: @@ -593,7 +598,7 @@ columns: collation: comment: collections_filters: - - *23 + - *24 - *18 comments: - *5 @@ -619,7 +624,7 @@ columns: default_function: collation: comment: - - *24 + - *21 - *6 - *25 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column @@ -712,7 +717,7 @@ columns: comment: messages: - *5 - - *24 + - *21 - *6 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: @@ -737,7 +742,7 @@ columns: - *9 notifications: - *5 - - *24 + - *21 - *6 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: @@ -783,7 +788,7 @@ columns: - *30 pins: - *5 - - *24 + - *21 - *6 - *9 - *30 @@ -869,7 +874,7 @@ columns: - *30 taggings: - *5 - - *24 + - *21 - *6 - *31 - *9 @@ -927,7 +932,7 @@ columns: - *9 watches: - *5 - - *24 + - *21 - *6 - *9 - *30 @@ -984,6 +989,7 @@ primary_keys: assigners_filters: assignments: id card_engagements: id + card_goldnesses: id cards: id closure_reasons: id closures: id @@ -1020,6 +1026,7 @@ data_sources: assigners_filters: true assignments: true card_engagements: true + card_goldnesses: true cards: true closure_reasons: true closures: true @@ -1048,10 +1055,9 @@ indexes: accesses: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: accesses - name: index_accesses_on_collection_id_and_user_id - unique: true + name: index_accesses_on_user_id + unique: false columns: - - collection_id - user_id lengths: {} orders: {} @@ -1081,9 +1087,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: accesses - name: index_accesses_on_user_id - unique: false + name: index_accesses_on_collection_id_and_user_id + unique: true columns: + - collection_id - user_id lengths: {} orders: {} @@ -1303,10 +1310,9 @@ indexes: assignments: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: assignments - name: index_assignments_on_assignee_id_and_card_id - unique: true + name: index_assignments_on_card_id + unique: false columns: - - assignee_id - card_id lengths: {} orders: {} @@ -1320,9 +1326,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: assignments - name: index_assignments_on_card_id - unique: false + name: index_assignments_on_assignee_id_and_card_id + unique: true columns: + - assignee_id - card_id lengths: {} orders: {} @@ -1351,7 +1358,57 @@ indexes: nulls_not_distinct: comment: valid: true + card_goldnesses: + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: card_goldnesses + name: index_card_goldnesses_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 + name: index_cards_on_stage_id + unique: false + columns: + - stage_id + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: cards + name: index_cards_on_last_active_at_and_status + unique: false + columns: + - last_active_at + - status + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: cards name: index_cards_on_collection_id @@ -1384,39 +1441,6 @@ indexes: nulls_not_distinct: comment: valid: true - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: cards - name: index_cards_on_last_active_at_and_status - unique: false - columns: - - last_active_at - - status - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: cards - name: index_cards_on_stage_id - unique: false - columns: - - stage_id - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true closure_reasons: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: closure_reasons @@ -1435,6 +1459,22 @@ indexes: comment: valid: true closures: + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: closures + name: index_closures_on_user_id + unique: false + columns: + - user_id + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: closures name: index_closures_on_card_id @@ -1468,29 +1508,13 @@ indexes: nulls_not_distinct: comment: valid: true - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: closures - name: index_closures_on_user_id - unique: false - columns: - - user_id - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true collections: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: collections - name: index_collections_on_account_id + name: index_collections_on_workflow_id unique: false columns: - - account_id + - workflow_id lengths: {} orders: {} opclasses: {} @@ -1519,10 +1543,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: collections - name: index_collections_on_workflow_id + name: index_collections_on_account_id unique: false columns: - - workflow_id + - account_id lengths: {} orders: {} opclasses: {} @@ -1536,10 +1560,10 @@ indexes: collections_filters: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: collections_filters - name: index_collections_filters_on_collection_id + name: index_collections_filters_on_filter_id unique: false columns: - - collection_id + - filter_id lengths: {} orders: {} opclasses: {} @@ -1552,10 +1576,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: collections_filters - name: index_collections_filters_on_filter_id + name: index_collections_filters_on_collection_id unique: false columns: - - filter_id + - collection_id lengths: {} orders: {} opclasses: {} @@ -1602,22 +1626,6 @@ indexes: valid: true event_summaries: [] events: - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: events - name: index_events_on_card_id - unique: false - columns: - - card_id - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: events name: index_events_on_summary_id_and_action @@ -1651,6 +1659,22 @@ indexes: nulls_not_distinct: comment: valid: true + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: events + name: index_events_on_card_id + unique: false + columns: + - card_id + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true filters: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: filters @@ -1736,22 +1760,6 @@ indexes: comment: valid: true messages: - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: messages - name: index_messages_on_card_id - unique: false - columns: - - card_id - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: messages name: index_messages_on_messageable @@ -1769,10 +1777,9 @@ indexes: nulls_not_distinct: comment: valid: true - notifications: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: notifications - name: index_notifications_on_card_id + table: messages + name: index_messages_on_card_id unique: false columns: - card_id @@ -1786,6 +1793,7 @@ indexes: nulls_not_distinct: comment: valid: true + notifications: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: notifications name: index_notifications_on_user_id @@ -1855,13 +1863,28 @@ indexes: nulls_not_distinct: comment: valid: true + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: notifications + name: index_notifications_on_card_id + unique: false + columns: + - card_id + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true pins: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: pins - name: index_pins_on_card_id_and_user_id - unique: true + name: index_pins_on_user_id + unique: false columns: - - card_id - user_id lengths: {} orders: {} @@ -1891,9 +1914,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: pins - name: index_pins_on_user_id - unique: false + name: index_pins_on_card_id_and_user_id + unique: true columns: + - card_id - user_id lengths: {} orders: {} @@ -1959,10 +1983,9 @@ indexes: taggings: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: taggings - name: index_taggings_on_card_id_and_tag_id - unique: true + name: index_taggings_on_tag_id + unique: false columns: - - card_id - tag_id lengths: {} orders: {} @@ -1976,9 +1999,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: taggings - name: index_taggings_on_tag_id - unique: false + name: index_taggings_on_card_id_and_tag_id + unique: true columns: + - card_id - tag_id lengths: {} orders: {} @@ -2076,10 +2100,10 @@ indexes: watches: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: watches - name: index_watches_on_card_id + name: index_watches_on_user_id unique: false columns: - - card_id + - user_id lengths: {} orders: {} opclasses: {} @@ -2092,10 +2116,10 @@ indexes: valid: true - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: watches - name: index_watches_on_user_id + name: index_watches_on_card_id unique: false columns: - - user_id + - card_id lengths: {} orders: {} opclasses: {} @@ -2140,4 +2164,4 @@ indexes: nulls_not_distinct: comment: valid: true -version: 20250409201424 +version: 20250410141409 From 2e5b25a30c14f07afd5b23233b293931c2fe1596 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 17:05:30 +0200 Subject: [PATCH 02/16] Always place golden cards first --- app/controllers/cards_controller.rb | 6 +++--- app/models/card/golden.rb | 6 ++++++ app/views/cards/display/_preview.html.erb | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index d0b751613..bdb40be8c 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -10,7 +10,7 @@ class CardsController < ApplicationController def index @considering = page_and_filter_for @filter.with(engagement_status: "considering"), per_page: PAGE_SIZE - @doing = page_and_filter_for @filter.with(engagement_status: "doing"), per_page: PAGE_SIZE + @doing = page_and_filter_for @filter.with(engagement_status: "doing"), cards: @filter.cards.golden_first, per_page: PAGE_SIZE @closed = page_and_filter_for @filter.with(indexed_by: "closed"), per_page: PAGE_SIZE end @@ -39,9 +39,9 @@ class CardsController < ApplicationController @card = @collection.cards.find params[:id] end - def page_and_filter_for(filter, per_page: nil) + def page_and_filter_for(filter, per_page: nil, cards: filter.cards) OpenStruct.new \ - page: GearedPagination::Recordset.new(filter.cards, per_page:).page(1), + page: GearedPagination::Recordset.new(cards, per_page:).page(1), filter: filter end diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index 339b8cab6..bc912431c 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -6,6 +6,12 @@ module Card::Golden scope :non_golden, -> { where.missing(:goldness) } has_one :goldness, dependent: :destroy, class_name: "Card::Goldness" + + scope :golden_first, -> do + left_outer_joins(:goldness).tap do |relation| + relation.order_values.unshift("card_goldnesses.id IS NULL") + end + end end def golden? diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index 035c72e58..e7a723a1b 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -1,5 +1,5 @@ <% cache [ card ] do %> -
From 9029853bdfe31a91165b68d0cd465ccf6f76c503 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 17:11:00 +0200 Subject: [PATCH 03/16] Only show the button when card is in "doing" --- app/views/cards/_golden_toggle.html.erb | 6 +++--- app/views/cards/show.html.erb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/cards/_golden_toggle.html.erb b/app/views/cards/_golden_toggle.html.erb index e1c475484..f04e14355 100644 --- a/app/views/cards/_golden_toggle.html.erb +++ b/app/views/cards/_golden_toggle.html.erb @@ -1,10 +1,10 @@ -<% if @card.golden? %> - <%= button_to card_goldeness_path(@card), method: :delete, class: "btn btn--reversed" do %> +<% if card.golden? %> + <%= button_to card_goldeness_path(card), method: :delete, class: "btn btn--reversed" do %> <%= icon_tag "star" %> Demote to normal <% end %> <% else %> - <%= button_to card_goldeness_path(@card), class: "btn" do %> + <%= button_to card_goldeness_path(card), class: "btn" do %> <%= icon_tag "star" %> Promote to golden <% end %> diff --git a/app/views/cards/show.html.erb b/app/views/cards/show.html.erb index d7a122b37..2ee0d121e 100644 --- a/app/views/cards/show.html.erb +++ b/app/views/cards/show.html.erb @@ -55,7 +55,7 @@ <%= render "cards/display/perma", card: @card %>
- <%= render "cards/golden_toggle" %> + <%= render "cards/golden_toggle", card: @card if @card.doing? %> <%= render "cards/image", card: @card %> <%= button_to collection_card_path(@card.collection, @card), From 9747d590eae0fd0d4eb34598cdbbac92318c48af Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 17:16:36 +0200 Subject: [PATCH 04/16] Not used --- app/models/card/golden.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index bc912431c..b3206e248 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -3,7 +3,6 @@ module Card::Golden included do scope :golden, -> { joins(:goldness) } - scope :non_golden, -> { where.missing(:goldness) } has_one :goldness, dependent: :destroy, class_name: "Card::Goldness" From fac2fce3d551bbc0618771e24027776dff786f09 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 17:18:02 +0200 Subject: [PATCH 05/16] Rename scope --- app/controllers/cards_controller.rb | 2 +- app/models/card/golden.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index bdb40be8c..21b6f0dbd 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -10,7 +10,7 @@ class CardsController < ApplicationController def index @considering = page_and_filter_for @filter.with(engagement_status: "considering"), per_page: PAGE_SIZE - @doing = page_and_filter_for @filter.with(engagement_status: "doing"), cards: @filter.cards.golden_first, per_page: PAGE_SIZE + @doing = page_and_filter_for @filter.with(engagement_status: "doing"), cards: @filter.cards.with_golden_first, per_page: PAGE_SIZE @closed = page_and_filter_for @filter.with(indexed_by: "closed"), per_page: PAGE_SIZE end diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index b3206e248..c8553f6be 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -6,7 +6,7 @@ module Card::Golden has_one :goldness, dependent: :destroy, class_name: "Card::Goldness" - scope :golden_first, -> do + scope :with_golden_first, -> do left_outer_joins(:goldness).tap do |relation| relation.order_values.unshift("card_goldnesses.id IS NULL") end From 0c107c5894a6f074ba261d4c8c21ff7c25d62dd0 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Thu, 10 Apr 2025 16:42:40 -0500 Subject: [PATCH 06/16] Fix that cards which were Drafted or in Considering were also being displayed in Doing CC: @jorgemanrubia --- app/controllers/cards_controller.rb | 2 +- app/models/card.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index 21b6f0dbd..1402d5943 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -10,7 +10,7 @@ class CardsController < ApplicationController def index @considering = page_and_filter_for @filter.with(engagement_status: "considering"), per_page: PAGE_SIZE - @doing = page_and_filter_for @filter.with(engagement_status: "doing"), cards: @filter.cards.with_golden_first, per_page: PAGE_SIZE + @doing = page_and_filter_for @filter.with(engagement_status: "doing"), per_page: PAGE_SIZE @closed = page_and_filter_for @filter.with(indexed_by: "closed"), per_page: PAGE_SIZE end diff --git a/app/models/card.rb b/app/models/card.rb index 46907bf3d..bf1007743 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -33,7 +33,7 @@ class Card < ApplicationRecord scope :by_engagement_status, ->(status) do case status.to_s when "considering" then considering - when "doing" then doing + when "doing" then doing.with_golden_first end end From da7a30203cc6f851fccbde82c50748ffb7ff4ff5 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Thu, 10 Apr 2025 17:14:04 -0500 Subject: [PATCH 07/16] Style golden cards --- app/assets/images/golden-ticket.svg | 1 + app/assets/images/star.svg | 1 - app/assets/stylesheets/_global.css | 2 ++ app/assets/stylesheets/cards.css | 15 ++++++++------- app/assets/stylesheets/icons.css | 2 +- app/views/cards/_golden_toggle.html.erb | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 app/assets/images/golden-ticket.svg delete mode 100644 app/assets/images/star.svg diff --git a/app/assets/images/golden-ticket.svg b/app/assets/images/golden-ticket.svg new file mode 100644 index 000000000..99d44fdf8 --- /dev/null +++ b/app/assets/images/golden-ticket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/star.svg b/app/assets/images/star.svg deleted file mode 100644 index 281a18051..000000000 --- a/app/assets/images/star.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/stylesheets/_global.css b/app/assets/stylesheets/_global.css index 8dc17b990..4711ea25d 100644 --- a/app/assets/stylesheets/_global.css +++ b/app/assets/stylesheets/_global.css @@ -31,6 +31,7 @@ --lch-blue: 54% 0.15 255; --lch-blue-light: 95% 0.03 255; --lch-blue-dark: 80% 0.08 255; + --lch-golden: 83% 0.1128 72.43; --lch-orange: 70% 0.2 44; --lch-red: 51% 0.2 31; --lch-green: 65.59% 0.234 142.49; @@ -58,6 +59,7 @@ --color-always-black: oklch(var(--lch-always-black)); --color-always-white: oklch(var(--lch-always-white)); --color-container: oklch(var(--lch-light-blue)); + --color-golden: oklch(var(--lch-golden)); @media (prefers-color-scheme: dark) { --lch-black: 100% 0 0; diff --git a/app/assets/stylesheets/cards.css b/app/assets/stylesheets/cards.css index b8f36e67c..1a8325e45 100644 --- a/app/assets/stylesheets/cards.css +++ b/app/assets/stylesheets/cards.css @@ -98,7 +98,14 @@ } .card--golden { - outline: 5px solid orange; + --border-color: var(--color-bg) !important; + + background-color: var(--color-bg); + background-image: linear-gradient(90deg, oklch(var(--lch-golden) / 0.5) 0%, oklch(var(--lch-golden) / 0.1) 50%, oklch(var(--lch-golden) / 0.75) 100%); + box-shadow: + 0 0 0.5em 0.2em var(--color-golden), + 0 0 1em 0.4em var(--color-golden) !important; + outline: 1px solid var(--color-golden); } .card__actions { @@ -251,12 +258,6 @@ display: inline-flex; margin-block: calc(var(--block-space) * -1) calc(var(--block-space) * -0.33); padding: var(--padding-block) var(--padding-inline); - - &:has(.card__star-input:checked) { - .card { - outline: 4px solid var(--color-negative); - } - } } .card__container--pointing { diff --git a/app/assets/stylesheets/icons.css b/app/assets/stylesheets/icons.css index 1f3d193dc..987210def 100644 --- a/app/assets/stylesheets/icons.css +++ b/app/assets/stylesheets/icons.css @@ -38,6 +38,7 @@ .icon--everyone { --svg: url("everyone.svg "); } .icon--filter { --svg: url("filter.svg "); } .icon--globe { --svg: url("globe.svg "); } + .icon--golden-ticket { --svg: url("golden-ticket.svg "); } .icon--home { --svg: url("home.svg "); } .icon--logout { --svg: url("logout.svg "); } .icon--menu { --svg: url("menu.svg "); } @@ -61,7 +62,6 @@ .icon--rename { --svg: url("rename.svg "); } .icon--settings { --svg: url("settings.svg "); } .icon--share { --svg: url("share.svg "); } - .icon--star { --svg: url("star.svg "); } .icon--tag { --svg: url("tag.svg "); } .icon--thumb-up { --svg: url("thumb-up.svg "); } .icon--trash { --svg: url("trash.svg "); } diff --git a/app/views/cards/_golden_toggle.html.erb b/app/views/cards/_golden_toggle.html.erb index f04e14355..3456bea4b 100644 --- a/app/views/cards/_golden_toggle.html.erb +++ b/app/views/cards/_golden_toggle.html.erb @@ -1,11 +1,11 @@ <% if card.golden? %> <%= button_to card_goldeness_path(card), method: :delete, class: "btn btn--reversed" do %> - <%= icon_tag "star" %> + <%= icon_tag "golden-ticket" %> Demote to normal <% end %> <% else %> <%= button_to card_goldeness_path(card), class: "btn" do %> - <%= icon_tag "star" %> + <%= icon_tag "golden-ticket" %> Promote to golden <% end %> <% end %> From 1bac0b84b32eee1017889451026289458b8dccac Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 09:36:24 +0200 Subject: [PATCH 08/16] Add tests --- .../cards/goldenesses_controller_test.rb | 27 +++++++++++++++++ test/fixtures/card/engagements.yml | 2 +- test/fixtures/card/goldnesses.yml | 2 ++ test/models/card/golden_test.rb | 30 +++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/controllers/cards/goldenesses_controller_test.rb create mode 100644 test/fixtures/card/goldnesses.yml create mode 100644 test/models/card/golden_test.rb diff --git a/test/controllers/cards/goldenesses_controller_test.rb b/test/controllers/cards/goldenesses_controller_test.rb new file mode 100644 index 000000000..245ccc180 --- /dev/null +++ b/test/controllers/cards/goldenesses_controller_test.rb @@ -0,0 +1,27 @@ +require "test_helper" + +class Cards::GoldenessesControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in_as :kevin + end + + test "create" do + card = cards(:text) + + assert_changes -> { card.reload.golden? }, from: false, to: true do + post card_goldeness_url(card) + end + + assert_redirected_to collection_card_url(card.collection, card) + end + + test "destroy" do + card = cards(:logo) + + assert_changes -> { card.reload.golden? }, from: true, to: false do + delete card_goldeness_url(card) + end + + assert_redirected_to collection_card_url(card.collection, card) + end +end diff --git a/test/fixtures/card/engagements.yml b/test/fixtures/card/engagements.yml index f15900c8b..77657385b 100644 --- a/test/fixtures/card/engagements.yml +++ b/test/fixtures/card/engagements.yml @@ -1,2 +1,2 @@ -logo_engagement: +logo: card: logo diff --git a/test/fixtures/card/goldnesses.yml b/test/fixtures/card/goldnesses.yml new file mode 100644 index 000000000..77657385b --- /dev/null +++ b/test/fixtures/card/goldnesses.yml @@ -0,0 +1,2 @@ +logo: + card: logo diff --git a/test/models/card/golden_test.rb b/test/models/card/golden_test.rb new file mode 100644 index 000000000..b20b16e9f --- /dev/null +++ b/test/models/card/golden_test.rb @@ -0,0 +1,30 @@ +require "test_helper" + +class Card::GoldenTest < ActiveSupport::TestCase + setup do + Current.session = sessions(:david) + end + + test "check whether a card is golden" do + assert cards(:logo).golden? + assert_not cards(:text).golden? + end + + test "promote and demote from golden" do + assert_changes -> { cards(:text).reload.golden? }, to: true do + cards(:text).promote_to_golden + end + + assert_changes -> { cards(:logo).reload.golden? }, to: false do + cards(:logo).demote_from_golden + end + 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) + end +end From 5360b4ccb4f2af29b3fa1110845351b2fa2e0766 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 09:49:34 +0200 Subject: [PATCH 09/16] Add comment --- app/models/card/golden.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index c8553f6be..340997fd7 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -8,6 +8,7 @@ module Card::Golden scope :with_golden_first, -> do left_outer_joins(:goldness).tap do |relation| + # Make sure it can be layered in with other orderings taking precedence. relation.order_values.unshift("card_goldnesses.id IS NULL") end end From 492a42ba92bda931ff71c553e844358ab1e11aaf Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 09:50:47 +0200 Subject: [PATCH 10/16] Not needed anymore --- app/controllers/cards_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index 07bb6e50f..103c05e99 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -39,9 +39,9 @@ class CardsController < ApplicationController @card = @collection.cards.find params[:id] end - def page_and_filter_for(filter, per_page: nil, cards: filter.cards) + def page_and_filter_for(filter, per_page: nil) OpenStruct.new \ - page: GearedPagination::Recordset.new(cards, per_page:).page(1), + page: GearedPagination::Recordset.new(filter.cards, per_page:).page(1), filter: filter end From f4b2bec5ce954dad8eee432fe9eab86c0ca5df17 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 09:54:34 +0200 Subject: [PATCH 11/16] Fix test --- test/models/card/golden_test.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/models/card/golden_test.rb b/test/models/card/golden_test.rb index b20b16e9f..2d26101d3 100644 --- a/test/models/card/golden_test.rb +++ b/test/models/card/golden_test.rb @@ -21,10 +21,7 @@ class Card::GoldenTest < ActiveSupport::TestCase 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) + assert_includes Card.golden, cards(:logo) + assert_not_includes Card.golden, cards(:text) end end From b4297ab852cc51e0567eb8c0adb27f87baa86026 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 09:55:40 +0200 Subject: [PATCH 12/16] Format --- app/models/card.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/card.rb b/app/models/card.rb index fdbf46cb7..8d4411cf4 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -35,7 +35,7 @@ class Card < ApplicationRecord scope :by_engagement_status, ->(status) do case status.to_s when "considering" then considering - when "doing" then doing.with_golden_first + when "doing" then doing.with_golden_first end end From 806609e77b53a1887e450f6a53f3072a0e2603f6 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 10:20:06 +0200 Subject: [PATCH 13/16] Use gild/ungild --- app/controllers/cards/goldenesses_controller.rb | 4 ++-- app/models/card/golden.rb | 4 ++-- test/models/card/golden_test.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/cards/goldenesses_controller.rb b/app/controllers/cards/goldenesses_controller.rb index 974610569..2d1045402 100644 --- a/app/controllers/cards/goldenesses_controller.rb +++ b/app/controllers/cards/goldenesses_controller.rb @@ -2,12 +2,12 @@ class Cards::GoldenessesController < ApplicationController include CardScoped def create - @card.promote_to_golden + @card.gild redirect_to @card end def destroy - @card.demote_from_golden + @card.ungild redirect_to @card end end diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index 340997fd7..92fd3a199 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -18,11 +18,11 @@ module Card::Golden goldness.present? end - def promote_to_golden + def gild create_goldness! unless golden? end - def demote_from_golden + def ungild goldness&.destroy end end diff --git a/test/models/card/golden_test.rb b/test/models/card/golden_test.rb index 2d26101d3..be501c754 100644 --- a/test/models/card/golden_test.rb +++ b/test/models/card/golden_test.rb @@ -12,11 +12,11 @@ class Card::GoldenTest < ActiveSupport::TestCase test "promote and demote from golden" do assert_changes -> { cards(:text).reload.golden? }, to: true do - cards(:text).promote_to_golden + cards(:text).gild end assert_changes -> { cards(:logo).reload.golden? }, to: false do - cards(:logo).demote_from_golden + cards(:logo).ungild end end From eae1669ac30300fbdf7255176fb98e9cf2eeeae1 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 10:20:30 +0200 Subject: [PATCH 14/16] Touch --- app/models/card/goldness.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/card/goldness.rb b/app/models/card/goldness.rb index 5ef88fc0b..fc2697328 100644 --- a/app/models/card/goldness.rb +++ b/app/models/card/goldness.rb @@ -1,3 +1,3 @@ class Card::Goldness < ApplicationRecord - belongs_to :card + belongs_to :card, touch: true end From 4f3f32252871f6fdd3622d1142ce778e853d2915 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 10:22:18 +0200 Subject: [PATCH 15/16] Rename inconsistency: go with goldness --- .../{goldenesses_controller.rb => goldnesses_controller.rb} | 2 +- app/views/cards/_golden_toggle.html.erb | 4 ++-- config/routes.rb | 2 +- ...ses_controller_test.rb => goldnesses_controller_test.rb} | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) rename app/controllers/cards/{goldenesses_controller.rb => goldnesses_controller.rb} (70%) rename test/controllers/cards/{goldenesses_controller_test.rb => goldnesses_controller_test.rb} (76%) diff --git a/app/controllers/cards/goldenesses_controller.rb b/app/controllers/cards/goldnesses_controller.rb similarity index 70% rename from app/controllers/cards/goldenesses_controller.rb rename to app/controllers/cards/goldnesses_controller.rb index 2d1045402..4be611d14 100644 --- a/app/controllers/cards/goldenesses_controller.rb +++ b/app/controllers/cards/goldnesses_controller.rb @@ -1,4 +1,4 @@ -class Cards::GoldenessesController < ApplicationController +class Cards::GoldnessesController < ApplicationController include CardScoped def create diff --git a/app/views/cards/_golden_toggle.html.erb b/app/views/cards/_golden_toggle.html.erb index 3456bea4b..b3525f351 100644 --- a/app/views/cards/_golden_toggle.html.erb +++ b/app/views/cards/_golden_toggle.html.erb @@ -1,10 +1,10 @@ <% if card.golden? %> - <%= button_to card_goldeness_path(card), method: :delete, class: "btn btn--reversed" do %> + <%= button_to card_goldness_path(card), method: :delete, class: "btn btn--reversed" do %> <%= icon_tag "golden-ticket" %> Demote to normal <% end %> <% else %> - <%= button_to card_goldeness_path(card), class: "btn" do %> + <%= button_to card_goldness_path(card), class: "btn" do %> <%= icon_tag "golden-ticket" %> Promote to golden <% end %> diff --git a/config/routes.rb b/config/routes.rb index 25e6a0f62..70de37a31 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,7 +22,7 @@ Rails.application.routes.draw do resource :reading resource :recover resource :watch - resource :goldeness + resource :goldness resources :assignments resources :boosts diff --git a/test/controllers/cards/goldenesses_controller_test.rb b/test/controllers/cards/goldnesses_controller_test.rb similarity index 76% rename from test/controllers/cards/goldenesses_controller_test.rb rename to test/controllers/cards/goldnesses_controller_test.rb index 245ccc180..081a6ec61 100644 --- a/test/controllers/cards/goldenesses_controller_test.rb +++ b/test/controllers/cards/goldnesses_controller_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class Cards::GoldenessesControllerTest < ActionDispatch::IntegrationTest +class Cards::GoldnessesControllerTest < ActionDispatch::IntegrationTest setup do sign_in_as :kevin end @@ -9,7 +9,7 @@ class Cards::GoldenessesControllerTest < ActionDispatch::IntegrationTest card = cards(:text) assert_changes -> { card.reload.golden? }, from: false, to: true do - post card_goldeness_url(card) + post card_goldness_url(card) end assert_redirected_to collection_card_url(card.collection, card) @@ -19,7 +19,7 @@ class Cards::GoldenessesControllerTest < ActionDispatch::IntegrationTest card = cards(:logo) assert_changes -> { card.reload.golden? }, from: true, to: false do - delete card_goldeness_url(card) + delete card_goldness_url(card) end assert_redirected_to collection_card_url(card.collection, card) From 17aa9b97e9496db031e87e2e8563a4b565c2cd4e Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Fri, 11 Apr 2025 10:28:12 +0200 Subject: [PATCH 16/16] Monkey patch a prepend_order method --- app/models/card/golden.rb | 7 +------ lib/rails_ext/prepend_order.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 lib/rails_ext/prepend_order.rb diff --git a/app/models/card/golden.rb b/app/models/card/golden.rb index 92fd3a199..759179415 100644 --- a/app/models/card/golden.rb +++ b/app/models/card/golden.rb @@ -6,12 +6,7 @@ module Card::Golden has_one :goldness, dependent: :destroy, class_name: "Card::Goldness" - scope :with_golden_first, -> do - left_outer_joins(:goldness).tap do |relation| - # Make sure it can be layered in with other orderings taking precedence. - relation.order_values.unshift("card_goldnesses.id IS NULL") - end - end + scope :with_golden_first, -> { left_outer_joins(:goldness).prepend_order("card_goldnesses.id IS NULL") } end def golden? diff --git a/lib/rails_ext/prepend_order.rb b/lib/rails_ext/prepend_order.rb new file mode 100644 index 000000000..b7eb995fa --- /dev/null +++ b/lib/rails_ext/prepend_order.rb @@ -0,0 +1,16 @@ +module ActiveRecordRelationPrependOrder + extend ActiveSupport::Concern + + included do + def prepend_order(*args) + new_orders = args.flatten.map { |arg| arg.is_a?(String) ? arg : arg.to_sql } + + spawn.tap do |relation| + relation.order_values = new_orders + order_values + end + end + end +end + +ActiveRecord::Relation.include(ActiveRecordRelationPrependOrder) +ActiveRecord::AssociationRelation.include(ActiveRecordRelationPrependOrder)