From 7406a1039f5d4d3ee9ff7ac6fb3ffb7c54f8123f Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 10 Apr 2025 16:48:12 +0200 Subject: [PATCH] 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