Merge pull request #1133 from basecamp/filtering-nicer
Higher fidelity for filters
This commit is contained in:
@@ -108,7 +108,15 @@
|
||||
}
|
||||
|
||||
.quick-filter {
|
||||
&:not(.default-value):has(.checked) {
|
||||
.checked {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[aria-checked="true"] .checked {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:has([aria-checked="true"]):not(.quick-filter--with-default) {
|
||||
.input--select {
|
||||
--input-background: var(--color-selected);
|
||||
}
|
||||
@@ -130,5 +138,13 @@
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.filters__manage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filters--has-filters-set .filters__manage {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,11 @@ module FilterScoped
|
||||
end
|
||||
|
||||
private
|
||||
DEFAULT_PARAMS = { indexed_by: "all", sorted_by: "latest" }
|
||||
|
||||
def set_filter
|
||||
if params[:filter_id].present?
|
||||
@filter = Current.user.filters.find(params[:filter_id])
|
||||
else
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**DEFAULT_PARAMS).permit(*Filter::PERMITTED_PARAMS)
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**Filter.default_values).permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
class FiltersController < ApplicationController
|
||||
before_action :set_filter, only: :destroy
|
||||
before_action :set_filters
|
||||
|
||||
def create
|
||||
@filter = Current.user.filters.remember filter_params
|
||||
redirect_to cards_path(filter_id: @filter.id)
|
||||
end
|
||||
|
||||
def destroy
|
||||
filter_params = @filter.as_params
|
||||
@filter = Current.user.filters.find(params[:id])
|
||||
@filter.destroy!
|
||||
|
||||
if request.referer == root_url
|
||||
redirect_to root_path
|
||||
else
|
||||
redirect_to cards_path(filter_params)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def set_filter
|
||||
@filter = Current.user.filters.find params[:id]
|
||||
def set_filters
|
||||
@filters = Current.user.filters
|
||||
end
|
||||
|
||||
def filter_params
|
||||
|
||||
@@ -35,8 +35,8 @@ module FiltersHelper
|
||||
}, &block
|
||||
end
|
||||
|
||||
def collapsible_nav_section(title, &block)
|
||||
tag.details class: "popup__section", data: { action: "toggle->nav-section-expander#toggle", nav_section_expander_target: "section", nav_section_expander_key_value: title.parameterize }, open: true do
|
||||
def collapsible_nav_section(title, **properties, &block)
|
||||
tag.details class: "popup__section", data: { action: "toggle->nav-section-expander#toggle", nav_section_expander_target: "section", nav_section_expander_key_value: title.parameterize }, open: true, **properties do
|
||||
concat(tag.summary(class: "popup__section-title") do
|
||||
concat title
|
||||
concat icon_tag "caret-down"
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
#hiddenField
|
||||
|
||||
static targets = [ "label", "item", "hiddenFieldTemplate" ]
|
||||
static values = {
|
||||
selectPropertyName: { type: String, default: "aria-checked" },
|
||||
defaultValue: String,
|
||||
defaultLabel: String
|
||||
}
|
||||
static classes = ["withDefault"]
|
||||
|
||||
connect() {
|
||||
this.#selectedItem = this.#selectedItem
|
||||
}
|
||||
|
||||
change(event) {
|
||||
const item = event.target.closest("[role='checkbox']")
|
||||
if (item) {
|
||||
this.#selectedItem = item
|
||||
}
|
||||
}
|
||||
|
||||
get #selectedLabel() {
|
||||
const selectedValue = this.#selectedItemValue()
|
||||
|
||||
if (this.hasDefaultLabelValue && (selectedValue === this.defaultValueValue || !selectedValue)) {
|
||||
return this.defaultLabelValue
|
||||
}
|
||||
|
||||
return this.#selectedItem?.dataset?.comboboxLabel || ""
|
||||
}
|
||||
|
||||
get #selectedItem() {
|
||||
return this.itemTargets.find(item => item.getAttribute(this.selectPropertyNameValue) === "true")
|
||||
}
|
||||
|
||||
#selectedItemValue() {
|
||||
return this.#selectedItem?.dataset?.comboboxValue || ""
|
||||
}
|
||||
|
||||
set #selectedItem(item) {
|
||||
if (!item) return
|
||||
|
||||
this.#clearSelection()
|
||||
item.setAttribute(this.selectPropertyNameValue, "true")
|
||||
this.labelTarget.textContent = this.#selectedLabel
|
||||
this.hiddenField.value = item.dataset.comboboxValue
|
||||
this.hiddenField.disabled = !item.dataset.comboboxValue
|
||||
this.#updateWithDefaultClass()
|
||||
}
|
||||
|
||||
#clearSelection() {
|
||||
this.itemTargets.forEach(target => {
|
||||
target.setAttribute(this.selectPropertyNameValue, "false")
|
||||
})
|
||||
}
|
||||
|
||||
get hiddenField() {
|
||||
if (!this.#hiddenField) {
|
||||
this.#hiddenField = this.#buildHiddenField()
|
||||
}
|
||||
return this.#hiddenField
|
||||
}
|
||||
|
||||
#buildHiddenField() {
|
||||
const [field] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
||||
this.element.appendChild(field)
|
||||
return field
|
||||
}
|
||||
|
||||
#updateWithDefaultClass() {
|
||||
if (this.hasWithDefaultClass && this.hasDefaultValueValue) {
|
||||
const selectedValue = this.#selectedItemValue()
|
||||
const shouldHaveClass = selectedValue === this.defaultValueValue
|
||||
|
||||
if (shouldHaveClass) {
|
||||
this.element.classList.add(this.withDefaultClass)
|
||||
} else {
|
||||
this.element.classList.remove(this.withDefaultClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { debounce } from "helpers/timing_helpers";
|
||||
|
||||
export default class extends Controller {
|
||||
static classes = ["filtersSet"]
|
||||
static targets = ["field"]
|
||||
|
||||
initialize() {
|
||||
this.debouncedChange = debounce(this.change.bind(this), 50)
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.change()
|
||||
}
|
||||
|
||||
change() {
|
||||
this.#toggleFiltersSetClass()
|
||||
}
|
||||
|
||||
async fieldTargetConnected(field) {
|
||||
this.debouncedChange()
|
||||
}
|
||||
|
||||
#toggleFiltersSetClass(shouldAdd) {
|
||||
this.element.classList.toggle(this.filtersSetClass, this.#hasFiltersSet)
|
||||
}
|
||||
|
||||
get #hasFiltersSet() {
|
||||
return this.fieldTargets.some(field => this.#isFieldSet(field))
|
||||
}
|
||||
|
||||
#isFieldSet(field) {
|
||||
const value = field.value?.trim()
|
||||
|
||||
if (!value) return false
|
||||
|
||||
const defaultValue = this.#defaultValueForField(field)
|
||||
return defaultValue ? value !== defaultValue : true
|
||||
}
|
||||
|
||||
#defaultValueForField(field) {
|
||||
const comboboxContainer = field.closest("[data-combobox-default-value-value]")
|
||||
return comboboxContainer?.dataset?.comboboxDefaultValueValue
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { toSentence } from "helpers/text_helpers"
|
||||
|
||||
export default class extends Controller {
|
||||
#hiddenField
|
||||
|
||||
static targets = [ "label", "item", "hiddenFieldTemplate" ]
|
||||
static values = {
|
||||
selectPropertyName: { type: String, default: "aria-checked" },
|
||||
defaultValue: String,
|
||||
noSelectionLabel: { type: String, default: "No selection" },
|
||||
labelPrefix: String
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.labelTarget.textContent = this.#selectedLabel
|
||||
this.#updateHiddenFields()
|
||||
}
|
||||
|
||||
change(event) {
|
||||
const item = event.target.closest("[role='checkbox']")
|
||||
if (item) {
|
||||
this.#toggleSelection(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
clear(event) {
|
||||
this.#deselectAll()
|
||||
this.#updateHiddenFields()
|
||||
this.labelTarget.textContent = this.#selectedLabel
|
||||
}
|
||||
|
||||
get #selectedLabel() {
|
||||
const selectedValues = this.#selectedValues()
|
||||
if (selectedValues.length === 0) {
|
||||
return this.noSelectionLabelValue
|
||||
}
|
||||
|
||||
const labels = this.#selectedItems().map(item => item.dataset.multiSelectionComboboxLabel)
|
||||
const sentence = toSentence(labels, {
|
||||
two_words_connector: " or ",
|
||||
last_word_connector: ", or "
|
||||
})
|
||||
|
||||
return this.hasLabelPrefixValue ? `${this.labelPrefixValue} ${sentence}` : sentence
|
||||
}
|
||||
|
||||
#toggleSelection(item) {
|
||||
const isSelected = item.getAttribute(this.selectPropertyNameValue) === "true"
|
||||
|
||||
if (isSelected) {
|
||||
item.setAttribute(this.selectPropertyNameValue, "false")
|
||||
} else {
|
||||
item.setAttribute(this.selectPropertyNameValue, "true")
|
||||
}
|
||||
|
||||
this.#updateHiddenFields()
|
||||
this.labelTarget.textContent = this.#selectedLabel
|
||||
}
|
||||
|
||||
#updateHiddenFields() {
|
||||
this.#clearHiddenFields()
|
||||
this.#addHiddenFields()
|
||||
}
|
||||
|
||||
#deselectAll() {
|
||||
this.itemTargets.forEach(item => {
|
||||
item.setAttribute(this.selectPropertyNameValue, "false")
|
||||
})
|
||||
}
|
||||
|
||||
#selectedItems() {
|
||||
return this.itemTargets.filter(item =>
|
||||
item.getAttribute(this.selectPropertyNameValue) === "true"
|
||||
)
|
||||
}
|
||||
|
||||
#selectedValues() {
|
||||
return this.#selectedItems().map(item => item.dataset.multiSelectionComboboxValue)
|
||||
}
|
||||
|
||||
#clearHiddenFields() {
|
||||
this.element.querySelectorAll('input[type="hidden"]').forEach(field => {
|
||||
if (field !== this.hiddenField) {
|
||||
field.remove()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#addHiddenFields() {
|
||||
this.#selectedValues().forEach(value => {
|
||||
const [field] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
||||
field.value = value
|
||||
this.element.appendChild(field)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,27 @@ export function normalizeFilteredText(string) {
|
||||
export function filterMatches(text, potentialMatch) {
|
||||
return normalizeFilteredText(text).includes(normalizeFilteredText(potentialMatch))
|
||||
}
|
||||
|
||||
export function toSentence(array, options = {}) {
|
||||
const defaultConnectors = {
|
||||
words_connector: ", ",
|
||||
two_words_connector: " and ",
|
||||
last_word_connector: ", and "
|
||||
}
|
||||
|
||||
const connectors = { ...defaultConnectors, ...options }
|
||||
|
||||
if (array.length === 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (array.length === 1) {
|
||||
return array[0]
|
||||
}
|
||||
|
||||
if (array.length === 2) {
|
||||
return array.join(connectors.two_words_connector)
|
||||
}
|
||||
|
||||
return array.slice(0, -1).join(connectors.words_connector) + connectors.last_word_connector + array[array.length - 1]
|
||||
}
|
||||
|
||||
@@ -41,10 +41,6 @@ class Card < ApplicationRecord
|
||||
|
||||
delegate :accessible_to?, to: :collection
|
||||
|
||||
def cache_key
|
||||
[ super, collection.name ].compact.join("/")
|
||||
end
|
||||
|
||||
def card
|
||||
self
|
||||
end
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
module Card::Cacheable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def cache_key
|
||||
[ super, collection.name ].compact.join("/")
|
||||
end
|
||||
|
||||
def cache_invalidation_parts
|
||||
@cache_invalidation_parts ||= InvalidationParts.new(self)
|
||||
end
|
||||
|
||||
@@ -9,15 +9,15 @@ class Cards::Columns
|
||||
end
|
||||
|
||||
def considering
|
||||
@considering ||= build_column(filter.with(engagement_status: "considering"))
|
||||
@considering ||= build_column_for "considering"
|
||||
end
|
||||
|
||||
def on_deck
|
||||
@on_deck ||= build_column(filter.with(engagement_status: "on_deck"))
|
||||
@on_deck ||= build_column_for "on_deck"
|
||||
end
|
||||
|
||||
def doing
|
||||
@doing ||= build_column(filter.with(engagement_status: "doing"))
|
||||
@doing ||= build_column_for "doing"
|
||||
end
|
||||
|
||||
def closed
|
||||
@@ -33,6 +33,10 @@ class Cards::Columns
|
||||
end
|
||||
|
||||
private
|
||||
def build_column_for(engagement_status)
|
||||
build_column(filter.with(engagement_status: engagement_status))
|
||||
end
|
||||
|
||||
def build_column(filter, &block)
|
||||
cards = block ? yield(filter.cards) : filter.cards
|
||||
|
||||
|
||||
@@ -21,4 +21,16 @@ module Filter::Resources
|
||||
def collections
|
||||
creator.collections.where id: super.ids
|
||||
end
|
||||
|
||||
def collection_titles
|
||||
if collections.none?
|
||||
[ Collection.one? ? collections.first.name : "All collections" ]
|
||||
else
|
||||
collections.map(&:name)
|
||||
end
|
||||
end
|
||||
|
||||
def collections_label
|
||||
collection_titles.to_sentence
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@ class User::Filtering
|
||||
|
||||
attr_reader :user, :filter, :expanded
|
||||
|
||||
delegate :as_params, :any?, :single_collection, to: :filter
|
||||
delegate :as_params, :single_collection, to: :filter
|
||||
delegate :only_closed?, to: :filter
|
||||
|
||||
def initialize(user, filter, expanded: false)
|
||||
@@ -15,15 +15,11 @@ class User::Filtering
|
||||
end
|
||||
|
||||
def selected_collection_titles
|
||||
if filter.collections.none?
|
||||
[ collections.one? ? collections.first.name : "All collections" ]
|
||||
else
|
||||
filter.collections.map(&:name)
|
||||
end
|
||||
filter.collection_titles
|
||||
end
|
||||
|
||||
def selected_collections_label
|
||||
selected_collection_titles.to_sentence
|
||||
filter.collections_label
|
||||
end
|
||||
|
||||
def tags
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<div id="filter-toggle">
|
||||
<% if filter.persisted? %>
|
||||
<%= button_to filter_path(filter), method: :delete, class: "btn txt-x-small btn--reversed", form_class: "inline" do %>
|
||||
<%= icon_tag "bookmark-outline" %>
|
||||
<span class="for-screen-reader">Remove saved filter</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% filter_params = filter.as_params.transform_values { |v| v.respond_to?(:to_str) ? v.to_str : v } %>
|
||||
<%= button_to filters_path, method: :post, params: filter_params, class: "btn txt-x-small", form_class: "inline" do %>
|
||||
<%= icon_tag "bookmark-outline" %>
|
||||
<span class="for-screen-reader">Save filter</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<% cache user_filtering do %>
|
||||
<%= 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? }),
|
||||
data: { controller: "toggle-class", toggle_class_toggle_class: "filters--expanded" } do %>
|
||||
data: { controller: "toggle-class filter-settings", toggle_class_toggle_class: "filters--expanded", filter_settings_filters_set_class: "filters--has-filters-set" } do %>
|
||||
<div class="flex-inline center align-center gap-half" data-controller="toggle-enable">
|
||||
<%= render "filters/settings/terms", user_filtering: user_filtering %>
|
||||
<%= render "filters/settings/controls", user_filtering: user_filtering %>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<%= turbo_stream.replace("filter-toggle", partial: "filters/filter_toggle", locals: { filter: @filter }) %>
|
||||
<%= turbo_stream.replace("my-filters", partial: "filters/menu/custom", locals: { filters: @filters }) %>
|
||||
@@ -0,0 +1,2 @@
|
||||
<%= turbo_stream.replace("filter-toggle", partial: "filters/filter_toggle", locals: { filter: @filter }) %>
|
||||
<%= turbo_stream.replace("my-filters", partial: "filters/menu/custom", locals: { filters: @filters }) %>
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= collapsible_nav_section "Saved filters" do %>
|
||||
<%= collapsible_nav_section "Saved filters", id: "my-filters" do %>
|
||||
<%= form_with url: cards_path, method: :get, data: { controller: "form" } do |form| %>
|
||||
<%= render "filters/menu/custom/create" %>
|
||||
<%= render partial: "filters/menu/custom/filter", collection: user_filtering.filters, as: :filter, locals: { user_filtering: user_filtering } %>
|
||||
<%= render partial: "filters/menu/custom/filter", collection: filters, as: :filter %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<%= icon_tag "bookmark", class: "popup__icon" %>
|
||||
<%= link_to cards_path(filter_id: filter.id), class: "popup__btn btn" do %>
|
||||
<div class="txt-tight-lines min-width txt-small overflow-ellipsis">
|
||||
<div><%= filter_selected_collections_title(user_filtering) %></div>
|
||||
<div><%= filter.collections_label %></div>
|
||||
<div><%= filter.summary %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,74 +1,47 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
<%= tag.div class: "quick-filter position-relative",
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_assignees? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<% if filter.assignment_status.unassigned? %>
|
||||
No one
|
||||
<% elsif filter.assignees.any? %>
|
||||
Assigned to <%= filter.assignees.map(&:familiar_name).to_sentence(two_words_connector: " or ", last_word_connector: ", or ") %>
|
||||
<% else %>
|
||||
Assigned to…
|
||||
<% end %>
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_assignees?,
|
||||
multi_selection_combobox_no_selection_label_value: "Assigned to…",
|
||||
multi_selection_combobox_label_prefix_value: "Assigned to" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-multi-selection-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-multi-selection-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag "assignee_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Assigned to…" do %>
|
||||
<strong class="popup__title">Assigned to…</strong>
|
||||
|
||||
<% if User.active.many? %>
|
||||
<%= text_field_tag :search, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
<%= text_field_tag nil, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:assignee_ids, :assignment_status).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: "unassigned", multi_selection_combobox_label: "No one" },
|
||||
role: "checkbox", aria: { checked: filter.assignment_status.unassigned? } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#clear form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow">No one</span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
|
||||
<% unless filter.assignment_status.unassigned? %>
|
||||
<%= hidden_field_tag :assignment_status, "unassigned" %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow">No one</span>
|
||||
<% if filter.assignment_status.unassigned? %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% user_filtering.users.each do |user| %>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: user.id, multi_selection_combobox_label: user.familiar_name },
|
||||
role: "checkbox", aria: { checked: filter.assignees.include?(user) } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
</li>
|
||||
<% User.active.order(:name).each do |user| %>
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:assignee_ids, :assignment_status).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<% filter.assignees.each do |existing_assignee| %>
|
||||
<% unless existing_assignee == user %>
|
||||
<%= hidden_field_tag "assignee_ids[]", existing_assignee.id %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% unless filter.assignees.include?(user) %>
|
||||
<%= hidden_field_tag "assignee_ids[]", user.id %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<% if filter.assignees.include?(user) %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -1,53 +1,39 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: "quick-filter position-relative",
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_closers? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<% if filter.closers.any? %>
|
||||
<%= "Closed by #{filter.closers.map(&:familiar_name).to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" %>
|
||||
<% else %>
|
||||
Closed by…
|
||||
<% end %>
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_closers?,
|
||||
multi_selection_combobox_no_selection_label_value: "Closed by…",
|
||||
multi_selection_combobox_label_prefix_value: "Closed by" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-multi-selection-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-multi-selection-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag "closer_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Closed by…" do %>
|
||||
<strong class="popup__title">Closed by…</strong>
|
||||
|
||||
<% if user_filtering.users.many? %>
|
||||
<%= text_field_tag :search, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
<%= text_field_tag nil, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% user_filtering.users.each do |user| %>
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:closer_ids).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<% filter.closers.each do |existing_closer| %>
|
||||
<% unless existing_closer == user %>
|
||||
<%= hidden_field_tag "closer_ids[]", existing_closer.id %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% unless filter.closers.include?(user) %>
|
||||
<%= hidden_field_tag "closer_ids[]", user.id %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<% if filter.closers.include?(user) %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: user.id, multi_selection_combobox_label: user.familiar_name },
|
||||
role: "checkbox", aria: { checked: filter.closers.include?(user) } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<%= 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 %>
|
||||
<%= form_with url: cards_path, method: :get, class: "flex-inline center align-center gap-half",
|
||||
data: { controller: "form", turbo_frame: "card_columns", turbo_action: "advance" } do |form| %>
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= 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,53 +1,39 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: "quick-filter position-relative",
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_creators? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<% if filter.creators.any? %>
|
||||
<%= "Added by #{filter.creators.map(&:familiar_name).to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" %>
|
||||
<% else %>
|
||||
Added by…
|
||||
<% end %>
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_creators?,
|
||||
multi_selection_combobox_no_selection_label_value: "Added by…",
|
||||
multi_selection_combobox_label_prefix_value: "Added by" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-multi-selection-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-multi-selection-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag "creator_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Added by…" do %>
|
||||
<strong class="popup__title">Added by…</strong>
|
||||
|
||||
<% if user_filtering.users.many? %>
|
||||
<%= text_field_tag :search, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
<%= text_field_tag nil, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% user_filtering.users.each do |user| %>
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:creator_ids).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<% filter.creators.each do |existing_creators| %>
|
||||
<% unless existing_creators == user %>
|
||||
<%= hidden_field_tag "creator_ids[]", existing_creators.id %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% unless filter.creators.include?(user) %>
|
||||
<%= hidden_field_tag "creator_ids[]", user.id %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<% if filter.creators.include?(user) %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: user.id, multi_selection_combobox_label: user.familiar_name },
|
||||
role: "checkbox", aria: { checked: filter.creators.include?(user) } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= user.name %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: class_names("quick-filter position-relative", "default-value": filter.indexed_by.all?),
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_indexed_by? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<%= filter.indexed_by == "all" ? "Status" : filter.indexed_by.humanize %>
|
||||
<%= tag.div class: class_names("quick-filter position-relative"),
|
||||
data: { controller: "dialog combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_indexed_by?,
|
||||
turbo_action: "advance",
|
||||
combobox_default_value_value: "all",
|
||||
combobox_default_label_value: "Status",
|
||||
combobox_with_default_class: "quick-filter--with-default" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag :indexed_by, nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Filter by…" do %>
|
||||
<strong class="popup__title">Filter by…</strong>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% Filter::INDEXES.each do |index| %>
|
||||
<li class="popup__item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:indexed_by).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :indexed_by, index %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= index.humanize %></span>
|
||||
<% if filter.indexed_by == index %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<%= tag.li class: "popup__item", data: { navigable_list_target: "item", combobox_target: "item", combobox_value: index, combobox_label: index.humanize }, role: "checkbox", aria: { checked: filter.indexed_by == index } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= index == "all" ? "Status" : index.humanize %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<% if user_filtering.any? %>
|
||||
<% if filter.persisted? %>
|
||||
<%= button_to filter_path(filter), method: :delete, class: "btn txt-x-small btn--reversed", form_class: "inline" do %>
|
||||
<%= icon_tag "bookmark-outline" %>
|
||||
<span class="for-screen-reader">Remove saved filter</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% filter_params = filter.as_params.transform_values { |v| v.respond_to?(:to_str) ? v.to_str : v } %>
|
||||
<%= button_to filters_path, method: :post, params: filter_params, class: "btn txt-x-small", form_class: "inline" do %>
|
||||
<%= icon_tag "bookmark-outline" %>
|
||||
<span class="for-screen-reader">Save filter</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div class="filters__manage center align-center gap-half">
|
||||
<%= 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 %>
|
||||
<%= icon_tag "close" %>
|
||||
<span class="for-screen-reader">Clear all</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: class_names("quick-filter position-relative", "default-value": filter.sorted_by.latest?),
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_sorted_by? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<%= sorted_by_label(filter.sorted_by) %>
|
||||
<%= tag.div class: class_names("quick-filter position-relative"),
|
||||
data: {
|
||||
controller: "dialog combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_sorted_by?,
|
||||
turbo_action: "advance",
|
||||
combobox_default_value_value: "latest",
|
||||
combobox_with_default_class: "quick-filter--with-default" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag :sorted_by, nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Sort by…" do %>
|
||||
<strong class="popup__title">Sort by…</strong>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% Filter::SORTED_BY.each do |sort| %>
|
||||
<li class="popup__item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:sorted_by).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :sorted_by, sort %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= sorted_by_label(sort) %></span>
|
||||
<% if filter.sorted_by == sort %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
navigable_list_target: "item", combobox_target: "item", combobox_value: sort, combobox_label: sorted_by_label(sort) },
|
||||
role: "checkbox", aria: { checked: filter.sorted_by == sort } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= sorted_by_label(sort) %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,53 +1,38 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: "quick-filter position-relative",
|
||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_tags? } do %>
|
||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
<% if filter.tags.any? %>
|
||||
<%= filter.tags.map(&:hashtag).to_sentence(two_words_connector: " or ", last_word_connector: ", or ") %>
|
||||
<% else %>
|
||||
Tagged…
|
||||
<% end %>
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_tags?,
|
||||
multi_selection_combobox_no_selection_label_value: "Tagged…" } do %>
|
||||
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||
<span class="overflow-ellipsis" data-multi-selection-combobox-target="label">
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template data-multi-selection-combobox-target="hiddenFieldTemplate">
|
||||
<%= hidden_field_tag "tag_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Tagged…" do %>
|
||||
<strong class="popup__title">Tagged…</strong>
|
||||
|
||||
<% if user_filtering.tags.many? %>
|
||||
<%= text_field_tag :search, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
<%= text_field_tag nil, nil, placeholder: "Filter…", class: "input input--transparent txt-small", autofocus: true,
|
||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||
<% end %>
|
||||
|
||||
<ul class="popup__list" data-filter-target="list">
|
||||
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||
<% user_filtering.tags.each do |tag| %>
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
||||
<% filter.as_params.except(:tag_ids).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<% filter.tags.each do |existing_tag| %>
|
||||
<% unless existing_tag == tag %>
|
||||
<%= hidden_field_tag "tag_ids[]", existing_tag.id %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% unless filter.tags.include?(tag) %>
|
||||
<%= hidden_field_tag "tag_ids[]", tag.id %>
|
||||
<% end %>
|
||||
|
||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||
|
||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= tag.hashtag %></span>
|
||||
<% if filter.tags.include?(tag) %>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</li>
|
||||
<%= content_tag(:li, class: "popup__item", data: {
|
||||
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: tag.id, multi_selection_combobox_label: tag.hashtag },
|
||||
role: "checkbox", aria: { checked: filter.tags.include?(tag) }) do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change form#submit filter-settings#change">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= tag.hashtag %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= form_with url: cards_path, method: :get, class: "", data: { controller: "form", turbo_frame: "card_columns", action: "input->form#debouncedSubmit" } do |form| %>
|
||||
<% filter.as_params.except(:terms).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
@@ -13,7 +14,9 @@
|
||||
<% 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: "keydown.enter->form#submitToTopTarget" } %>
|
||||
autofocus: false, autocomplete: :off, autocorrect: "off", data: {
|
||||
"1p-ignore": "true",
|
||||
action: "input->form#debouncedSubmit keydown.enter->form#submitToTopTarget" } %>
|
||||
<% end %>
|
||||
|
||||
<% if filter.terms.present? %>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
|
||||
<%= render "filters/menu/hotkeys" %>
|
||||
<%= render "filters/menu/custom", user_filtering: @user_filtering %>
|
||||
<%= render "filters/menu/custom", filters: @user_filtering.filters %>
|
||||
<%= render "filters/menu/collections", user_filtering: @user_filtering %>
|
||||
<%= render "filters/menu/tags", user_filtering: @user_filtering %>
|
||||
<%= render "filters/menu/users", user_filtering: @user_filtering %>
|
||||
|
||||
@@ -12,9 +12,9 @@ class FiltersControllerTest < ActionDispatch::IntegrationTest
|
||||
assignment_status: "unassigned",
|
||||
tag_ids: [ tags(:mobile).id ],
|
||||
assignee_ids: [ users(:jz).id ],
|
||||
collection_ids: [ collections(:writebook).id ] }
|
||||
collection_ids: [ collections(:writebook).id ] }, as: :turbo_stream
|
||||
end
|
||||
assert_redirected_to cards_path(filter_id: Filter.last.id)
|
||||
assert_response :success
|
||||
|
||||
filter = Filter.last
|
||||
assert_predicate filter.indexed_by, :closed?
|
||||
@@ -29,8 +29,8 @@ class FiltersControllerTest < ActionDispatch::IntegrationTest
|
||||
expected_params = filter.as_params
|
||||
|
||||
assert_difference "users(:david).filters.count", -1 do
|
||||
delete filter_path(filter)
|
||||
delete filter_path(filter), as: :turbo_stream
|
||||
end
|
||||
assert_redirected_to cards_path(expected_params)
|
||||
assert_response :success
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user