Merge pull request #1210 from basecamp/collections-filter
Collections filtering
This commit is contained in:
@@ -1 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3 5h8v2h-8zm10 0h8v2h-8zm-10 4h8v2h-8zm10 0h8v2h-8zm-10 4h8v2h-8zm10 0h8v2h-8zm-10 4h8v2h-8z"/></svg>
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.8 0h-19.6c-1.2 0-2.2 1-2.2 2.2v19.5c0 1.2 1 2.2 2.2 2.2h19.5c1.2 0 2.2-1 2.2-2.2v-19.5c0-1.2-1-2.2-2.2-2.2zm-10.8 19h-8v-2h8zm0-4h-8v-2h8zm0-4h-8v-2h8zm0-4h-8v-2h8zm10 8h-8v-2h8zm0-4h-8v-2h8zm0-4h-8v-2h8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 171 B After Width: | Height: | Size: 286 B |
@@ -97,6 +97,17 @@
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.events__filter-select {
|
||||
font-weight: inherit;
|
||||
text-decoration: underline;
|
||||
|
||||
@media (any-hover: hover) {
|
||||
&:hover {
|
||||
--btn-color: var(--color-link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.events__day {
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ module PaginationHelper
|
||||
|
||||
def day_timeline_pagination_link(day_timeline, filter)
|
||||
if day_timeline.next_day
|
||||
link_to "Load more...", events_days_path(day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
|
||||
data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" }
|
||||
link_to "Load more…", events_days_path(day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
|
||||
class: "txt-reversed", data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { post } from "@rails/request.js"
|
||||
export default class extends Controller {
|
||||
static classes = ["filtersSet"]
|
||||
static targets = ["field", "form"]
|
||||
static values = { refreshUrl: String, noFilteringUrl: String }
|
||||
static values = { refreshUrl: String, noFilteringUrl: String, cardsUrl: String }
|
||||
|
||||
initialize() {
|
||||
this.debouncedToggle = debounce(this.#toggle.bind(this), 50)
|
||||
@@ -31,6 +31,12 @@ export default class extends Controller {
|
||||
this.debouncedToggle()
|
||||
}
|
||||
|
||||
submitToGenericCardsView() {
|
||||
this.formTarget.action = this.cardsUrlValue
|
||||
this.formTarget.dataset.turboFrame = "top"
|
||||
this.formTarget.requestSubmit()
|
||||
}
|
||||
|
||||
#toggle() {
|
||||
this.element.classList.toggle(this.filtersSetClass, this.#hasFiltersSet)
|
||||
}
|
||||
|
||||
@@ -82,15 +82,14 @@ export default class extends Controller {
|
||||
|
||||
#clearHiddenFields() {
|
||||
this.element.querySelectorAll('input[type="hidden"]').forEach(field => {
|
||||
if (field !== this.hiddenField) {
|
||||
field.remove()
|
||||
}
|
||||
field.remove()
|
||||
})
|
||||
}
|
||||
|
||||
#addHiddenFields() {
|
||||
this.#selectedValues().forEach(value => {
|
||||
const [field] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
||||
const [ field ] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
||||
field.removeAttribute("id")
|
||||
field.value = value
|
||||
this.element.appendChild(field)
|
||||
})
|
||||
|
||||
@@ -22,7 +22,6 @@ class Card < ApplicationRecord
|
||||
case index
|
||||
when "stalled" then stalled
|
||||
when "postponing_soon" then postponing_soon
|
||||
when "falling_back_soon" then falling_back_soon
|
||||
when "closed" then closed.recently_closed_first
|
||||
when "golden" then golden
|
||||
when "draft" then drafted
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module Filter::Fields
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
INDEXES = %w[ all stalled postponing_soon falling_back_soon golden draft ]
|
||||
INDEXES = %w[ all stalled postponing_soon golden draft ]
|
||||
SORTED_BY = %w[ newest oldest latest ]
|
||||
|
||||
delegate :default_value?, to: :class
|
||||
|
||||
@@ -67,6 +67,10 @@ class User::Filtering
|
||||
filter.closers.any?
|
||||
end
|
||||
|
||||
def show_collections?
|
||||
filter.collections.any?
|
||||
end
|
||||
|
||||
def enable_collection_filtering(&block)
|
||||
@collection_filtering_route_resolver = block
|
||||
end
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<%= link_to event.notifiable_target,
|
||||
class: "event event--#{ event.action } #{ "golden-effect" if event.card.golden? } center-block flex flex-column full-width align-start justify-start position-relative",
|
||||
style: "--card-color: #{ card.closed? ? "var(--color-card-complete)" : card.color };", target: "_top",
|
||||
data: { related_element_target: "related",
|
||||
related_element_group_value: card.id,
|
||||
action: "mouseover->related-element#highlight mouseout->related-element#unhighlight" } do %>
|
||||
style: "--card-color: #{ card.closed? ? "var(--color-card-complete)" : card.color };",
|
||||
target: "_top",
|
||||
data: {
|
||||
related_element_target: "related",
|
||||
related_element_group_value: card.id,
|
||||
action: "mouseover->related-element#highlight mouseout->related-element#unhighlight" } do %>
|
||||
<div class="card__header flex align-start gap full-width">
|
||||
<h4 class="card__collection flex-inline align-start">
|
||||
<span class="card__id"><%= card.id %></span>
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
<%= render "filters/menu", user_filtering: @user_filtering %>
|
||||
<%= render "events/index/add_card_button", user_filtering: @user_filtering %>
|
||||
|
||||
<h1 class="header__title overflow-ellipsis">
|
||||
<div class="overflow-ellipsis">
|
||||
Activity in <%= @user_filtering.selected_collections_label %>
|
||||
</div>
|
||||
<h1 class="header__title">
|
||||
<span>Activity in</span>
|
||||
<%= render "events/index/filter", user_filtering: @user_filtering %>
|
||||
</h1>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= form_with url: events_path,
|
||||
method: :get, class: "flex-inline position-relative",
|
||||
data: { controller: "form", turbo_frame: "cards_container", turbo_action: "advance" } do |form| %>
|
||||
<%= tag.div class: "flex-inline position-relative quick-filter",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_collections?,
|
||||
multi_selection_combobox_no_selection_label_value: user_filtering.selected_collections_label } do %>
|
||||
<button type="button" class="btn borderless btn--plain events__filter-select" 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 "collection_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Collection…" do %>
|
||||
<strong class="popup__title">Collection…</strong>
|
||||
|
||||
<% if user_filtering.collections.many? %>
|
||||
<%= text_field_tag nil, nil, placeholder: "Filter…", class: "input input--transparent txt-small font-weight-normal", 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" role="listbox">
|
||||
<% user_filtering.collections.each do |collection| %>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
filter_target: "item", navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: collection.id, multi_selection_combobox_label: collection.name },
|
||||
role: "checkbox", aria: { checked: filter.collections.include?(collection) } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change filter-settings#change form#submit">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= collection.name %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -6,8 +6,9 @@
|
||||
toggle_class_toggle_class: "filters--expanded",
|
||||
filter_settings_filters_set_class: "filters--has-filters-set",
|
||||
filter_settings_no_filtering_url_value: no_filtering_url,
|
||||
turbo_permanent: true,
|
||||
filter_settings_refresh_url_value: settings_refresh_path } do %>
|
||||
filter_settings_refresh_url_value: settings_refresh_path,
|
||||
filter_settings_cards_url_value: cards_path,
|
||||
turbo_permanent: true } do %>
|
||||
<%= form_with url: filter_url, method: :get, class: "", data: {
|
||||
controller: "form",
|
||||
turbo_frame: "cards_container",
|
||||
@@ -15,9 +16,6 @@
|
||||
action: "turbo:submit-end->filter-settings#resetIfNoFiltering",
|
||||
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 %>
|
||||
|
||||
<%= yield form if block_given? %>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% if platform.desktop? %>
|
||||
<footer class="popup__footer">
|
||||
Press <kbd class="kbd">J</kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close, <kbd class="kbd">↑</kbd><kbd class="kbd">↓</kbd> to move, <kbd class="kbd">enter</kbd> to navigate, <kbd class="kbd">SHIFT+ENTER</kbd> to select.
|
||||
Press <kbd class="kbd">J</kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close, <kbd class="kbd">↑</kbd><kbd class="kbd">↓</kbd> to move, <kbd class="kbd">enter</kbd> to navigate.
|
||||
</footer>
|
||||
<% end %>
|
||||
|
||||
@@ -2,15 +2,8 @@
|
||||
|
||||
<% if Current.user.collections.many? %>
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item" id="filter-collection-all">
|
||||
<%= link_to clear_url_path, class: "popup__radio btn" do %>
|
||||
<%= check_box_tag "filter_collections", nil, user_filtering.collections.blank?, class: "form-checkbox" %>
|
||||
<span class="for-screen-reader">
|
||||
See everything in all collections
|
||||
</span>
|
||||
<%= icon_tag "check", size: 18, class: "checked" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to clear_url_path, class: "popup__btn btn" do %>
|
||||
<%= icon_tag "collection", class: "popup__icon" %>
|
||||
<%= link_to cards_path, class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis">All collections</span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item" id="filter-collection-<%= collection.id %>">
|
||||
<label class="popup__radio btn">
|
||||
<%= form.check_box "collection_ids[]", {
|
||||
checked: user_filtering.filter.collections.include?(collection),
|
||||
data: { action: "change->form#submit" },
|
||||
include_hidden: false,
|
||||
}, collection.id %>
|
||||
|
||||
<span class="for-screen-reader">
|
||||
Toggle filter for <%= collection.name %>
|
||||
</span>
|
||||
<%= icon_tag "check", size: 18, class: "checked" %>
|
||||
</label>
|
||||
|
||||
<%= icon_tag "collection", class: "popup__icon" %>
|
||||
<%= link_to collection_path(collection), class: "popup__btn btn" do %>
|
||||
<span class="overflow-ellipsis"><%= collection.name %></span>
|
||||
<% end %>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<%= 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.collections_label %></div>
|
||||
<div><%= filter.summary %></div>
|
||||
<div><strong><%= filter.collections_label %></strong></div>
|
||||
<div class="txt-capitalize"><%= filter.summary %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<% filter = user_filtering.filter %>
|
||||
|
||||
<%= tag.div class: "quick-filter position-relative",
|
||||
data: {
|
||||
controller: "dialog multi-selection-combobox",
|
||||
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||
filter_show: user_filtering.show_collections?,
|
||||
multi_selection_combobox_no_selection_label_value: "Collection…",
|
||||
multi_selection_combobox_label_prefix_value: "" } 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 "collection_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||
</template>
|
||||
|
||||
<%= filter_dialog "Collection…" do %>
|
||||
<strong class="popup__title">Collection…</strong>
|
||||
|
||||
<% if user_filtering.collections.many? %>
|
||||
<%= 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" role="listbox">
|
||||
<% user_filtering.collections.each do |collection| %>
|
||||
<%= tag.li class: "popup__item", data: {
|
||||
filter_target: "item", navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: collection.id, multi_selection_combobox_label: collection.name },
|
||||
role: "checkbox", aria: { checked: filter.collections.include?(collection) } do %>
|
||||
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change filter-settings#change filter-settings#submitToGenericCardsView:stop">
|
||||
<span class="overflow-ellipsis flex-item-grow"><%= collection.name %></span>
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -1,3 +1,4 @@
|
||||
<%= render "filters/settings/collections", 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 %>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<%= render "events/day", day_timeline: day_timeline %>
|
||||
|
||||
<% if day_timeline.next_day %>
|
||||
<%= link_to "Load more...", user_path(user, day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
|
||||
data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" } %>
|
||||
<%= link_to "Load more…", user_path(user, day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
|
||||
class: "txt-reversed", data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" } %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user