Paginate collection cards
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
class Cards::PreviewsController < ApplicationController
|
||||
include FilterScoped
|
||||
before_action :set_filter, only: :index
|
||||
|
||||
def index
|
||||
set_page_and_extract_portion_from @filter.cards, per_page: CardsController::PAGE_SIZE
|
||||
end
|
||||
end
|
||||
@@ -1,17 +1,17 @@
|
||||
require "ostruct"
|
||||
|
||||
class CardsController < ApplicationController
|
||||
include CollectionScoped
|
||||
include CollectionScoped, FilterScoped
|
||||
|
||||
skip_before_action :set_collection, only: :index
|
||||
|
||||
before_action :set_filter, only: :index
|
||||
before_action :set_card, only: %i[ show edit update destroy ]
|
||||
|
||||
RECENTLY_CLOSED_LIMIT = 100
|
||||
PAGE_SIZE = 50
|
||||
|
||||
def index
|
||||
@considering_cards = @filter.cards.considering.load_async
|
||||
@doing_cards = @filter.cards.doing.load_async
|
||||
@closed_cards = @filter.with(indexed_by: "closed").cards.recently_closed_first.limit(RECENTLY_CLOSED_LIMIT).load_async
|
||||
@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
|
||||
@closed = page_and_filter_for @filter.with(indexed_by: "closed"), per_page: PAGE_SIZE
|
||||
end
|
||||
|
||||
def create
|
||||
@@ -35,16 +35,16 @@ class CardsController < ApplicationController
|
||||
end
|
||||
|
||||
private
|
||||
DEFAULT_PARAMS = { indexed_by: "newest" }
|
||||
|
||||
def set_filter
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**DEFAULT_PARAMS).permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
|
||||
def set_card
|
||||
@card = @collection.cards.find params[:id]
|
||||
end
|
||||
|
||||
def page_and_filter_for(filter, per_page: nil)
|
||||
OpenStruct.new \
|
||||
page: GearedPagination::Recordset.new(filter.cards, per_page:).page(1),
|
||||
filter: filter
|
||||
end
|
||||
|
||||
def card_params
|
||||
params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ])
|
||||
end
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
module FilterScoped
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :set_filter, only: :index
|
||||
end
|
||||
|
||||
private
|
||||
DEFAULT_PARAMS = { indexed_by: "newest" }
|
||||
|
||||
def set_filter
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**DEFAULT_PARAMS).permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
end
|
||||
@@ -10,4 +10,20 @@ module CardsHelper
|
||||
|
||||
"--card-rotate: #{value}deg;"
|
||||
end
|
||||
|
||||
def cards_next_page_link(target, page:, filter:, fetch_on_visible: false, data: {}, **options)
|
||||
url = cards_previews_path(target: target, page: page.next_param, **filter.as_params)
|
||||
|
||||
if fetch_on_visible
|
||||
data[:controller] = "#{data[:controller]} fetch-on-visible"
|
||||
data[:fetch_on_visible_url_value] = url
|
||||
end
|
||||
|
||||
link_to "Load more",
|
||||
url,
|
||||
id: "#{target}-load-page-#{page.next_param}",
|
||||
data: { turbo_stream: true, **data },
|
||||
class: "btn txt-small",
|
||||
**options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,6 +29,13 @@ class Card < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
scope :by_engagement_status, ->(status) do
|
||||
case status.to_s
|
||||
when "considering" then considering
|
||||
when "doing" then doing
|
||||
end
|
||||
end
|
||||
|
||||
def cache_key
|
||||
[ super, collection&.name ].compact.join("/")
|
||||
end
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
module Filter::Params
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
PERMITTED_PARAMS = %i[
|
||||
indexed_by assignment_status collection_ids creator_ids
|
||||
assignee_ids stage_ids tag_ids terms
|
||||
].freeze
|
||||
|
||||
def as_params
|
||||
self.class.normalize_params(
|
||||
indexed_by: indexed_by,
|
||||
assignment_status: assignment_status,
|
||||
collection_ids: collections.ids,
|
||||
creator_ids: creators.ids,
|
||||
assignee_ids: assignees.ids,
|
||||
stage_ids: stages.ids,
|
||||
tag_ids: tags.ids,
|
||||
terms: terms
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -20,6 +20,7 @@ class Filter < ApplicationRecord
|
||||
@cards ||= begin
|
||||
result = creator.accessible_cards.indexed_by(indexed_by)
|
||||
result = result.active unless indexed_by.closed?
|
||||
result = result.by_engagement_status(engagement_status) if engagement_status.present?
|
||||
result = result.unassigned if assignment_status.unassigned?
|
||||
result = result.assigned_to(assignees.ids) if assignees.present?
|
||||
result = result.where(creator_id: creators.ids) if creators.present?
|
||||
|
||||
@@ -16,7 +16,7 @@ module Filter::Fields
|
||||
end
|
||||
|
||||
included do
|
||||
store_accessor :fields, :assignment_status, :indexed_by, :terms
|
||||
store_accessor :fields, :assignment_status, :indexed_by, :terms, :engagement_status
|
||||
|
||||
def assignment_status
|
||||
super.to_s.inquiry
|
||||
@@ -26,6 +26,10 @@ module Filter::Fields
|
||||
(super || default_indexed_by).inquiry
|
||||
end
|
||||
|
||||
def engagement_status
|
||||
super&.inquiry
|
||||
end
|
||||
|
||||
def terms
|
||||
Array(super)
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ module Filter::Params
|
||||
PERMITTED_PARAMS = [
|
||||
:assignment_status,
|
||||
:indexed_by,
|
||||
:engagement_status,
|
||||
assignee_ids: [],
|
||||
creator_ids: [],
|
||||
collection_ids: [],
|
||||
@@ -35,6 +36,7 @@ module Filter::Params
|
||||
def as_params
|
||||
{}.tap do |params|
|
||||
params[:indexed_by] = indexed_by
|
||||
params[:engagement_status] = engagement_status
|
||||
params[:assignment_status] = assignment_status
|
||||
params[:terms] = terms
|
||||
params[:tag_ids] = tags.ids
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<% end %>
|
||||
|
||||
<div class="cards--columns">
|
||||
<%= render "cards/index/engagement/considering", cards: @considering_cards %>
|
||||
<%= render "cards/index/engagement/doing", cards: @doing_cards, filter: @filter %>
|
||||
<%= render "cards/index/engagement/considering", **@considering.to_h %>
|
||||
<%= render "cards/index/engagement/doing", **@doing.to_h %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/index/engagement/closed", cards: @closed_cards, filter: @filter %>
|
||||
<%= render "cards/index/engagement/closed", **@closed.to_h %>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
Recently closed
|
||||
</h2>
|
||||
|
||||
<section class="cards--grid">
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/preview", collection: cards, as: :card, cached: true %>
|
||||
<section id="closed-cards" class="cards--grid">
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "closed-cards", page: page, filter: filter, fetch_on_visible: true %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<section class="cards" style="align-items: center; border-inline-end: 1px solid var(--color-subtle);">
|
||||
<section id="considering-cards" class="cards" style="align-items: center; border-inline-end: 1px solid var(--color-subtle);">
|
||||
<h2 class="txt-align-center flex-inline center txt-uppercase txt-medium margin-none-block-start margin-block-end">
|
||||
Considering
|
||||
</h2>
|
||||
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/mini", collection: cards, as: :card, cached: true %>
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/mini", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "considering-cards", page: page, filter: filter %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<section class="cards gap position-relative" style="align-items: center; view-transition-name: cards-container;" data-controller="card-size" data-action="turbo:morph@window->card-size#resize">
|
||||
<section id="doing-cards" class="cards gap position-relative" style="align-items: center; view-transition-name: cards-container;" data-controller="card-size" data-action="turbo:morph@window->card-size#resize">
|
||||
<% if workflow = filter.single_workflow %>
|
||||
<%= render "cards/index/workflow_filter", workflow: workflow, filter: filter %>
|
||||
<% else %>
|
||||
@@ -7,8 +7,12 @@
|
||||
</h2>
|
||||
<% end %>
|
||||
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/preview", collection: cards, as: :card, cached: true %>
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "doing-cards", page: page, filter: filter %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<%= turbo_stream.remove "#{params[:target]}-load-page-#{@page.number}" %>
|
||||
|
||||
<%= turbo_stream.append params[:target] do %>
|
||||
<%= render partial: @filter.engagement_status&.considering? ? "cards/display/mini" : "cards/display/preview",
|
||||
collection: @page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless @page.last? %>
|
||||
<%= cards_next_page_link params[:target], page: @page, filter: @filter, fetch_on_visible: @filter.indexed_by.closed? %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -8,6 +8,10 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
namespace :cards do
|
||||
resources :previews
|
||||
end
|
||||
|
||||
resources :cards do
|
||||
scope module: :cards do
|
||||
resource :engagement
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
require_relative "../../config/environment"
|
||||
|
||||
CARDS_COUNT = 200
|
||||
|
||||
ApplicationRecord.current_tenant = "development-tenant"
|
||||
account = Account.first
|
||||
user = account.users.first
|
||||
Current.session = user.sessions.last
|
||||
collection = account.collections.first
|
||||
|
||||
# Doing
|
||||
|
||||
CARDS_COUNT.times do |index|
|
||||
card = collection.cards.create!(title: "Doing card #{index}", creator: user, status: :published)
|
||||
card.engage
|
||||
end
|
||||
|
||||
# Considering
|
||||
|
||||
CARDS_COUNT.times do |index|
|
||||
card = collection.cards.create!(title: "Considering card #{index}", creator: user, status: :published)
|
||||
card.reconsider
|
||||
end
|
||||
|
||||
# Completed
|
||||
|
||||
CARDS_COUNT.times do |index|
|
||||
card = collection.cards.create!(title: "Popped card #{index}", creator: user, status: :published)
|
||||
card.close
|
||||
end
|
||||
@@ -5,7 +5,7 @@ require "active_support/core_ext/string" # for camelize
|
||||
|
||||
RENAME_RULES = {
|
||||
"bubble" => "card",
|
||||
"popped" => "closed",
|
||||
"closed" => "closed",
|
||||
"poppable" => "closeable",
|
||||
"pop" => "closure",
|
||||
"bucket" => "collection"
|
||||
|
||||
@@ -9,7 +9,7 @@ EXCLUDED_DIRS = [ "db", ".git", "script/renaming" ].freeze
|
||||
RENAMES = {
|
||||
"bubble" => "card",
|
||||
"poppable" => "closeable",
|
||||
"popped" => "closed",
|
||||
"closed" => "closed",
|
||||
"pop" => "closure",
|
||||
"bucket" => "collection"
|
||||
}.freeze
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
require "test_helper"
|
||||
|
||||
class Cards::PreviewsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "index" do
|
||||
get cards_previews_url(format: :turbo_stream)
|
||||
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user