diff --git a/app/controllers/cards/drops_controller.rb b/app/controllers/cards/drops_controller.rb index a404d2d3e..468290fd9 100644 --- a/app/controllers/cards/drops_controller.rb +++ b/app/controllers/cards/drops_controller.rb @@ -1,5 +1,6 @@ class Cards::DropsController < ApplicationController - include Collections::ColumnsScoped + include FilterScoped + before_action :set_card, :set_drop_target def create @@ -34,11 +35,13 @@ class Cards::DropsController < ApplicationController end def render_column_replacement - page_and_filter = page_and_filter_for @filter.with(engagement_status: @drop_target.to_s), per_page: CardsController::PAGE_SIZE + columns = Cards::Columns.new(user_filtering: @user_filtering, page_size: CardsController::PAGE_SIZE) + column = columns.public_send(@drop_target) + render \ turbo_stream: turbo_stream.replace("#{@drop_target.to_s.gsub('_', '-')}-cards", method: :morph, partial: "cards/index/engagement/#{@drop_target}", - locals: { user_filtering: @user_filtering, **page_and_filter.to_h }) + locals: { column: column }) end end diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index 1bdd201c0..aa4aa5263 100644 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -1,7 +1,7 @@ require "ostruct" class CardsController < ApplicationController - include Collections::ColumnsScoped + include CardsHelper, FilterScoped before_action :set_collection, only: %i[ create ] before_action :set_card, only: %i[ show edit update destroy ] @@ -11,13 +11,9 @@ class CardsController < ApplicationController PAGE_SIZE = 25 def index - @considering = page_and_filter_for @filter.with(engagement_status: "considering"), per_page: PAGE_SIZE - @on_deck = page_and_filter_for @filter.with(engagement_status: "on_deck"), per_page: PAGE_SIZE - @doing = page_and_filter_for @filter.with(engagement_status: "doing"), per_page: PAGE_SIZE - @closed = page_and_filter_for_closed_cards + @columns = Cards::Columns.new(user_filtering: @user_filtering, page_size: PAGE_SIZE) - @cache_key = [ @considering, @on_deck, @doing, @closed ].collect { it.page.records }.including([ Workflow.all, @user_filtering ]) - fresh_when etag: @cache_key + fresh_when etag: @columns end def create @@ -26,7 +22,7 @@ class CardsController < ApplicationController end def show - fresh_when @card + fresh_when etag: @card.cache_invalidation_parts.for_perma end def edit diff --git a/app/controllers/concerns/collections/columns_scoped.rb b/app/controllers/concerns/collections/columns_scoped.rb deleted file mode 100644 index a588a15b6..000000000 --- a/app/controllers/concerns/collections/columns_scoped.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Collections::ColumnsScoped - extend ActiveSupport::Concern - - included do - include FilterScoped - end - - def page_and_filter_for(filter, per_page: nil) - cards = block_given? ? yield(filter.cards) : filter.cards - - OpenStruct.new \ - page: GearedPagination::Recordset.new(cards, per_page:).page(1), - filter: filter - end - - def page_and_filter_for_closed_cards - if @filter.indexed_by.stalled? - page_and_filter_for(@filter, per_page: CardsController::PAGE_SIZE) { |cards| cards.recently_closed_first } - else - page_and_filter_for(@filter.with(indexed_by: "closed"), per_page: CardsController::PAGE_SIZE) { |cards| cards.recently_closed_first } - end - end -end diff --git a/app/helpers/cards_helper.rb b/app/helpers/cards_helper.rb index cdf5c5d7b..0fba06f5f 100644 --- a/app/helpers/cards_helper.rb +++ b/app/helpers/cards_helper.rb @@ -65,8 +65,4 @@ module CardsHelper title << "assigned to #{card.assignees.map(&:name).to_sentence}" if card.assignees.any? title.join(" ") end - - def cacheable_preview_parts_for(card, *options) - [ card, card.workflow, card.collection.entropy_configuration, card.collection.publication, *options ] - end end diff --git a/app/models/card.rb b/app/models/card.rb index 00214fa5d..fe41c5d9b 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,5 +1,5 @@ class Card < ApplicationRecord - include Assignable, Attachments, Closeable, Colored, Engageable, Entropic, Eventable, + include Assignable, Attachments, Cacheable, Closeable, Colored, Engageable, Entropic, Eventable, Golden, Mentions, Multistep, Pinnable, Promptable, Readable, Searchable, Staged, Stallable, Statuses, Taggable, Watchable diff --git a/app/models/card/cacheable.rb b/app/models/card/cacheable.rb new file mode 100644 index 000000000..b6c381ceb --- /dev/null +++ b/app/models/card/cacheable.rb @@ -0,0 +1,23 @@ +module Card::Cacheable + extend ActiveSupport::Concern + + def cache_invalidation_parts + @cache_invalidation_parts ||= InvalidationParts.new(self) + end + + class InvalidationParts + attr_reader :card + + def initialize(card) + @card = card + end + + def for_perma(*other) + [ card, Workflow.all, User.all, Tag.all, *other ] + end + + def for_preview(*other) + [ card, card.workflow, Workflow.all, card.collection.entropy_configuration, card.collection.publication, *other ] + end + end +end diff --git a/app/models/card/staged.rb b/app/models/card/staged.rb index fd9b1d09c..4cd497abd 100644 --- a/app/models/card/staged.rb +++ b/app/models/card/staged.rb @@ -7,10 +7,7 @@ module Card::Staged before_create :assign_initial_stage scope :in_stage, ->(stage) { where stage: stage } - end - - def workflow - stage&.workflow + delegate :workflow, to: :collection, allow_nil: true end def staged? diff --git a/app/models/cards/columns.rb b/app/models/cards/columns.rb new file mode 100644 index 000000000..7af28d1b9 --- /dev/null +++ b/app/models/cards/columns.rb @@ -0,0 +1,41 @@ +class Cards::Columns + attr_reader :user_filtering, :page_size + + delegate :filter, to: :user_filtering + + def initialize(user_filtering:, page_size:) + @user_filtering = user_filtering + @page_size = page_size + end + + def considering + @considering ||= build_column(filter.with(engagement_status: "considering")) + end + + def on_deck + @on_deck ||= build_column(filter.with(engagement_status: "on_deck")) + end + + def doing + @doing ||= build_column(filter.with(engagement_status: "doing")) + end + + def closed + @closed ||= if filter.indexed_by.stalled? + build_column(filter) { |cards| cards.recently_closed_first } + else + build_column(filter.with(indexed_by: "closed")) { |cards| cards.recently_closed_first } + end + end + + def cache_key + ActiveSupport::Cache.expand_cache_key([ considering, on_deck, doing, closed, Workflow.all, user_filtering ]) + end + + private + def build_column(filter, &block) + cards = block ? yield(filter.cards) : filter.cards + + Column.new(page: GearedPagination::Recordset.new(cards, per_page: page_size).page(1), user_filtering: user_filtering) + end +end diff --git a/app/models/cards/columns/column.rb b/app/models/cards/columns/column.rb new file mode 100644 index 000000000..ff7d9b461 --- /dev/null +++ b/app/models/cards/columns/column.rb @@ -0,0 +1,18 @@ +class Cards::Columns::Column + attr_reader :page, :user_filtering + + delegate :filter, to: :user_filtering + + def initialize(page:, user_filtering:) + @page = page + @user_filtering = user_filtering + end + + def cards + page.records + end + + def cache_key + ActiveSupport::Cache.expand_cache_key([ cards ]) + end +end diff --git a/app/views/cards/_container.html.erb b/app/views/cards/_container.html.erb index 09eb83d11..f067781b1 100644 --- a/app/views/cards/_container.html.erb +++ b/app/views/cards/_container.html.erb @@ -1,4 +1,4 @@ -<% cache card do %> +<% cache card.cache_invalidation_parts.for_perma do %>
<%= render "cards/container/engagement", card: card %> diff --git a/app/views/cards/columns/_column.html.erb b/app/views/cards/columns/_column.html.erb new file mode 100644 index 000000000..e2da152a4 --- /dev/null +++ b/app/views/cards/columns/_column.html.erb @@ -0,0 +1 @@ +<%= render partial: "cards/display/preview", collection: column.cards, as: :card, locals: { draggable: draggable }, cached: ->(card) { card.cache_invalidation_parts.for_preview } %> \ No newline at end of file diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index 9fda1c484..2f580a519 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -1,43 +1,41 @@ <% draggable = local_assigns.fetch(:draggable, false) && card.published? %> -<% cache cacheable_preview_parts_for(card, draggable) do %> - <%= card_article_tag card, class: "card", draggable: draggable, data: { id: card.id, drag_and_drop_target: "item" } do %> -
-
- <%= render "cards/display/preview/collection", card: card %> - <%= render "cards/display/preview/tags", card: card %> - <%= render "cards/display/preview/steps", card: card %> - <%= icon_tag "attachment", class: "card__attachments-indicator translucent txt-x-small" if card.has_attachments? %> +<%= card_article_tag card, class: "card", draggable: draggable, data: { id: card.id, drag_and_drop_target: "item" } do %> +
+
+ <%= render "cards/display/preview/collection", card: card %> + <%= render "cards/display/preview/tags", card: card %> + <%= render "cards/display/preview/steps", card: card %> + <%= icon_tag "attachment", class: "card__attachments-indicator translucent txt-x-small" if card.has_attachments? %> - <% if card.staged? && card.doing? %> + <% if card.staged? && card.doing? %> <%= card.stage.name %> - <% end %> -
+ <% end %> +
-
-
-

- <%= card.title %> -

-
- - <%= render "cards/display/preview/stages", card: card if card.doing? %> +
+
+

+ <%= card.title %> +

+ + <%= render "cards/display/preview/stages", card: card if card.doing? %>
+
-
- <%= render "cards/display/preview/meta", card: card %> - <%= render "cards/display/common/background", card: card %> -
+
+ <%= render "cards/display/preview/meta", card: card %> + <%= render "cards/display/common/background", card: card %> +
- <%= link_to card_path(card), draggable: false, class: "card__link", title: card_title_tag(card), data: { action: "dialog#close", turbo_frame: "_top" } do %> - <%= card.title %> - <% end %> + <%= link_to card_path(card), draggable: false, class: "card__link", title: card_title_tag(card), data: { action: "dialog#close", turbo_frame: "_top" } do %> + <%= card.title %> + <% end %> - <% if card.entropic? %> - <%= render "cards/display/preview/bubble", card: card %> - <% end %> + <% if card.entropic? %> + <%= render "cards/display/preview/bubble", card: card %> <% end %> <% end %> diff --git a/app/views/cards/display/_public_preview.html.erb b/app/views/cards/display/_public_preview.html.erb index e0f7e945a..95ccc0740 100644 --- a/app/views/cards/display/_public_preview.html.erb +++ b/app/views/cards/display/_public_preview.html.erb @@ -1,4 +1,4 @@ -<% cache cacheable_preview_parts_for(card) do %> +<% cache card.cache_invalidation_parts.for_preview do %> <%= card_article_tag card, class: "card" do %>
diff --git a/app/views/cards/index.html.erb b/app/views/cards/index.html.erb index 680535c0b..91602a3a6 100644 --- a/app/views/cards/index.html.erb +++ b/app/views/cards/index.html.erb @@ -42,5 +42,5 @@ drop->drag-and-drop#drop dragend->drag-and-drop#dragEnd" } do %> - <%= render "cards/index/columns", user_filtering: @user_filtering, on_deck: @on_deck, considering: @considering, doing: @doing, closed: @closed, cache_key: @cache_key %> + <%= render "cards/index/columns", columns: @columns %> <% end %> diff --git a/app/views/cards/index/_columns.html.erb b/app/views/cards/index/_columns.html.erb index 9104145fc..b7b79aa67 100644 --- a/app/views/cards/index/_columns.html.erb +++ b/app/views/cards/index/_columns.html.erb @@ -1,13 +1,13 @@ -<% cache @cache_key do %> +<% cache columns do %> <%= turbo_frame_tag :card_columns do %>
- <% unless user_filtering.only_closed? %> - <%= render "cards/index/engagement/on_deck", user_filtering: user_filtering, **on_deck.to_h %> - <%= render "cards/index/engagement/considering", user_filtering: user_filtering, **considering.to_h %> - <%= render "cards/index/engagement/doing", user_filtering: user_filtering, **doing.to_h %> + <% unless columns.user_filtering.only_closed? %> + <%= render "cards/index/engagement/on_deck", column: columns.on_deck %> + <%= render "cards/index/engagement/considering", column: columns.considering %> + <%= render "cards/index/engagement/doing", column: columns.doing %> <% end %>
- <%= render "cards/index/engagement/closed", user_filtering: user_filtering, **closed.to_h %> + <%= render "cards/index/engagement/closed", column: columns.closed %> <% end %> <% end %> diff --git a/app/views/cards/index/engagement/_closed.html.erb b/app/views/cards/index/engagement/_closed.html.erb index ad323c67b..0285b8a34 100644 --- a/app/views/cards/index/engagement/_closed.html.erb +++ b/app/views/cards/index/engagement/_closed.html.erb @@ -1,15 +1,15 @@

Recently closed

- <% if page.used? %> - <%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %> + <% if column.page.used? %> + <%= render "cards/columns/column", column: column, draggable: false %> - <% unless page.last? %> + <% unless column.page.last? %>
- <%= cards_next_page_link "closed-cards", page: page, filter: filter, fetch_on_visible: true %> + <%= cards_next_page_link "closed-cards", page: column.page, filter: column.filter, fetch_on_visible: true %>
<% end %> <% else %> -

<%= user_filtering.any? ? "No matches" : "Nothing here" %>

+

<%= column.user_filtering.any? ? "No matches" : "Nothing here" %>

<% end %>
diff --git a/app/views/cards/index/engagement/_considering.html.erb b/app/views/cards/index/engagement/_considering.html.erb index 44a80c0e5..0fbee8170 100644 --- a/app/views/cards/index/engagement/_considering.html.erb +++ b/app/views/cards/index/engagement/_considering.html.erb @@ -5,13 +5,13 @@ data-related-element-group-value="card-columns" data-action="mouseover->related-element#highlight mouseout->related-element#unhighlight">
- <%= render "cards/index/add_card_button", user_filtering: user_filtering %> - <% if page.used? %> - <%= render partial: "cards/display/preview", collection: page.records, as: :card, locals: { draggable: true }, cached: true %> + <%= render "cards/index/add_card_button", user_filtering: column.user_filtering %> + <% if column.page.used? %> + <%= render "cards/columns/column", column: column, draggable: true %> - <% unless page.last? %> + <% unless column.page.last? %>
- <%= cards_next_page_link "considering-cards", page: page, filter: filter %> + <%= cards_next_page_link "considering-cards", page: column.page, filter: column.filter %>
<% end %> <% end %> diff --git a/app/views/cards/index/engagement/_doing.html.erb b/app/views/cards/index/engagement/_doing.html.erb index 7d69e9322..36e453d5a 100644 --- a/app/views/cards/index/engagement/_doing.html.erb +++ b/app/views/cards/index/engagement/_doing.html.erb @@ -4,23 +4,23 @@ data-related-element-target="related" data-related-element-group-value="card-columns" data-action="mouseover->related-element#highlight mouseout->related-element#unhighlight"> - <% if workflow = filter.single_workflow %> - <%= render "cards/index/workflow_filter", workflow: workflow, filter: filter %> + <% if workflow = column.filter.single_workflow %> + <%= render "cards/index/workflow_filter", workflow: workflow, filter: column.filter %> <% else %>

Working On

<% end %> - <% if page.used? %> - <%= render partial: "cards/display/preview", collection: page.records, as: :card, locals: { draggable: true }, cached: ->(card) { cacheable_preview_parts_for(card) } %> + <% if column.page.used? %> + <%= render "cards/columns/column", column: column, draggable: true %> - <% unless page.last? %> + <% unless column.page.last? %>
- <%= cards_next_page_link "doing-cards", page: page, filter: filter %> + <%= cards_next_page_link "doing-cards", page: column.page, filter: column.filter %>
<% end %> <% else %> -

<%= user_filtering.any? ? "No matches" : "Nothing here" %>

+

<%= column.user_filtering.any? ? "No matches" : "Nothing here" %>

<% end %>
diff --git a/app/views/cards/index/engagement/_on_deck.html.erb b/app/views/cards/index/engagement/_on_deck.html.erb index c56871f7c..8309554fa 100644 --- a/app/views/cards/index/engagement/_on_deck.html.erb +++ b/app/views/cards/index/engagement/_on_deck.html.erb @@ -6,15 +6,15 @@ data-action="mouseover->related-element#highlight mouseout->related-element#unhighlight">

On Deck

- <% if page.used? %> - <%= render partial: "cards/display/preview", collection: page.records, as: :card, locals: { draggable: true }, cached: true %> + <% if column.page.used? %> + <%= render "cards/columns/column", column: column, draggable: true %> - <% unless page.last? %> + <% unless column.page.last? %>
- <%= cards_next_page_link "on-deck-cards", page: page, filter: filter %> + <%= cards_next_page_link "on-deck-cards", page: column.page, filter: column.filter %>
<% end %> <% else %> -

<%= user_filtering.any? ? "No matches" : "Nothing here" %>

+

<%= column.user_filtering.any? ? "No matches" : "Nothing here" %>

<% end %> diff --git a/app/views/public/collections/show/_doing.html.erb b/app/views/public/collections/show/_doing.html.erb index d072bc614..386ce6104 100644 --- a/app/views/public/collections/show/_doing.html.erb +++ b/app/views/public/collections/show/_doing.html.erb @@ -4,7 +4,7 @@ <% if page.used? %> - <%= render partial: "cards/display/public_preview", collection: page.records, as: :card, cached: ->(card) { cacheable_preview_parts_for(card) } %> + <%= render partial: "cards/display/public_preview", collection: page.records, as: :card, cached: ->(card) { card.cache_invalidation_parts.for_preview } %> <% unless page.last? %>