Filter activity by bucket

This commit is contained in:
Jason Zimdars
2025-02-19 18:05:12 -06:00
parent 1fde270b18
commit 8cde1883a6
10 changed files with 124 additions and 2 deletions
+13
View File
@@ -25,6 +25,19 @@
}
}
.events__popup {
.panel:is(&) {
max-block-size: calc(100dvh - (2 * var(--block-space-double)));
max-inline-size: calc(100dvw - (2 * var(--block-space-double)));
}
#header:has(&) {
max-inline-size: 100%;
position: relative;
z-index: 5;
}
}
.event {
--column-gap: 0.7ch;
--panel-border-radius: 0.5em;
@@ -0,0 +1,24 @@
module BucketFilterable
extend ActiveSupport::Concern
included do
before_action :set_bucket_filter
end
private
def set_bucket_filter
params[:bucket_ids] ||= cookies[:bucket_filter]&.split(",") unless params[:clear_filter]
end
def bucket_filter
params[:bucket_ids].presence || Current.user.bucket_ids
end
def update_bucket_filter
if params[:clear_filter]
cookies.delete(:bucket_filter)
elsif params[:bucket_ids].present?
cookies[:bucket_filter] = params[:bucket_ids].join(",")
end
end
end
+6 -1
View File
@@ -1,7 +1,10 @@
class EventsController < ApplicationController
include BucketFilterable
before_action :set_activity_day
def index
update_bucket_filter
@buckets = Current.user.buckets.alphabetically
@events = unique_events_by_hour_and_column
@next_day = latest_event_before_today&.created_at
end
@@ -22,7 +25,9 @@ class EventsController < ApplicationController
end
def user_bubbles
Current.user.accessible_bubbles.published_or_drafted_by(Current.user)
Current.user.accessible_bubbles
.published_or_drafted_by(Current.user)
.where(bucket_id: bucket_filter)
end
def set_activity_day
+1
View File
@@ -50,6 +50,7 @@ module EventsHelper
accessible_events = Event.joins(bubble: :bucket)
.merge(Current.user.buckets)
.where(created_at: start_time..end_time)
.where(bubbles: { bucket_id: params[:bucket_ids].presence || Current.user.bucket_ids })
headers = {
"Touched" => nil,
+2
View File
@@ -8,4 +8,6 @@ class Bucket < ApplicationRecord
has_many :tags, -> { distinct }, through: :bubbles
validates_presence_of :name
scope :alphabetically, -> { order(name: :asc) }
end
+29
View File
@@ -0,0 +1,29 @@
class BucketFilterPresenter
def initialize(buckets, params, cookies)
@buckets = buckets
@params = params
@cookies = cookies
end
def filter_text
if selected_bucket_ids.present?
"Showing activity for #{selected_bucket_names_bold}".html_safe
else
"Showing everything"
end
end
private
def selected_bucket_ids
@params[:bucket_ids].presence || @cookies[:bucket_filter]&.split(",")
end
def selected_bucket_names
@buckets.where(id: selected_bucket_ids).pluck(:name).to_sentence
end
def selected_bucket_names_bold
names = @buckets.where(id: selected_bucket_ids).pluck(:name)
names.map { |name| "<strong>#{name}</strong>" }.to_sentence
end
end
+29
View File
@@ -0,0 +1,29 @@
<% presenter = BucketFilterPresenter.new(@buckets, params, cookies) %>
<div class="position-relative margin-block-start-half margin-block-end center max-width"
data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="input input--select flex-inline min-width max-width" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<%= presenter.filter_text %>
</span>
</button>
<dialog class="events__popup popup panel flex-column full-width align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Filter by projects…</strong>
<%= form_with url: events_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<%= link_to "Show everything", events_path(clear_filter: true), class: "btn popup__item" %>
<% @buckets.each do |bucket| %>
<div class="btn popup__item">
<%= form.check_box "bucket_ids[]", {
checked: (params[:bucket_ids] || cookies[:bucket_filter]&.split(","))&.include?(bucket.id.to_s),
data: { action: "change->form#submit" },
include_hidden: false,
}, bucket.id %>
<%= form.label "bucket_ids[]", bucket.name, for: dom_id(bucket, :filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>
+2 -1
View File
@@ -2,12 +2,13 @@
<% content_for :header do %>
<nav class="align-start">
<header class="flex flex-column center">
<header class="flex-inline flex-column center max-width">
<div class="flex align-center gap-half justify-center">
<%= link_to "Collections", root_path %>
<%= link_to "Activity", events_path %>
</div>
<h1 class="txt-x-large"><%= @page_title %></h1>
<%= render "events/filter" %>
</header>
</nav>
<% end %>
@@ -25,4 +25,16 @@ class EventsControllerTest < ActionDispatch::IntegrationTest
assert_select "strong", text: "David assigned JZ to Layout is broken"
end
end
test "only displays events from filtered buckets" do
get events_path(bucket_ids: [ buckets(:writebook).id ])
assert_response :success
events_shown = css_select(".event").count
assert events_shown > 0, "Should show some events"
css_select(".event").each do |event|
assert_includes event.text, buckets(:writebook).name
end
end
end
+6
View File
@@ -3,3 +3,9 @@ writebook:
account: 37s
creator: david
all_access: true
fizzy:
name: Fizzy
account: 37s
creator: david
all_access: true