From 8c29a59ac25cdd388cb1efdb4b8ad1e7e8eec9c6 Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Wed, 6 Nov 2024 14:23:48 -0600 Subject: [PATCH 01/29] Stub design for new filtering UI --- app/assets/images/close.svg | 1 + app/assets/images/filter.svg | 1 + app/assets/stylesheets/buttons.css | 4 + app/assets/stylesheets/filters.css | 23 +--- app/helpers/filters_helper.rb | 2 +- app/models/bucket/view/order_by.rb | 5 +- app/views/bubbles/_filters.html.erb | 205 ++++++++++++++++++++++++---- 7 files changed, 193 insertions(+), 48 deletions(-) create mode 100644 app/assets/images/close.svg create mode 100644 app/assets/images/filter.svg diff --git a/app/assets/images/close.svg b/app/assets/images/close.svg new file mode 100644 index 000000000..878343d21 --- /dev/null +++ b/app/assets/images/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/filter.svg b/app/assets/images/filter.svg new file mode 100644 index 000000000..b8865e243 --- /dev/null +++ b/app/assets/images/filter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/stylesheets/buttons.css b/app/assets/stylesheets/buttons.css index ecba266af..df48c288b 100644 --- a/app/assets/stylesheets/buttons.css +++ b/app/assets/stylesheets/buttons.css @@ -211,6 +211,10 @@ --outline-color: var(--color-positive); } +.btn--remove { + --btn-icon-size: 0.7em; +} + .btn--reversed { --btn-background: var(--color-ink); --btn-color: var(--color-bg); diff --git a/app/assets/stylesheets/filters.css b/app/assets/stylesheets/filters.css index df9ea05cd..0484df105 100644 --- a/app/assets/stylesheets/filters.css +++ b/app/assets/stylesheets/filters.css @@ -1,29 +1,12 @@ -.filter { - display: inline-flex; - position: relative; - +.filters { #header:has(&) { position: relative; z-index: 1; } } -.filter--active { - li { - display: none; - - &.selected { - display: flex; - } - } -} - -.filter__button { - --hover-size: 0; - - color: var(--color-link); - text-decoration: underline; - text-decoration-skip-ink: auto; +.filter__label { + padding: 0.3em 0.7em; } .filter__menu { diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 15919f416..e9ab4afb7 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -38,7 +38,7 @@ module FiltersHelper end def bubble_filter_form_tag(path, method:, id: nil) - form_tag path, method: method, id: id do + form_tag path, method: method, id: id, class: "full-width" do yield if block_given? if params[:order_by].present? diff --git a/app/models/bucket/view/order_by.rb b/app/models/bucket/view/order_by.rb index 49d87a29e..f32ed51a1 100644 --- a/app/models/bucket/view/order_by.rb +++ b/app/models/bucket/view/order_by.rb @@ -7,9 +7,8 @@ module Bucket::View::OrderBy private ORDERS = { - "most_active" => "most active", - "most_discussed" => "most discussed", - "most_boosted" => "most boosted", + "most_discussed" => "most comments", + "most_boosted" => "most boosts", "newest" => "newest", "oldest" => "oldest" } end diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index ce16c39b9..e2c87effe 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -1,28 +1,185 @@ -
-

- <%= render "bubbles/filters/main", bucket: bucket %> - in - <%= render "bubbles/filters/bucket", bucket: bucket %> - - <% if false %> - <%= button_tag type: :submit, class: "btn txt-small borderless" do %> - <%= image_tag "bookmark.svg", aria: { hidden: true }, size: 24 %> - Save this filter - <% end %> - <% else %> - <%= button_tag type: :submit, class: "btn txt-small borderless" do %> - <%= image_tag "bookmark-outline.svg", aria: { hidden: true }, size: 24 %> - Save this filter - <% end %> - <% end %> +
+

+ Writebook

-

- <%= filter.tags ? "Tagged" : "with" %> - <%= render "bubbles/filters/tags", bucket: bucket, filter: filter %> +
+ - <% unless unassigned_filter_activated? %> - and <%= render "bubbles/filters/assignees", bucket: bucket, filter: filter %> - <% end %> -

+ + + + + + + + + + + +
+ + +
+
+ + +

+ Writebook +

+ +
+ +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
  • Sort by
  • + <% Bucket::View::ORDERS.each do |key, value| %> +
  • <%= link_to value.humanize, bucket_bubbles_path(bucket, view_filter_params.merge(order_by: key, status: nil)), class: "filter__button" %>
  • + <% end %> +
    +
    + +
    +
    + +
  • In Project
  • +
  • All projects
  • + <% Current.user.buckets.order(:name).each do |bucket| %> +
  • <%= link_to bucket.name, bucket_bubbles_path(bucket, view_filter_params), class: "filter__button" %>
  • + <% end %> +
    +
    + +
    +
    + +
  • Tagged
  • + <% bucket.tags.order(:title).each do |tag| %> +
  • <%= link_to tag.title, bucket_bubbles_path(bucket, view_filter_params.merge(tag_ids: [ tag.id ])) %>
  • + <% end %> +
    +
    + +
    +
    + +
  • Assigned to…
  • +
  • No one
  • + <% bucket.users.active.order(:name).each do |user| %> +
  • <%= link_to user.name, bucket_bubbles_path(bucket, view_filter_params.merge(assignee_ids: [ user.id ])) %>
  • + <% end %> +
    +
    + +
    +
    + +
  • Assigned by…
  • +
  • Me
  • + <% bucket.users.active.order(:name).each do |user| %> +
  • <%= link_to user.name, bucket_bubbles_path(bucket, view_filter_params.merge(assignee_ids: [ user.id ])) %>
  • + <% end %> +
    +
    + +
    +
    + +
  • Status
  • + <% Bucket::View::STATUSES.each do |key, value| %> +
  • <%= link_to value.humanize, bucket_bubbles_path(bucket, view_filter_params.merge(order_by: nil, status: key)), class: "filter__button" %>
  • + <% end %> +
    +
    +
    +
    + +
    + + + +
    +
    +

    From 3db6e230c9e1f69c31ed38f64f05767f4a26dc9e Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 7 Nov 2024 17:03:52 -0600 Subject: [PATCH 02/29] Update links to use new system --- app/views/bubbles/_filters.html.erb | 32 ++++++++++------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index e2c87effe..c8a511ac5 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -108,8 +108,8 @@
  • Sort by
  • - <% Bucket::View::ORDERS.each do |key, value| %> -
  • <%= link_to value.humanize, bucket_bubbles_path(bucket, view_filter_params.merge(order_by: key, status: nil)), class: "filter__button" %>
  • + <% Filter::INDEXES.each do |index| %> +
  • <%= link_to index.humanize, bubbles_path(filter.to_params.merge(indexed_by: index)), class: "filter__button" %>
  • <% end %>
    @@ -118,9 +118,9 @@
  • In Project
  • -
  • All projects
  • +
  • <%= link_to "All projects", bubbles_path(filter.to_params.merge(bucket_ids: nil)), class: "filter__button" %>
  • <% Current.user.buckets.order(:name).each do |bucket| %> -
  • <%= link_to bucket.name, bucket_bubbles_path(bucket, view_filter_params), class: "filter__button" %>
  • +
  • <%= link_to bucket.name, bubbles_path(filter.to_params.merge(bucket_ids: [ bucket.id ])), class: "filter__button" %>
  • <% end %>
    @@ -129,8 +129,8 @@
  • Tagged
  • - <% bucket.tags.order(:title).each do |tag| %> -
  • <%= link_to tag.title, bucket_bubbles_path(bucket, view_filter_params.merge(tag_ids: [ tag.id ])) %>
  • + <% Current.account.tags.order(:title).each do |tag| %> +
  • <%= link_to tag.title, bubbles_path(filter.to_params.merge(tag_ids: [ tag.id ])) %>
  • <% end %>
    @@ -139,9 +139,9 @@
  • Assigned to…
  • -
  • No one
  • - <% bucket.users.active.order(:name).each do |user| %> -
  • <%= link_to user.name, bucket_bubbles_path(bucket, view_filter_params.merge(assignee_ids: [ user.id ])) %>
  • +
  • <%= link_to "No one", bubbles_path(filter.to_params.merge(assignments: :unassigned, assignee_ids: [])), class: "filter__button" %>
  • + <% Current.account.users.active.order(:name).each do |user| %> +
  • <%= link_to user.name, bubbles_path(filter.to_params.merge(assignments: nil, assignee_ids: [ user.id ])) %>
  • <% end %>
    @@ -151,18 +151,8 @@
  • Assigned by…
  • Me
  • - <% bucket.users.active.order(:name).each do |user| %> -
  • <%= link_to user.name, bucket_bubbles_path(bucket, view_filter_params.merge(assignee_ids: [ user.id ])) %>
  • - <% end %> -
    - - -
    -
    - -
  • Status
  • - <% Bucket::View::STATUSES.each do |key, value| %> -
  • <%= link_to value.humanize, bucket_bubbles_path(bucket, view_filter_params.merge(order_by: nil, status: key)), class: "filter__button" %>
  • + <% Current.account.users.active.order(:name).each do |user| %> +
  • <%= link_to user.name, bubbles_path(filter.to_params.merge(assignments: nil, assignee_ids: [ user.id ])) %>
  • <% end %>
    From b1570e34ed6ed58fb6f094bb8ab6baf1c921f216 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Thu, 7 Nov 2024 17:05:19 -0600 Subject: [PATCH 03/29] Remove unused files --- .../bubbles/filters/_assignments.html.erb | 22 ------------ app/views/bubbles/filters/_bookmark.html.erb | 34 ------------------- app/views/bubbles/filters/_buckets.html.erb | 15 -------- app/views/bubbles/filters/_index.html.erb | 13 ------- app/views/bubbles/filters/_tags.html.erb | 20 ----------- 5 files changed, 104 deletions(-) delete mode 100644 app/views/bubbles/filters/_assignments.html.erb delete mode 100644 app/views/bubbles/filters/_bookmark.html.erb delete mode 100644 app/views/bubbles/filters/_buckets.html.erb delete mode 100644 app/views/bubbles/filters/_index.html.erb delete mode 100644 app/views/bubbles/filters/_tags.html.erb diff --git a/app/views/bubbles/filters/_assignments.html.erb b/app/views/bubbles/filters/_assignments.html.erb deleted file mode 100644 index fb893ebb4..000000000 --- a/app/views/bubbles/filters/_assignments.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -
    - - - - -
  • <%= link_to "No one", bubbles_path(filter.to_params.merge(assignments: :unassigned, assignee_ids: [])), class: "filter__button" %>
  • - - <% Current.account.users.active.order(:name).each do |user| %> -
  • <%= link_to user.name, bubbles_path(filter.to_params.merge(assignments: nil, assignee_ids: [ user.id ])) %>
  • - <% end %> -
    -
    - - <% if [ filter.assignees, filter.assignments ].any?(&:present?) %> - <%= link_to bubbles_path(filter.to_params.without(:assignments, :assignee_ids)), class: "btn", style: "font-size: 0.4em;" do %> - <%= image_tag "remove.svg", aria: { hidden: true }, size: 24 %> - Clear - <% end %> - <% end %> -
    diff --git a/app/views/bubbles/filters/_bookmark.html.erb b/app/views/bubbles/filters/_bookmark.html.erb deleted file mode 100644 index 5b7b962dc..000000000 --- a/app/views/bubbles/filters/_bookmark.html.erb +++ /dev/null @@ -1,34 +0,0 @@ -<% if params[:filter_id] %> - <%= button_to filter_path(params[:filter_id]), method: :delete, class: "btn txt-small borderless" do %> - <%= image_tag "bookmark.svg", aria: { hidden: true }, size: 24 %> - Delete this filter - <% end %> -<% else %> - <%= form_with url: filters_path, method: :post do %> - <%= hidden_field_tag :indexed_by, params[:indexed_by] if params[:indexed_by].present? %> - <%= hidden_field_tag :assignments, params[:assignments] if params[:assignments].present? %> - - <% if values = params[:bucket_ids].presence %> - <% values.each do |value| %> - <%= hidden_field_tag "bucket_ids[]", value, id: nil %> - <% end %> - <% end %> - - <% if values = params[:tag_ids].presence %> - <% values.each do |value| %> - <%= hidden_field_tag "tag_ids[]", value, id: nil %> - <% end %> - <% end %> - - <% if values = params[:assignee_ids].presence %> - <% values.each do |value| %> - <%= hidden_field_tag "assignee_ids[]", value, id: nil %> - <% end %> - <% end %> - - <%= button_tag type: :submit, class: "btn txt-small borderless" do %> - <%= image_tag "bookmark-outline.svg", aria: { hidden: true }, size: 24 %> - Save this filter - <% end %> - <% end %> -<% end %> diff --git a/app/views/bubbles/filters/_buckets.html.erb b/app/views/bubbles/filters/_buckets.html.erb deleted file mode 100644 index d5537aa07..000000000 --- a/app/views/bubbles/filters/_buckets.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -
    - - - - -
  • <%= link_to "all projects", bubbles_path(filter.to_params.merge(bucket_ids: nil)), class: "filter__button" %>
  • - - <% Current.user.buckets.each do |bucket| %> -
  • <%= link_to bucket.name, bubbles_path(filter.to_params.merge(bucket_ids: [ bucket.id ])), class: "filter__button" %>
  • - <% end %> -
    -
    -
    diff --git a/app/views/bubbles/filters/_index.html.erb b/app/views/bubbles/filters/_index.html.erb deleted file mode 100644 index ff83a8640..000000000 --- a/app/views/bubbles/filters/_index.html.erb +++ /dev/null @@ -1,13 +0,0 @@ -
    - - - - - <% Filter::INDEXES.each do |index| %> -
  • <%= link_to index.humanize, bubbles_path(filter.to_params.merge(indexed_by: index)), class: "filter__button" %>
  • - <% end %> -
    -
    -
    diff --git a/app/views/bubbles/filters/_tags.html.erb b/app/views/bubbles/filters/_tags.html.erb deleted file mode 100644 index 7972e7e2f..000000000 --- a/app/views/bubbles/filters/_tags.html.erb +++ /dev/null @@ -1,20 +0,0 @@ -
    - - - - - <% Current.account.tags.order(:title).each do |tag| %> -
  • <%= link_to tag.title, bubbles_path(filter.to_params.merge(tag_ids: [ tag.id ])) %>
  • - <% end %> -
    -
    - - <% if filter.tags.present? %> - <%= link_to bubbles_path(filter.to_params.without(:tag_ids)), class: "btn", style: "font-size: 0.4em;" do %> - <%= image_tag "remove.svg", aria: { hidden: true }, size: 24 %> - Clear - <% end %> - <% end %> -
    From d455b72906ba7ae0446499f82d290de1c23450f3 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Fri, 8 Nov 2024 15:17:55 -0600 Subject: [PATCH 04/29] Hash filter params --- app/models/filter.rb | 2 +- app/models/filter/params.rb | 40 ++++++++----------- app/models/filter/resources.rb | 2 +- .../20241108205445_hash_filter_params.rb | 7 ++++ db/schema.rb | 6 +-- test/controllers/filters_controller_test.rb | 2 +- test/fixtures/filters.yml | 2 +- test/models/filter_test.rb | 8 ++-- 8 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 db/migrate/20241108205445_hash_filter_params.rb diff --git a/app/models/filter.rb b/app/models/filter.rb index 58edae90f..c3d163c97 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -10,7 +10,7 @@ class Filter < ApplicationRecord filter.save! filter rescue ActiveRecord::RecordNotUnique - find_by!(params: filter.params).tap(&:touch) + find_by!(params_digest: filter.hashed_params).tap(&:touch) end end diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index 2726e153a..1077203ab 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -4,34 +4,28 @@ module Filter::Params KNOWN_PARAMS = [ :indexed_by, :assignments, bucket_ids: [], assignee_ids: [], tag_ids: [] ] included do - after_initialize :derive_params + before_save { self.params_digest = hashed_params } + end + + def as_params + params = {}.tap do |h| + h["tag_ids"] = tags.ids + h["bucket_ids"] = buckets.ids + h["assignee_ids"] = assignees.ids + h["indexed_by"] = indexed_by + h["assignments"] = assignments + end + + params.compact_blank.reject { |k, v| default_fields[k] == v } end def to_params - ActionController::Parameters.new(params).permit(*KNOWN_PARAMS).tap do |params| + ActionController::Parameters.new(as_params).permit(*KNOWN_PARAMS).tap do |params| params[:filter_id] = id if persisted? end end - private - # `derive_params` stores a denormalized version of the filter in `params` to - # 1) Enforce uniqueness via db constraints - # 2) Look up identical filters by a single column - # 3) Easily turn all filter params into a query string - def derive_params - derive_params_from_resource_ids - derive_params_from_fields - params.compact_blank! - end - alias_method :derived_params, :derive_params - - def derive_params_from_resource_ids - params["tag_ids"] = tags.ids - params["bucket_ids"] = buckets.ids - params["assignee_ids"] = assignees.ids - end - - def derive_params_from_fields - self.params.merge! fields.reject { |k, v| default_fields[k] == v } - end + def hashed_params + Digest::MD5.hexdigest as_params.to_json + end end diff --git a/app/models/filter/resources.rb b/app/models/filter/resources.rb index 5215087f6..e44fd91f8 100644 --- a/app/models/filter/resources.rb +++ b/app/models/filter/resources.rb @@ -10,6 +10,6 @@ module Filter::Resources def resource_removed(resource) kind = resource.class.model_name.plural send "#{kind}=", send(kind).without(resource) - derived_params.blank? ? destroy! : save! + as_params.blank? ? destroy! : save! end end diff --git a/db/migrate/20241108205445_hash_filter_params.rb b/db/migrate/20241108205445_hash_filter_params.rb new file mode 100644 index 000000000..e403598d0 --- /dev/null +++ b/db/migrate/20241108205445_hash_filter_params.rb @@ -0,0 +1,7 @@ +class HashFilterParams < ActiveRecord::Migration[8.0] + def change + change_column :filters, :params, :string, null: false + change_column_default :filters, :params, from: {}, to: nil + rename_column :filters, :params, :params_digest + end +end diff --git a/db/schema.rb b/db/schema.rb index bbb0daf2c..41085fa06 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.0].define(version: 2024_11_05_224305) do +ActiveRecord::Schema[8.0].define(version: 2024_11_08_205445) do create_table "accesses", force: :cascade do |t| t.integer "bucket_id", null: false t.integer "user_id", null: false @@ -131,11 +131,11 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_05_224305) do create_table "filters", force: :cascade do |t| t.integer "creator_id", null: false - t.json "params", default: {}, null: false + t.string "params_digest", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.json "fields", default: {}, null: false - t.index ["creator_id", "params"], name: "index_filters_on_creator_id_and_params", unique: true + t.index ["creator_id", "params_digest"], name: "index_filters_on_creator_id_and_params_digest", unique: true end create_table "filters_tags", id: false, force: :cascade do |t| diff --git a/test/controllers/filters_controller_test.rb b/test/controllers/filters_controller_test.rb index 2522fde07..8e422fae2 100644 --- a/test/controllers/filters_controller_test.rb +++ b/test/controllers/filters_controller_test.rb @@ -28,6 +28,6 @@ class FiltersControllerTest < ActionDispatch::IntegrationTest assert_difference "users(:david).filters.count", -1 do delete filter_url(filters(:jz_assignments)) end - assert_redirected_to bubbles_path(filters(:jz_assignments).params) + assert_redirected_to bubbles_path(filters(:jz_assignments).as_params) end end diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml index b80de3a69..ff1f46bfa 100644 --- a/test/fixtures/filters.yml +++ b/test/fixtures/filters.yml @@ -3,4 +3,4 @@ jz_assignments: tags: mobile assignees: jz fields: <%= { indexed_by: :most_discussed }.to_json %> - params: <%= { indexed_by: :most_discussed, tag_ids: [ ActiveRecord::FixtureSet.identify(:mobile) ], assignee_ids: [ ActiveRecord::FixtureSet.identify(:jz) ] }.to_json %> + params_digest: <%= Digest::MD5.hexdigest({ indexed_by: :most_discussed, tag_ids: [ ActiveRecord::FixtureSet.identify(:mobile) ], assignee_ids: [ ActiveRecord::FixtureSet.identify(:jz) ] }.to_json) %> diff --git a/test/models/filter_test.rb b/test/models/filter_test.rb index 49c88942d..cffe18792 100644 --- a/test/models/filter_test.rb +++ b/test/models/filter_test.rb @@ -37,7 +37,7 @@ class FilterTest < ActiveSupport::TestCase test "param sanitization" do filter = users(:david).filters.new indexed_by: "most_active", tag_ids: "", assignee_ids: [ users(:jz).id ], bucket_ids: [ buckets(:writebook).id ] expected = { assignee_ids: [ users(:jz).id ], bucket_ids: [ buckets(:writebook).id ] } - assert_equal expected.stringify_keys, filter.params + assert_equal expected.stringify_keys, filter.as_params end test "cacheable" do @@ -48,15 +48,15 @@ class FilterTest < ActiveSupport::TestCase test "resource removal" do filter = users(:david).filters.create! tag_ids: [ tags(:mobile).id ], bucket_ids: [ buckets(:writebook).id ] - assert_includes filter.params["tag_ids"], tags(:mobile).id + assert_includes filter.as_params["tag_ids"], tags(:mobile).id assert_includes filter.tags, tags(:mobile) - assert_includes filter.params["bucket_ids"], buckets(:writebook).id + assert_includes filter.as_params["bucket_ids"], buckets(:writebook).id assert_includes filter.buckets, buckets(:writebook) assert_changes "filter.reload.updated_at" do tags(:mobile).destroy! end - assert_nil filter.reload.params["tag_ids"] + assert_nil filter.reload.as_params["tag_ids"] assert_changes "Filter.exists?(filter.id)" do buckets(:writebook).destroy! From 0baaf5d87f0cce1d3afbb6e8688a68c00a6d1645 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Mon, 11 Nov 2024 13:46:15 -0600 Subject: [PATCH 05/29] Wire up filter form sans search --- app/controllers/filter_buttons_controller.rb | 4 + app/helpers/filters_helper.rb | 62 ++++++++--- .../controllers/filter_form_controller.js | 17 +++ app/models/filter/params.rb | 24 +++-- app/views/bubbles/_filters.html.erb | 101 +++++------------- .../filter_buttons/create.turbo_stream.erb | 4 + config/routes.rb | 1 + 7 files changed, 112 insertions(+), 101 deletions(-) create mode 100644 app/controllers/filter_buttons_controller.rb create mode 100644 app/javascript/controllers/filter_form_controller.js create mode 100644 app/views/filter_buttons/create.turbo_stream.erb diff --git a/app/controllers/filter_buttons_controller.rb b/app/controllers/filter_buttons_controller.rb new file mode 100644 index 000000000..20d316679 --- /dev/null +++ b/app/controllers/filter_buttons_controller.rb @@ -0,0 +1,4 @@ +class FilterButtonsController < ApplicationController + def create + end +end diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 05caac3d0..80621407e 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -1,27 +1,55 @@ module FiltersHelper - def buckets_filter_text(filter) - if filter.buckets.present? - filter.buckets.map(&:name).to_choice_sentence - else - "all projects" + def filter_button_id(value, name) + "#{name}_filter--#{value}" + end + + def filter_buttons(filter, **) + filter.to_h.map do |kind, object| + filter_button_from kind, object, ** + end.join.html_safe + end + + def filter_button_tag(display:, value:, name:, **options) + tag.button id: filter_button_id(value, name), class: [ "btn txt-small btn--remove", options.delete(:class) ], data: { action: "filter-form#removeFilter form#submit" } do + concat hidden_field_tag(name, value, id: nil) + concat tag.span(display) + concat image_tag("close.svg", aria: { hidden: true }, size: 24) end end - def assignments_filter_text(filter) - if filter.assignees.present? - "assigned to #{filter.assignees.map(&:name).to_choice_sentence}" - elsif filter.assignments.unassigned? - "assigned to no one" + def button_to_filter(text, kind:, object:, data: {}) + if object + button_to text, filter_buttons_path, method: :post, class: "btn btn--plain", params: filter_attrs(kind, object), data: data else - "assigned to anyone" + button_tag text, type: :button, class: "btn btn--plain", data: data end end - def tags_filter_text(filter) - if filter.tags.present? - filter.tags.map(&:hashtag).to_choice_sentence - else - "any tag" + private + def filter_button_from(kind, object, **) + if object.respond_to? :map + safe_join object.map { |o| filter_button_tag(**filter_attrs(kind, o), **) } + else + filter_button_tag(**filter_attrs(kind, object), **) + end + end + + def filter_attrs(kind, object) + case kind&.to_sym + when :tags + [ object.hashtag, object.id, "tag_ids[]" ] + when :buckets + [ "in #{object.name}", object.id, "bucket_ids[]" ] + when :assignees + [ "for #{object.name}", object.id, "assignee_ids[]" ] + when :assigners + [ "by #{object.name}", object.id, "assigner_ids[]" ] + when :indexed_by + [ object.humanize, object, "indexed_by" ] + when :assignments + [ object.humanize, object, "assignments" ] + end.then do |display, value, name| + { display: display, value: value, name: name } + end end - end end diff --git a/app/javascript/controllers/filter_form_controller.js b/app/javascript/controllers/filter_form_controller.js new file mode 100644 index 000000000..b55cc6069 --- /dev/null +++ b/app/javascript/controllers/filter_form_controller.js @@ -0,0 +1,17 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + removeFilter(event) { + event.preventDefault() + this.#removeButton(event.target.closest("button")) + } + + clearCategory({ params: { name } }) { + this.element.querySelectorAll(`input[name="${name}"]`).forEach(input => this.#removeButton(input.closest("button"))) + } + + #removeButton(button) { + button.querySelector("input").disabled = true + button.hidden = true + } +} diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index 1077203ab..ee63c983e 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -8,15 +8,23 @@ module Filter::Params end def as_params - params = {}.tap do |h| - h["tag_ids"] = tags.ids - h["bucket_ids"] = buckets.ids - h["assignee_ids"] = assignees.ids - h["indexed_by"] = indexed_by - h["assignments"] = assignments - end + @as_params ||= to_h.dup.tap do |h| + h["tag_ids"] = h.delete("tags")&.ids + h["bucket_ids"] = h.delete("buckets")&.ids + h["assignee_ids"] = h.delete("assignees")&.ids + end.compact_blank + end - params.compact_blank.reject { |k, v| default_fields[k] == v } + def to_h + @to_h ||= {}.tap do |h| + h["indexed_by"] = indexed_by + h["assignments"] = assignments + h["assignees"] = assignees + h["tags"] = tags + h["buckets"] = buckets + end.reject do |k, v| + default_fields[k] == v + end.compact_blank end def to_params diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index c8a511ac5..ebe553043 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -1,6 +1,6 @@ -
    +

    - Writebook + <%= filter.buckets.first&.name || "All projects" %>

    @@ -9,35 +9,9 @@ Filter - - - - - - - - - - - + <%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %> + <%= filter_buttons filter %> + <% end %>
    @@ -45,9 +19,9 @@
    -

    - Writebook -

    +

    + <%= filter.buckets.first&.name || "All projects" %> +

    - - - - - - - - - - - + <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> + <%= filter_buttons filter, class: "fill-selected" %> + <% end %>
    @@ -109,7 +57,7 @@
  • Sort by
  • <% Filter::INDEXES.each do |index| %> -
  • <%= link_to index.humanize, bubbles_path(filter.to_params.merge(indexed_by: index)), class: "filter__button" %>
  • +
  • <%= button_to_filter index.humanize, kind: :indexed_by, object: index, data: { action: "filter-form#clearCategory", filter_form_name_param: "indexed_by" } %>
  • <% end %>
    @@ -118,9 +66,9 @@
  • In Project
  • -
  • <%= link_to "All projects", bubbles_path(filter.to_params.merge(bucket_ids: nil)), class: "filter__button" %>
  • +
  • <%= button_to_filter "All projects", kind: :buckets, object: nil, data: { action: "filter-form#clearCategory", filter_form_name_param: "bucket_ids[]" } %>
  • <% Current.user.buckets.order(:name).each do |bucket| %> -
  • <%= link_to bucket.name, bubbles_path(filter.to_params.merge(bucket_ids: [ bucket.id ])), class: "filter__button" %>
  • +
  • <%= button_to_filter bucket.name, kind: :buckets, object: bucket %>
  • <% end %>
    @@ -130,7 +78,7 @@
  • Tagged
  • <% Current.account.tags.order(:title).each do |tag| %> -
  • <%= link_to tag.title, bubbles_path(filter.to_params.merge(tag_ids: [ tag.id ])) %>
  • +
  • <%= button_to_filter tag.title, kind: :tags, object: tag %>
  • <% end %>
    @@ -139,9 +87,10 @@
  • Assigned to…
  • -
  • <%= link_to "No one", bubbles_path(filter.to_params.merge(assignments: :unassigned, assignee_ids: [])), class: "filter__button" %>
  • - <% Current.account.users.active.order(:name).each do |user| %> -
  • <%= link_to user.name, bubbles_path(filter.to_params.merge(assignments: nil, assignee_ids: [ user.id ])) %>
  • +
  • <%= button_to_filter "No one", kind: :assignments, object: "unassigned", data: { action: "filter-form#clearCategory", filter_form_name_param: "assignee_ids[]" } %>
  • +
  • <%= button_to_filter "Me", kind: :assignees, object: Current.user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • + <% Current.account.users.active.without(Current.user).order(:name).each do |user| %> +
  • <%= button_to_filter user.name, kind: :assignees, object: user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • <% end %>
    @@ -150,9 +99,9 @@
  • Assigned by…
  • -
  • Me
  • - <% Current.account.users.active.order(:name).each do |user| %> -
  • <%= link_to user.name, bubbles_path(filter.to_params.merge(assignments: nil, assignee_ids: [ user.id ])) %>
  • +
  • <%= button_to_filter "Me", kind: :assigners, object: Current.user %>
  • + <% Current.account.users.active.without(Current.user).order(:name).each do |user| %> +
  • <%= button_to_filter user.name, kind: :assigners, object: user %>
  • <% end %>
    @@ -160,12 +109,12 @@
    - + <% end %> - diff --git a/app/views/filter_buttons/create.turbo_stream.erb b/app/views/filter_buttons/create.turbo_stream.erb new file mode 100644 index 000000000..0a242797e --- /dev/null +++ b/app/views/filter_buttons/create.turbo_stream.erb @@ -0,0 +1,4 @@ +<%= turbo_stream.remove filter_button_id(params[:value], params[:name]) %> +<%= turbo_stream.append :filter_form do %> + <%= filter_button_tag display: params[:display], value: params[:value], name: params[:name], class: "fill-selected" %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 0778fb130..c412efff6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -33,6 +33,7 @@ Rails.application.routes.draw do end resources :filters + resources :filter_buttons resource :first_run resource :session From eff8539b66c20e47a4c16d7de2f61f141e27f644 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Mon, 11 Nov 2024 14:23:00 -0600 Subject: [PATCH 06/29] Fix test --- test/models/filter_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/filter_test.rb b/test/models/filter_test.rb index cffe18792..ae50cb915 100644 --- a/test/models/filter_test.rb +++ b/test/models/filter_test.rb @@ -56,7 +56,7 @@ class FilterTest < ActiveSupport::TestCase assert_changes "filter.reload.updated_at" do tags(:mobile).destroy! end - assert_nil filter.reload.as_params["tag_ids"] + assert_nil Filter.find(filter.id).as_params["tag_ids"] # can't reload because as_params is memoized assert_changes "Filter.exists?(filter.id)" do buckets(:writebook).destroy! From 9e99d961bacee216472fbc1dd25113c0b8f43fb6 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Mon, 11 Nov 2024 15:05:54 -0600 Subject: [PATCH 07/29] Iron out quirks from navigating back and forth --- app/helpers/filters_helper.rb | 4 +++- .../controllers/filter_form_controller.js | 17 ++++++++++++++--- app/views/bubbles/_filters.html.erb | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 80621407e..f2f224dd6 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -10,7 +10,9 @@ module FiltersHelper end def filter_button_tag(display:, value:, name:, **options) - tag.button id: filter_button_id(value, name), class: [ "btn txt-small btn--remove", options.delete(:class) ], data: { action: "filter-form#removeFilter form#submit" } do + tag.button id: filter_button_id(value, name), + class: [ "btn txt-small btn--remove", options.delete(:class) ], + data: { action: "filter-form#removeFilter form#submit", filter_form_target: "button" } do concat hidden_field_tag(name, value, id: nil) concat tag.span(display) concat image_tag("close.svg", aria: { hidden: true }, size: 24) diff --git a/app/javascript/controllers/filter_form_controller.js b/app/javascript/controllers/filter_form_controller.js index b55cc6069..65ac570a1 100644 --- a/app/javascript/controllers/filter_form_controller.js +++ b/app/javascript/controllers/filter_form_controller.js @@ -1,16 +1,27 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { + static targets = [ "button" ] + + connect() { + this.buttonTargets.forEach(button => this.#showButton(button)) + } + removeFilter(event) { event.preventDefault() - this.#removeButton(event.target.closest("button")) + this.#hideButton(event.target.closest("button")) } clearCategory({ params: { name } }) { - this.element.querySelectorAll(`input[name="${name}"]`).forEach(input => this.#removeButton(input.closest("button"))) + this.element.querySelectorAll(`input[name="${name}"]`).forEach(input => this.#hideButton(input.closest("button"))) } - #removeButton(button) { + #showButton(button) { + button.querySelector("input").disabled = false + button.hidden = false + } + + #hideButton(button) { button.querySelector("input").disabled = true button.hidden = true } diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index ebe553043..f5233e139 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -1,4 +1,4 @@ -
    +

    <%= filter.buckets.first&.name || "All projects" %>

    From 3b513fc72688369c79d76141adeb620abdb1d1fd Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Mon, 11 Nov 2024 15:40:10 -0600 Subject: [PATCH 08/29] Wire up search --- app/controllers/bubbles_controller.rb | 5 ++++- app/helpers/filters_helper.rb | 14 +++++++++++--- app/views/bubbles/_filters.html.erb | 11 ++++++----- app/views/bubbles/index.html.erb | 2 +- app/views/filter_buttons/create.turbo_stream.erb | 4 +++- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/app/controllers/bubbles_controller.rb b/app/controllers/bubbles_controller.rb index 7765be897..97cc84a2a 100644 --- a/app/controllers/bubbles_controller.rb +++ b/app/controllers/bubbles_controller.rb @@ -8,7 +8,10 @@ class BubblesController < ApplicationController def index @bubbles = @filter.bubbles - @bubbles = @bubbles.mentioning(params[:term]) if params[:term].present? + + Array.wrap(params[:terms]).each do |term| + @bubbles = @bubbles.mentioning(term) + end end def create diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index f2f224dd6..ef458cb44 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -3,10 +3,16 @@ module FiltersHelper "#{name}_filter--#{value}" end - def filter_buttons(filter, **) - filter.to_h.map do |kind, object| + def filter_buttons(filter, terms, **) + filters = filter.to_h.map do |kind, object| filter_button_from kind, object, ** - end.join.html_safe + end + + terms = Array.wrap(terms).map do |term| + filter_button_from :terms, term, ** + end + + safe_join filters + terms end def filter_button_tag(display:, value:, name:, **options) @@ -50,6 +56,8 @@ module FiltersHelper [ object.humanize, object, "indexed_by" ] when :assignments [ object.humanize, object, "assignments" ] + when :terms + [ %Q("#{object}"), object, "terms[]" ] end.then do |display, value, name| { display: display, value: value, name: name } end diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index f5233e139..e64765602 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -10,7 +10,7 @@ <%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %> - <%= filter_buttons filter %> + <%= filter_buttons filter, terms %> <% end %>
    @@ -38,18 +38,19 @@ <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> - <%= filter_buttons filter, class: "fill-selected" %> + <%= filter_buttons filter, terms, class: "fill-selected" %> <% end %>
    -
    - + <%= form_with url: filter_buttons_path, method: :post, class: "flex gap flex-item-grow align-center justify-center full-width center margin-block" do %> + <%= hidden_field_tag :name, "terms[]" %> + -
    + <% end %>
    diff --git a/app/views/bubbles/index.html.erb b/app/views/bubbles/index.html.erb index 406a1960d..9065ff749 100644 --- a/app/views/bubbles/index.html.erb +++ b/app/views/bubbles/index.html.erb @@ -8,7 +8,7 @@ <% end %>
    - <%= render "bubbles/filters", filter: @filter %> + <%= render "bubbles/filters", filter: @filter, terms: params[:terms] %>
    <% if @filter.buckets.any? %> diff --git a/app/views/filter_buttons/create.turbo_stream.erb b/app/views/filter_buttons/create.turbo_stream.erb index 0a242797e..b7546c382 100644 --- a/app/views/filter_buttons/create.turbo_stream.erb +++ b/app/views/filter_buttons/create.turbo_stream.erb @@ -1,4 +1,6 @@ <%= turbo_stream.remove filter_button_id(params[:value], params[:name]) %> + <%= turbo_stream.append :filter_form do %> - <%= filter_button_tag display: params[:display], value: params[:value], name: params[:name], class: "fill-selected" %> + <%= filter_button_tag display: params[:display] || %Q("#{params[:value]}"), + value: params[:value], name: params[:name], class: "fill-selected" %> <% end %> From adf98d61b81f30bd85746042b9d23af86e73445d Mon Sep 17 00:00:00 2001 From: Jason Zimdars Date: Mon, 11 Nov 2024 17:15:52 -0600 Subject: [PATCH 09/29] Fix styles regression --- app/assets/stylesheets/filters.css | 32 ++++++++++++++--------------- app/helpers/filters_helper.rb | 4 ++-- app/views/bubbles/_filters.html.erb | 10 ++++----- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/assets/stylesheets/filters.css b/app/assets/stylesheets/filters.css index ec0729942..95d988c49 100644 --- a/app/assets/stylesheets/filters.css +++ b/app/assets/stylesheets/filters.css @@ -5,29 +5,27 @@ } } -.filter__label { +.filter__button { + border-radius: 0.5em; + color: var(--color-ink); + display: block; + overflow: hidden; padding: 0.3em 0.7em; -} + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; -.filter__menu { - a { - border-radius: 0.5em; - color: var(--color-ink); - display: block; - overflow: hidden; - padding: 0.3em 0.7em; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; - - @media (hover: hover) { - &:hover { - background-color: var(--color-selected); - } + @media (hover: hover) { + &:hover { + background-color: var(--color-selected); } } } +.filter__label { + padding: 0.3em 0.7em; +} + .filter__popup { --panel-border-radius: 0.5em; --panel-padding: 0.5em; diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index ef458cb44..08b0635e3 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -27,9 +27,9 @@ module FiltersHelper def button_to_filter(text, kind:, object:, data: {}) if object - button_to text, filter_buttons_path, method: :post, class: "btn btn--plain", params: filter_attrs(kind, object), data: data + button_to text, filter_buttons_path, method: :post, class: "btn btn--plain filter__button", params: filter_attrs(kind, object), data: data else - button_tag text, type: :button, class: "btn btn--plain", data: data + button_tag text, type: :button, class: "btn btn--plain filter__button", data: data end end diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index e64765602..370b74e44 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -55,7 +55,7 @@
    - +
  • Sort by
  • <% Filter::INDEXES.each do |index| %>
  • <%= button_to_filter index.humanize, kind: :indexed_by, object: index, data: { action: "filter-form#clearCategory", filter_form_name_param: "indexed_by" } %>
  • @@ -65,7 +65,7 @@
    - +
  • In Project
  • <%= button_to_filter "All projects", kind: :buckets, object: nil, data: { action: "filter-form#clearCategory", filter_form_name_param: "bucket_ids[]" } %>
  • <% Current.user.buckets.order(:name).each do |bucket| %> @@ -76,7 +76,7 @@
    - +
  • Tagged
  • <% Current.account.tags.order(:title).each do |tag| %>
  • <%= button_to_filter tag.title, kind: :tags, object: tag %>
  • @@ -86,7 +86,7 @@
    - +
  • Assigned to…
  • <%= button_to_filter "No one", kind: :assignments, object: "unassigned", data: { action: "filter-form#clearCategory", filter_form_name_param: "assignee_ids[]" } %>
  • <%= button_to_filter "Me", kind: :assignees, object: Current.user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • @@ -98,7 +98,7 @@
    - +
  • Assigned by…
  • <%= button_to_filter "Me", kind: :assigners, object: Current.user %>
  • <% Current.account.users.active.without(Current.user).order(:name).each do |user| %> From 6384d5eb0e3d12a243f82ff626cf6e52bd8be6be Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Mon, 11 Nov 2024 17:29:16 -0600 Subject: [PATCH 10/29] Remove most_active as index option --- app/models/filter/fields.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/filter/fields.rb b/app/models/filter/fields.rb index 2db92f0e3..68268545c 100644 --- a/app/models/filter/fields.rb +++ b/app/models/filter/fields.rb @@ -1,7 +1,7 @@ module Filter::Fields extend ActiveSupport::Concern - INDEXES = %w[ most_active most_discussed most_boosted newest oldest popped ] + INDEXES = %w[ most_discussed most_boosted newest oldest popped ] class_methods do def default_fields From e53df951f24305eaa8587561635ba69d343ec307 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 16:36:38 -0600 Subject: [PATCH 11/29] KNOWN_PARAMS -> PERMITTED_PARAMS --- app/controllers/bubbles_controller.rb | 2 +- app/controllers/filters_controller.rb | 2 +- app/models/filter/params.rb | 10 +++------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/controllers/bubbles_controller.rb b/app/controllers/bubbles_controller.rb index 97cc84a2a..756407558 100644 --- a/app/controllers/bubbles_controller.rb +++ b/app/controllers/bubbles_controller.rb @@ -33,7 +33,7 @@ class BubblesController < ApplicationController private def set_filter - @filter = Current.user.filters.build params.permit(*Filter::KNOWN_PARAMS) + @filter = Current.user.filters.build params.permit(*Filter::PERMITTED_PARAMS) end def set_bubble diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index 34a020c4f..1274f11d8 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -17,7 +17,7 @@ class FiltersController < ApplicationController end def filter_params - params.permit(*Filter::KNOWN_PARAMS).compact_blank + params.permit(*Filter::PERMITTED_PARAMS).compact_blank end def redirect_after_destroy diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index ee63c983e..cac5a6641 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -1,10 +1,10 @@ module Filter::Params extend ActiveSupport::Concern - KNOWN_PARAMS = [ :indexed_by, :assignments, bucket_ids: [], assignee_ids: [], tag_ids: [] ] + PERMITTED_PARAMS = [ :indexed_by, :assignments, bucket_ids: [], assignee_ids: [], tag_ids: [] ] included do - before_save { self.params_digest = hashed_params } + before_save { self.params_digest = self.class.digest_params(as_params) } end def as_params @@ -28,12 +28,8 @@ module Filter::Params end def to_params - ActionController::Parameters.new(as_params).permit(*KNOWN_PARAMS).tap do |params| + ActionController::Parameters.new(as_params).permit(*PERMITTED_PARAMS).tap do |params| params[:filter_id] = id if persisted? end end - - def hashed_params - Digest::MD5.hexdigest as_params.to_json - end end From e399702217799fa65d666a0cb9b98e7842b64a64 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 16:36:59 -0600 Subject: [PATCH 12/29] Clean up Filter class methods --- app/models/filter.rb | 14 ++++++++++---- app/models/filter/resources.rb | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/models/filter.rb b/app/models/filter.rb index c3d163c97..74a56301a 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -6,12 +6,18 @@ class Filter < ApplicationRecord class << self def persist!(attrs) - filter = new(attrs) - filter.save! - filter + create!(attrs) rescue ActiveRecord::RecordNotUnique - find_by!(params_digest: filter.hashed_params).tap(&:touch) + find_by!(params_digest: digest_params(attrs)).tap(&:touch) end + + def digest_params(params) + Digest::MD5.hexdigest params.to_json + end + end + + def empty? + as_params.blank? end def bubbles diff --git a/app/models/filter/resources.rb b/app/models/filter/resources.rb index e44fd91f8..d7cc35e2e 100644 --- a/app/models/filter/resources.rb +++ b/app/models/filter/resources.rb @@ -10,6 +10,6 @@ module Filter::Resources def resource_removed(resource) kind = resource.class.model_name.plural send "#{kind}=", send(kind).without(resource) - as_params.blank? ? destroy! : save! + empty? ? destroy! : save! end end From 8bc89d497c9b3076c717118f84d51f0b9a062ea9 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 18:55:35 -0600 Subject: [PATCH 13/29] buttons -> chips --- app/controllers/filter_buttons_controller.rb | 4 ---- app/controllers/filter_chips_controller.rb | 4 ++++ app/helpers/filters_helper.rb | 14 +++++++------- app/views/bubbles/_filters.html.erb | 6 +++--- app/views/filter_buttons/create.turbo_stream.erb | 6 ------ app/views/filter_chips/create.turbo_stream.erb | 6 ++++++ config/routes.rb | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) delete mode 100644 app/controllers/filter_buttons_controller.rb create mode 100644 app/controllers/filter_chips_controller.rb delete mode 100644 app/views/filter_buttons/create.turbo_stream.erb create mode 100644 app/views/filter_chips/create.turbo_stream.erb diff --git a/app/controllers/filter_buttons_controller.rb b/app/controllers/filter_buttons_controller.rb deleted file mode 100644 index 20d316679..000000000 --- a/app/controllers/filter_buttons_controller.rb +++ /dev/null @@ -1,4 +0,0 @@ -class FilterButtonsController < ApplicationController - def create - end -end diff --git a/app/controllers/filter_chips_controller.rb b/app/controllers/filter_chips_controller.rb new file mode 100644 index 000000000..d08c906f3 --- /dev/null +++ b/app/controllers/filter_chips_controller.rb @@ -0,0 +1,4 @@ +class FilterChipsController < ApplicationController + def create + end +end diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 08b0635e3..bfb22cfc5 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -1,9 +1,9 @@ module FiltersHelper - def filter_button_id(value, name) + def filter_chip_id(value, name) "#{name}_filter--#{value}" end - def filter_buttons(filter, terms, **) + def filter_chips(filter, terms, **) filters = filter.to_h.map do |kind, object| filter_button_from kind, object, ** end @@ -15,8 +15,8 @@ module FiltersHelper safe_join filters + terms end - def filter_button_tag(display:, value:, name:, **options) - tag.button id: filter_button_id(value, name), + def filter_chip_tag(display:, value:, name:, **options) + tag.button id: filter_chip_id(value, name), class: [ "btn txt-small btn--remove", options.delete(:class) ], data: { action: "filter-form#removeFilter form#submit", filter_form_target: "button" } do concat hidden_field_tag(name, value, id: nil) @@ -27,7 +27,7 @@ module FiltersHelper def button_to_filter(text, kind:, object:, data: {}) if object - button_to text, filter_buttons_path, method: :post, class: "btn btn--plain filter__button", params: filter_attrs(kind, object), data: data + button_to text, filter_chips_path, method: :post, class: "btn btn--plain filter__button", params: filter_attrs(kind, object), data: data else button_tag text, type: :button, class: "btn btn--plain filter__button", data: data end @@ -36,9 +36,9 @@ module FiltersHelper private def filter_button_from(kind, object, **) if object.respond_to? :map - safe_join object.map { |o| filter_button_tag(**filter_attrs(kind, o), **) } + safe_join object.map { |o| filter_chip_tag(**filter_attrs(kind, o), **) } else - filter_button_tag(**filter_attrs(kind, object), **) + filter_chip_tag(**filter_attrs(kind, object), **) end end diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index 370b74e44..139e2919c 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -10,7 +10,7 @@ <%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %> - <%= filter_buttons filter, terms %> + <%= filter_chips filter, terms %> <% end %>
    @@ -38,11 +38,11 @@ <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> - <%= filter_buttons filter, terms, class: "fill-selected" %> + <%= filter_chips filter, terms, class: "fill-selected" %> <% end %>
    - <%= form_with url: filter_buttons_path, method: :post, class: "flex gap flex-item-grow align-center justify-center full-width center margin-block" do %> + <%= form_with url: filter_chips_path, method: :post, class: "flex gap flex-item-grow align-center justify-center full-width center margin-block" do %> <%= hidden_field_tag :name, "terms[]" %> diff --git a/app/views/filter_buttons/create.turbo_stream.erb b/app/views/filter_buttons/create.turbo_stream.erb deleted file mode 100644 index b7546c382..000000000 --- a/app/views/filter_buttons/create.turbo_stream.erb +++ /dev/null @@ -1,6 +0,0 @@ -<%= turbo_stream.remove filter_button_id(params[:value], params[:name]) %> - -<%= turbo_stream.append :filter_form do %> - <%= filter_button_tag display: params[:display] || %Q("#{params[:value]}"), - value: params[:value], name: params[:name], class: "fill-selected" %> -<% end %> diff --git a/app/views/filter_chips/create.turbo_stream.erb b/app/views/filter_chips/create.turbo_stream.erb new file mode 100644 index 000000000..382e2ecb9 --- /dev/null +++ b/app/views/filter_chips/create.turbo_stream.erb @@ -0,0 +1,6 @@ +<%= turbo_stream.remove filter_chip_id(params[:value], params[:name]) %> + +<%= turbo_stream.append :filter_form do %> + <%= filter_chip_tag display: params[:display] || %Q("#{params[:value]}"), + value: params[:value], name: params[:name], class: "fill-selected" %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index c412efff6..dffa263f2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -33,7 +33,7 @@ Rails.application.routes.draw do end resources :filters - resources :filter_buttons + resources :filter_chips resource :first_run resource :session From 932fc341cede488b80e8a6472c251226fd8ecbb8 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 19:14:40 -0600 Subject: [PATCH 14/29] Add terms to filter --- app/helpers/filters_helper.rb | 12 +++--------- app/models/filter.rb | 4 ++++ app/models/filter/fields.rb | 22 +++++++++++----------- app/models/filter/params.rb | 3 ++- app/models/filter/summarized.rb | 8 +++++++- app/views/bubbles/_filters.html.erb | 4 ++-- app/views/bubbles/index.html.erb | 2 +- 7 files changed, 30 insertions(+), 25 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index bfb22cfc5..3e66f5f5c 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -3,16 +3,10 @@ module FiltersHelper "#{name}_filter--#{value}" end - def filter_chips(filter, terms, **) - filters = filter.to_h.map do |kind, object| + def filter_chips(filter, **) + filter.to_h.map do |kind, object| filter_button_from kind, object, ** - end - - terms = Array.wrap(terms).map do |term| - filter_button_from :terms, term, ** - end - - safe_join filters + terms + end.join.html_safe end def filter_chip_tag(display:, value:, name:, **options) diff --git a/app/models/filter.rb b/app/models/filter.rb index 74a56301a..e8f7b2f60 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -28,6 +28,10 @@ class Filter < ApplicationRecord result = result.assigned_to(assignees.ids) if assignees.present? result = result.in_bucket(buckets.ids) if buckets.present? result = result.tagged_with(tags.ids) if tags.present? + result = terms.reduce(result) do |result, term| + result.mentioning(term) + end + result end end diff --git a/app/models/filter/fields.rb b/app/models/filter/fields.rb index 68268545c..085ead833 100644 --- a/app/models/filter/fields.rb +++ b/app/models/filter/fields.rb @@ -9,20 +9,20 @@ module Filter::Fields end end - def assignments=(value) - fields["assignments"] = value - end + included do + store_accessor :fields, :indexed_by, :assignments, :terms - def assignments - fields["assignments"].to_s.inquiry - end + def indexed_by + (super || default_fields["indexed_by"]).inquiry + end - def indexed_by=(value) - fields["indexed_by"] = value - end + def assignments + super.to_s.inquiry + end - def indexed_by - (fields["indexed_by"] || default_fields["indexed_by"]).inquiry + def terms + Array(super) + end end private diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index cac5a6641..6fe266b53 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -1,7 +1,7 @@ module Filter::Params extend ActiveSupport::Concern - PERMITTED_PARAMS = [ :indexed_by, :assignments, bucket_ids: [], assignee_ids: [], tag_ids: [] ] + PERMITTED_PARAMS = [ :indexed_by, :assignments, bucket_ids: [], assignee_ids: [], tag_ids: [], terms: [] ] included do before_save { self.params_digest = self.class.digest_params(as_params) } @@ -22,6 +22,7 @@ module Filter::Params h["assignees"] = assignees h["tags"] = tags h["buckets"] = buckets + h["terms"] = terms end.reject do |k, v| default_fields[k] == v end.compact_blank diff --git a/app/models/filter/summarized.rb b/app/models/filter/summarized.rb index 67f194e81..c6c23adfd 100644 --- a/app/models/filter/summarized.rb +++ b/app/models/filter/summarized.rb @@ -1,6 +1,6 @@ module Filter::Summarized def summary - [ index_summary, tag_summary, assignee_summary ].compact.to_sentence + " #{bucket_summary}" + [ index_summary, tag_summary, assignee_summary, terms_summary ].compact.to_sentence + " #{bucket_summary}" end def plain_summary @@ -33,4 +33,10 @@ module Filter::Summarized "in all projects" end end + + def terms_summary + if terms.any? + "matching #{terms.map { |term| %Q("#{term}") }.to_sentence}" + end + end end diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index 139e2919c..abf39c727 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -10,7 +10,7 @@ <%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %> - <%= filter_chips filter, terms %> + <%= filter_chips filter %> <% end %>
    @@ -38,7 +38,7 @@ <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> - <%= filter_chips filter, terms, class: "fill-selected" %> + <%= filter_chips filter, class: "fill-selected" %> <% end %>
    diff --git a/app/views/bubbles/index.html.erb b/app/views/bubbles/index.html.erb index 9065ff749..406a1960d 100644 --- a/app/views/bubbles/index.html.erb +++ b/app/views/bubbles/index.html.erb @@ -8,7 +8,7 @@ <% end %>
    - <%= render "bubbles/filters", filter: @filter, terms: params[:terms] %> + <%= render "bubbles/filters", filter: @filter %>
    <% if @filter.buckets.any? %> From ea1fb674d952ebd844553102f64ac041a9d580c4 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 19:24:51 -0600 Subject: [PATCH 15/29] No need to apply terms from the controller anymore --- app/controllers/bubbles_controller.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/bubbles_controller.rb b/app/controllers/bubbles_controller.rb index 756407558..2c8cf0be5 100644 --- a/app/controllers/bubbles_controller.rb +++ b/app/controllers/bubbles_controller.rb @@ -8,10 +8,6 @@ class BubblesController < ApplicationController def index @bubbles = @filter.bubbles - - Array.wrap(params[:terms]).each do |term| - @bubbles = @bubbles.mentioning(term) - end end def create From d77eafe012758ae425b9c79bdc0dfed137a7a29b Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 19:26:21 -0600 Subject: [PATCH 16/29] button -> chip --- app/helpers/filters_helper.rb | 14 +++++++------- app/views/bubbles/_filters.html.erb | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 3e66f5f5c..a6689350c 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -5,7 +5,7 @@ module FiltersHelper def filter_chips(filter, **) filter.to_h.map do |kind, object| - filter_button_from kind, object, ** + filter_chip_from kind, object, ** end.join.html_safe end @@ -19,24 +19,24 @@ module FiltersHelper end end - def button_to_filter(text, kind:, object:, data: {}) + def button_to_chip(text, kind:, object:, data: {}) if object - button_to text, filter_chips_path, method: :post, class: "btn btn--plain filter__button", params: filter_attrs(kind, object), data: data + button_to text, filter_chips_path, method: :post, class: "btn btn--plain filter__button", params: chip_attrs(kind, object), data: data else button_tag text, type: :button, class: "btn btn--plain filter__button", data: data end end private - def filter_button_from(kind, object, **) + def filter_chip_from(kind, object, **) if object.respond_to? :map - safe_join object.map { |o| filter_chip_tag(**filter_attrs(kind, o), **) } + safe_join object.map { |o| filter_chip_tag(**chip_attrs(kind, o), **) } else - filter_chip_tag(**filter_attrs(kind, object), **) + filter_chip_tag(**chip_attrs(kind, object), **) end end - def filter_attrs(kind, object) + def chip_attrs(kind, object) case kind&.to_sym when :tags [ object.hashtag, object.id, "tag_ids[]" ] diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index abf39c727..be34a65a6 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -58,7 +58,7 @@
  • Sort by
  • <% Filter::INDEXES.each do |index| %> -
  • <%= button_to_filter index.humanize, kind: :indexed_by, object: index, data: { action: "filter-form#clearCategory", filter_form_name_param: "indexed_by" } %>
  • +
  • <%= button_to_chip index.humanize, kind: :indexed_by, object: index, data: { action: "filter-form#clearCategory", filter_form_name_param: "indexed_by" } %>
  • <% end %>
    @@ -67,9 +67,9 @@
  • In Project
  • -
  • <%= button_to_filter "All projects", kind: :buckets, object: nil, data: { action: "filter-form#clearCategory", filter_form_name_param: "bucket_ids[]" } %>
  • +
  • <%= button_to_chip "All projects", kind: :buckets, object: nil, data: { action: "filter-form#clearCategory", filter_form_name_param: "bucket_ids[]" } %>
  • <% Current.user.buckets.order(:name).each do |bucket| %> -
  • <%= button_to_filter bucket.name, kind: :buckets, object: bucket %>
  • +
  • <%= button_to_chip bucket.name, kind: :buckets, object: bucket %>
  • <% end %>
    @@ -79,7 +79,7 @@
  • Tagged
  • <% Current.account.tags.order(:title).each do |tag| %> -
  • <%= button_to_filter tag.title, kind: :tags, object: tag %>
  • +
  • <%= button_to_chip tag.title, kind: :tags, object: tag %>
  • <% end %>
    @@ -88,10 +88,10 @@
  • Assigned to…
  • -
  • <%= button_to_filter "No one", kind: :assignments, object: "unassigned", data: { action: "filter-form#clearCategory", filter_form_name_param: "assignee_ids[]" } %>
  • -
  • <%= button_to_filter "Me", kind: :assignees, object: Current.user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • +
  • <%= button_to_chip "No one", kind: :assignments, object: "unassigned", data: { action: "filter-form#clearCategory", filter_form_name_param: "assignee_ids[]" } %>
  • +
  • <%= button_to_chip "Me", kind: :assignees, object: Current.user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • <% Current.account.users.active.without(Current.user).order(:name).each do |user| %> -
  • <%= button_to_filter user.name, kind: :assignees, object: user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • +
  • <%= button_to_chip user.name, kind: :assignees, object: user, data: { action: "filter-form#clearCategory", filter_form_name_param: "assignments" } %>
  • <% end %>
    @@ -100,9 +100,9 @@
  • Assigned by…
  • -
  • <%= button_to_filter "Me", kind: :assigners, object: Current.user %>
  • +
  • <%= button_to_chip "Me", kind: :assigners, object: Current.user %>
  • <% Current.account.users.active.without(Current.user).order(:name).each do |user| %> -
  • <%= button_to_filter user.name, kind: :assigners, object: user %>
  • +
  • <%= button_to_chip user.name, kind: :assigners, object: user %>
  • <% end %>
    From ec16237bf49b11b93fa1b9490b232b6fe50ce4ba Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 19:58:19 -0600 Subject: [PATCH 17/29] Render each kind of filter in its own frame --- app/helpers/filters_helper.rb | 48 +++++++++++++++---- app/models/filter/params.rb | 4 +- app/views/bubbles/_filters.html.erb | 2 +- .../filter_chips/create.turbo_stream.erb | 7 +-- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index a6689350c..568c324e0 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -4,9 +4,25 @@ module FiltersHelper end def filter_chips(filter, **) - filter.to_h.map do |kind, object| - filter_chip_from kind, object, ** - end.join.html_safe + safe_join [ + chips_for_filter_kind(filter, :indexed_by, **), + chips_for_filter_kind(filter, :tags, **), + chips_for_filter_kind(filter, :assignees, **), + chips_for_filter_kind(filter, :assigners, **), + chips_for_filter_kind(filter, :buckets, **), + chips_for_filter_kind(filter, :terms, **) + ] + end + + def filter_chips_for_editing(filter, **) + safe_join [ + frame_for_filter_kind(filter, :indexed_by, **), + frame_for_filter_kind(filter, :tags, **), + frame_for_filter_kind(filter, :assignees, **), + frame_for_filter_kind(filter, :assigners, **), + frame_for_filter_kind(filter, :buckets, **), + frame_for_filter_kind(filter, :terms, **) + ] end def filter_chip_tag(display:, value:, name:, **options) @@ -28,11 +44,13 @@ module FiltersHelper end private - def filter_chip_from(kind, object, **) - if object.respond_to? :map - safe_join object.map { |o| filter_chip_tag(**chip_attrs(kind, o), **) } - else - filter_chip_tag(**chip_attrs(kind, object), **) + def chips_for_filter_kind(filter, kind, **) + Array(filter.to_h[kind]).map do |value| + if value.respond_to? :map + safe_join value.map { |v| filter_chip_tag(**chip_attrs(kind, v), **) } + else + filter_chip_tag(**chip_attrs(kind, value), **) + end end end @@ -53,7 +71,19 @@ module FiltersHelper when :terms [ %Q("#{object}"), object, "terms[]" ] end.then do |display, value, name| - { display: display, value: value, name: name } + { display: display, value: value, name: name, frame: filter_chip_frame(kind) } + end + end + + def filter_chip_frame(kind) + "#{kind}_chips" + end + + def frame_for_filter_kind(filter, kind, **) + chips_for_filter_kind(filter, kind, **).then do |chips| + turbo_frame_tag filter_chip_frame(kind) do + safe_join chips + end end end end diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index 6fe266b53..9baefc1f1 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -12,7 +12,7 @@ module Filter::Params h["tag_ids"] = h.delete("tags")&.ids h["bucket_ids"] = h.delete("buckets")&.ids h["assignee_ids"] = h.delete("assignees")&.ids - end.compact_blank + end.compact_blank.with_indifferent_access end def to_h @@ -25,7 +25,7 @@ module Filter::Params h["terms"] = terms end.reject do |k, v| default_fields[k] == v - end.compact_blank + end.compact_blank.with_indifferent_access end def to_params diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index be34a65a6..44593b37e 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -38,7 +38,7 @@ <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> - <%= filter_chips filter, class: "fill-selected" %> + <%= filter_chips_for_editing filter, class: "fill-selected" %> <% end %>
    diff --git a/app/views/filter_chips/create.turbo_stream.erb b/app/views/filter_chips/create.turbo_stream.erb index 382e2ecb9..045a3eaee 100644 --- a/app/views/filter_chips/create.turbo_stream.erb +++ b/app/views/filter_chips/create.turbo_stream.erb @@ -1,6 +1,7 @@ +<% display = params[:display] || %Q("#{params[:value]}") %> + <%= turbo_stream.remove filter_chip_id(params[:value], params[:name]) %> -<%= turbo_stream.append :filter_form do %> - <%= filter_chip_tag display: params[:display] || %Q("#{params[:value]}"), - value: params[:value], name: params[:name], class: "fill-selected" %> +<%= turbo_stream.append params[:frame] do %> + <%= filter_chip_tag display: display, value: params[:value], name: params[:name], class: "fill-selected" %> <% end %> From 8301db767a68a403444445ad25b6af35e0bf00e1 Mon Sep 17 00:00:00 2001 From: Jose Farias Date: Tue, 12 Nov 2024 20:20:38 -0600 Subject: [PATCH 18/29] Add frame to search terms form --- app/helpers/filters_helper.rb | 12 ++++++------ app/models/filter/params.rb | 8 ++++---- app/views/bubbles/_filters.html.erb | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index 568c324e0..ff5a62e37 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -3,6 +3,10 @@ module FiltersHelper "#{name}_filter--#{value}" end + def filter_chip_frame_id(kind) + "#{kind}_chips" + end + def filter_chips(filter, **) safe_join [ chips_for_filter_kind(filter, :indexed_by, **), @@ -71,17 +75,13 @@ module FiltersHelper when :terms [ %Q("#{object}"), object, "terms[]" ] end.then do |display, value, name| - { display: display, value: value, name: name, frame: filter_chip_frame(kind) } + { display: display, value: value, name: name, frame: filter_chip_frame_id(kind) } end end - def filter_chip_frame(kind) - "#{kind}_chips" - end - def frame_for_filter_kind(filter, kind, **) chips_for_filter_kind(filter, kind, **).then do |chips| - turbo_frame_tag filter_chip_frame(kind) do + turbo_frame_tag filter_chip_frame_id(kind) do safe_join chips end end diff --git a/app/models/filter/params.rb b/app/models/filter/params.rb index 9baefc1f1..1b256af53 100644 --- a/app/models/filter/params.rb +++ b/app/models/filter/params.rb @@ -17,12 +17,12 @@ module Filter::Params def to_h @to_h ||= {}.tap do |h| + h["tags"] = tags + h["terms"] = terms + h["buckets"] = buckets + h["assignees"] = assignees h["indexed_by"] = indexed_by h["assignments"] = assignments - h["assignees"] = assignees - h["tags"] = tags - h["buckets"] = buckets - h["terms"] = terms end.reject do |k, v| default_fields[k] == v end.compact_blank.with_indifferent_access diff --git a/app/views/bubbles/_filters.html.erb b/app/views/bubbles/_filters.html.erb index 44593b37e..e74608e23 100644 --- a/app/views/bubbles/_filters.html.erb +++ b/app/views/bubbles/_filters.html.erb @@ -44,6 +44,7 @@ <%= form_with url: filter_chips_path, method: :post, class: "flex gap flex-item-grow align-center justify-center full-width center margin-block" do %> <%= hidden_field_tag :name, "terms[]" %> + <%= hidden_field_tag :frame, filter_chip_frame_id(:terms) %> <%= form_with url: bubbles_path, method: :get, class: "flex-inline center align-center gap-half", data: { controller: "form" } do %> - <%= filter_chips filter %> + <%= filter_chip_tag filter.indexed_by.humanize, name: "indexed_by", value: filter.indexed_by %> + + <% filter.tags.each do |tag| %> + <%= filter_chip_tag tag.hashtag, name: "tag_ids[]", value: tag.id %> + <% end %> + + <% filter.assignees.each do |assignee| %> + <%= filter_chip_tag "for #{assignee.name}", name: "assignee_ids[]", value: assignee.id %> + <% end %> + + <% if filter.assignments.present? %> + <%= filter_chip_tag filter.assignments.humanize, name: "assignments", value: filter.assignments %> + <% end %> + + <% filter.assigners.each do |assigner| %> + <%= filter_chip_tag "by #{assigner.name}", name: "assigner_ids[]", value: assigner.id %> + <% end %> + + <% filter.buckets.each do |bucket| %> + <%= filter_chip_tag "in #{bucket.name}", name: "bucket_ids[]", value: bucket.id %> + <% end %> + + <% filter.terms.each do |term| %> + <%= filter_chip_tag %Q("#{term}"), name: "terms[]", value: term %> + <% end %> <% end %>
    @@ -38,13 +62,50 @@ <%= form_with url: bubbles_path, id: :filter_form, method: :get, class: "flex-inline center align-center gap-half" do %> - <%= filter_chips_for_editing filter, class: "fill-selected" %> + <%= turbo_frame_tag :indexed_by_chips do %> + <%= filter_chip_tag filter.indexed_by.humanize, name: "indexed_by", value: filter.indexed_by, class: "fill-selected" %> + <% end %> + + <%= turbo_frame_tag :tag_chips do %> + <% filter.tags.each do |tag| %> + <%= filter_chip_tag tag.hashtag, name: "tag_ids[]", value: tag.id, class: "fill-selected" %> + <% end %> + <% end %> + + <%= turbo_frame_tag :assignee_chips do %> + <% filter.assignees.each do |assignee| %> + <%= filter_chip_tag "for #{assignee.name}", name: "assignee_ids[]", value: assignee.id, class: "fill-selected" %> + <% end %> + + <% if filter.assignments.present? %> + <%= filter_chip_tag filter.assignments.humanize, name: "assignments", value: filter.assignments, class: "fill-selected" %> + <% end %> + <% end %> + + <%= turbo_frame_tag :assigner_chips do %> + <% filter.assigners.each do |assigner| %> + <%= filter_chip_tag "by #{assigner.name}", name: "assigner_ids[]", value: assigner.id, class: "fill-selected" %> + <% end %> + <% end %> + + <%= turbo_frame_tag :bucket_chips do %> + <% filter.buckets.each do |bucket| %> + <%= filter_chip_tag "in #{bucket.name}", name: "bucket_ids[]", value: bucket.id, class: "fill-selected" %> + <% end %> + <% end %> + + <%= turbo_frame_tag :terms_chips do %> + <% filter.terms.each do |term| %> + <%= filter_chip_tag %Q("#{term}"), name: "terms[]", value: term, class: "fill-selected" %> + <% end %> + <% end %> <% end %>
    <%= form_with url: filter_chips_path, method: :post, class: "flex gap flex-item-grow align-center justify-center full-width center margin-block" do %> <%= hidden_field_tag :name, "terms[]" %> - <%= hidden_field_tag :frame, filter_chip_frame_id(:terms) %> + <%= hidden_field_tag :frame, :terms_chips %> +