Several fixes for saving filters

- Unify terms with the settings form so that terms are saved normally in the same form.
- Fix filter normalization since it was sometimes failing to match the saved filters due to using quotes around number strings.
This commit is contained in:
Jorge Manrubia
2025-09-22 12:55:19 +02:00
parent 717f921a73
commit ce80c843d0
14 changed files with 66 additions and 64 deletions
+5 -1
View File
@@ -17,10 +17,14 @@ module FilterScoped
if params[:filter_id].present? if params[:filter_id].present?
@filter = Current.user.filters.find(params[:filter_id]) @filter = Current.user.filters.find(params[:filter_id])
else else
@filter = Current.user.filters.from_params params.reverse_merge(**Filter.default_values).permit(*Filter::PERMITTED_PARAMS) @filter = Current.user.filters.from_params filter_params
end end
end end
def filter_params
params.reverse_merge(**Filter.default_values).permit(*Filter::PERMITTED_PARAMS)
end
def set_user_filtering def set_user_filtering
@user_filtering = User::Filtering.new(Current.user, @filter, expanded: expanded_param) @user_filtering = User::Filtering.new(Current.user, @filter, expanded: expanded_param)
end end
@@ -1,7 +0,0 @@
class Filters::SaveToggleRefreshesController < ApplicationController
include FilterScoped
def create
turbo_stream.replace("filter-toggle", partial: "filters/filter_toggle", locals: { filter: @filter })
end
end
@@ -0,0 +1,6 @@
class Filters::SettingsRefreshesController < ApplicationController
include FilterScoped
def create
end
end
+1 -1
View File
@@ -16,6 +16,6 @@ class FiltersController < ApplicationController
end end
def filter_params def filter_params
params.permit(*Filter::PERMITTED_PARAMS).compact_blank Filter.normalize_params(params.permit(*Filter::PERMITTED_PARAMS))
end end
end end
@@ -5,26 +5,26 @@ import { post } from "@rails/request.js"
export default class extends Controller { export default class extends Controller {
static classes = ["filtersSet"] static classes = ["filtersSet"]
static targets = ["field", "form"] static targets = ["field", "form"]
static values = { refreshSaveToggleUrl: String } static values = { refreshUrl: String }
initialize() { initialize() {
this.debouncedChange = debounce(this.change.bind(this), 50) this.debouncedToggle = debounce(this.#toggle.bind(this), 50)
} }
connect() { connect() {
this.change() this.#toggle()
} }
change() { change() {
this.#toggleFiltersSetClass() this.#toggle()
this.#refreshSaveToggleButton() this.#refreshSaveToggleButton()
} }
async fieldTargetConnected(field) { async fieldTargetConnected(field) {
this.debouncedChange() this.debouncedToggle()
} }
#toggleFiltersSetClass(shouldAdd) { #toggle() {
this.element.classList.toggle(this.filtersSetClass, this.#hasFiltersSet) this.element.classList.toggle(this.filtersSetClass, this.#hasFiltersSet)
} }
@@ -47,7 +47,7 @@ export default class extends Controller {
} }
#refreshSaveToggleButton() { #refreshSaveToggleButton() {
post(this.refreshSaveToggleUrlValue, { post(this.refreshUrlValue, {
body: this.#collectFilterFormData(), body: this.#collectFilterFormData(),
responseKind: "turbo-stream" responseKind: "turbo-stream"
}) })
+7 -1
View File
@@ -28,7 +28,13 @@ module Filter::Params
end end
def normalize_params(params) def normalize_params(params)
params.to_h.compact_blank.reject(&method(:default_value?)).sort_by { |name, _| name.to_s } params
.to_h
.compact_blank
.reject(&method(:default_value?))
.collect { |name, value| [ name, value.is_a?(Array) ? value.collect(&:to_s) : value.to_s ] }
.sort_by { |name, _| name.to_s }
.to_h
end end
end end
+3 -4
View File
@@ -1,14 +1,13 @@
<div id="filter-toggle"> <div id="filter-settings-save-toggle">
<% if filter.persisted? %> <% if filter.persisted? %>
<%= button_to filter_path(filter), method: :delete, class: "btn txt-x-small btn--reversed", form_class: "inline" do %> <%= button_to filter_path(filter), method: :delete, class: "btn txt-x-small btn--reversed", form_class: "inline" do %>
<%= icon_tag "bookmark-outline" %> <%= icon_tag "bookmark-outline" %>
<span class="for-screen-reader">Remove saved filter</span> <span class="for-screen-reader">Remove saved filter</span>
<% end %> <% end %>
<% else %> <% else %>
<% filter_params = filter.as_params.transform_values { |v| v.respond_to?(:to_str) ? v.to_str : v } %> <%= button_to filters_path(filter.as_params), method: :post, class: "btn txt-x-small", form_class: "inline" do %>
<%= button_to filters_path, method: :post, params: filter_params, class: "btn txt-x-small", form_class: "inline" do %>
<%= icon_tag "bookmark-outline" %> <%= icon_tag "bookmark-outline" %>
<span class="for-screen-reader">Save filter</span> <span class="for-screen-reader">Save filter</span>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>
+20 -7
View File
@@ -1,13 +1,26 @@
<% cache user_filtering do %> <% cache user_filtering do %>
<%= tag.aside id: "filter-settings", <%= tag.aside id: "filter-settings",
class: class_names("filters flex align-center gap-half justify-center center margin-block-end", { "filters--expanded": user_filtering.expanded? }), class: class_names("filters flex align-center gap-half justify-center center margin-block-end", { "filters--expanded": user_filtering.expanded? }),
data: { controller: "toggle-class filter-settings", toggle_class_toggle_class: "filters--expanded", filter_settings_filters_set_class: "filters--has-filters-set", filter_settings_refresh_save_toggle_url_value: save_toggle_refresh_path } do %> data: {
<div class="flex-inline center align-center gap-half" data-controller="toggle-enable"> controller: "toggle-class filter-settings",
<%= render "filters/settings/terms", user_filtering: user_filtering %> toggle_class_toggle_class: "filters--expanded",
<%= render "filters/settings/controls", user_filtering: user_filtering %> filter_settings_filters_set_class: "filters--has-filters-set",
filter_settings_refresh_url_value: settings_refresh_path } do %>
<%= form_with url: cards_path, method: :get, class: "", data: { controller: "form", turbo_frame: "card_columns", filter_settings_target: "form", turbo_action: "advance" } do |form| %>
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
<% user_filtering.filter.collections.each do |collection| %>
<%= filter_hidden_field_tag "collection_ids[]", collection.id %>
<% end %>
<%= render "filters/settings/toggle", user_filtering: user_filtering %> <div class="flex-inline center align-center gap-half" data-controller="toggle-enable">
<%= render "filters/settings/manage", user_filtering: user_filtering %> <%= render "filters/settings/terms", filter: user_filtering.filter, form: form %>
</div> <%= render "filters/settings/controls", user_filtering: user_filtering, form: form %>
<%= render "filters/settings/toggle", user_filtering: user_filtering %>
</div>
<% end %>
<%= render "filters/settings/manage", user_filtering: user_filtering %>
<% end %> <% end %>
<% end %> <% end %>
+1 -1
View File
@@ -1,2 +1,2 @@
<%= turbo_stream.replace("filter-toggle", partial: "filters/filter_toggle", locals: { filter: @filter }) %> <%= turbo_stream.replace("filter-settings-save-toggle", partial: "filters/filter_toggle", locals: { filter: @filter }) %>
<%= turbo_stream.replace("my-filters", partial: "filters/menu/custom", locals: { filters: @filters }) %> <%= turbo_stream.replace("my-filters", partial: "filters/menu/custom", locals: { filters: @filters }) %>
+6 -14
View File
@@ -1,15 +1,7 @@
<%= form_with url: cards_path, method: :get, class: "flex-inline center align-center gap-half", <%= render "filters/settings/sorted_by", user_filtering: user_filtering %>
data: { controller: "form", turbo_frame: "card_columns", turbo_action: "advance", filter_settings_target: "form" } do |form| %> <%= render "filters/settings/indexed_by", user_filtering: user_filtering %>
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %> <%= render "filters/settings/tags", user_filtering: user_filtering %>
<% user_filtering.filter.collections.each do |collection| %> <%= render "filters/settings/assignees", user_filtering: user_filtering %>
<%= filter_hidden_field_tag "collection_ids[]", collection.id %> <%= render "filters/settings/creators", user_filtering: user_filtering %>
<% end %> <%= render "filters/settings/closers", user_filtering: user_filtering %>
<%= render "filters/settings/sorted_by", user_filtering: user_filtering %>
<%= render "filters/settings/indexed_by", user_filtering: user_filtering %>
<%= render "filters/settings/tags", user_filtering: user_filtering %>
<%= render "filters/settings/assignees", user_filtering: user_filtering %>
<%= render "filters/settings/creators", user_filtering: user_filtering %>
<%= render "filters/settings/closers", user_filtering: user_filtering %>
<% end %>
+1 -1
View File
@@ -1,6 +1,6 @@
<% filter = user_filtering.filter %> <% filter = user_filtering.filter %>
<div class="filters__manage center align-center gap-half"> <div class="filters__manage flex">
<%= render "filters/filter_toggle", filter: filter %> <%= render "filters/filter_toggle", filter: filter %>
<%= link_to cards_path(filter.as_params.except(:assignee_ids, :assignment_status, :card_ids, :creator_ids, :closer_ids, :stage_ids, :tag_ids, :terms, :indexed_by, :sorted_by, :creation, :closure)), class: "btn btn--remove txt-x-small" do %> <%= link_to cards_path(filter.as_params.except(:assignee_ids, :assignment_status, :card_ids, :creator_ids, :closer_ids, :stage_ids, :tag_ids, :terms, :indexed_by, :sorted_by, :creation, :closure)), class: "btn btn--remove txt-x-small" do %>
+7 -19
View File
@@ -1,24 +1,12 @@
<% filter = user_filtering.filter %> <% filter.terms.each do |existing_term| %>
<%= hidden_field_tag "terms[]", existing_term %>
<%= form_with url: cards_path, method: :get, class: "", data: { controller: "form", turbo_frame: "card_columns", action: "input->form#debouncedSubmit", filter_settings_target: "form" } do |form| %>
<% filter.as_params.except(:terms).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<% filter.terms.each do |existing_term| %>
<%= hidden_field_tag "terms[]", existing_term %>
<% end %>
<% if user_filtering.expanded? %>
<%= hidden_field_tag :expand_all, user_filtering.expanded? %>
<% end %>
<%= form.text_field "terms[]", placeholder: "Filter these cards…", class: "input txt-x-small filter__terms",
autofocus: false, autocomplete: :off, autocorrect: "off", data: {
"1p-ignore": "true",
action: "input->form#debouncedSubmit keydown.enter->form#submitToTopTarget" } %>
<% end %> <% end %>
<%= form.text_field "terms[]", placeholder: "Filter these cards…", class: "input txt-x-small filter__terms",
autofocus: false, autocomplete: :off, autocorrect: "off", data: {
"1p-ignore": "true",
action: "input->form#debouncedSubmit keydown.enter->form#submitToTopTarget" } %>
<% if filter.terms.present? %> <% if filter.terms.present? %>
<% filter.terms.each do |term| %> <% filter.terms.each do |term| %>
<%= filter_chip_tag %Q("#{term}"), filter.as_params_without(:terms, term) %> <%= filter_chip_tag %Q("#{term}"), filter.as_params_without(:terms, term) %>
@@ -0,0 +1 @@
<%= turbo_stream.replace("filter-settings-save-toggle", partial: "filters/filter_toggle", locals: { filter: @filter }) %>
+1 -1
View File
@@ -84,7 +84,7 @@ Rails.application.routes.draw do
resources :filters do resources :filters do
scope module: :filters do scope module: :filters do
collection do collection do
resource :save_toggle_refresh, only: :create resource :settings_refresh, only: :create
end end
end end
end end