implementar el buscador en el panel

ahora el índice de artículos incorporar buscador de texto libre.

además todos los filtros de búsqueda se mantienen entre búsquedas,
entonces al filtrar por tipo de artículo y término, se aplican ambos y
al cambiar el tipo se mantiene la búsqueda de texto.
This commit is contained in:
f 2021-05-07 16:17:25 -03:00
parent 34a05e860d
commit ad871baca6
8 changed files with 82 additions and 68 deletions

View file

@ -21,6 +21,10 @@ $form-feedback-invalid-color: $magenta;
$form-feedback-icon-valid-color: $black;
$component-active-bg: $magenta;
$spacers: (
2-plus: 0.75rem
);
@import "bootstrap";
@import "editor";

View file

@ -16,29 +16,25 @@ class PostsController < ApplicationController
authorize Post
@site = find_site
@category = params.dig(:category)
@layout = params.dig(:layout)
@locale = locale
@q = params[:q]
dictionary = IndexedPost.to_dictionary(locale: locale)
# XXX: Cada vez que cambiamos un Post tocamos el sitio con lo que es
# más simple saber si hubo cambios.
if @category || @layout || stale?(@site)
@posts = @site.posts(lang: locale)
@posts = @posts.where(categories: @category) if @category
@posts = @posts.where(layout: @layout) if @layout
if filter_params.present? || stale?(@site)
# Todos los artículos de este sitio para el idioma actual
@posts = @site.indexed_posts.where(locale: dictionary)
# De este tipo
@posts = @posts.where(layout: filter_params[:layout]) if filter_params[:layout]
# Que estén dentro de la categoría
@posts = @posts.in_category(filter_params[:category]) if filter_params[:category]
# Aplicar los parámetros de búsqueda
@posts = @posts.search(locale, filter_params[:q]) if filter_params[:q].present?
# A los que este usuarie tiene acceso
@posts = PostPolicy::Scope.new(current_usuarie, @posts).resolve
@category_name = if uuid?(@category)
@site.posts(lang: locale).find(@category, uuid: true)&.title&.value
else
@category
end
# Filtrar los posts que les invitades no pueden ver
@usuarie = @site.usuarie? current_usuarie
# Orden descendiente por número y luego por fecha
@posts.sort_by!(:order, :date).reverse!
end
end
@ -169,4 +165,14 @@ class PostsController < ApplicationController
def forget_content
flash[:js] = { target: 'editor', action: 'forget-content', keys: (params[:storage_keys] || []).to_json }
end
private
# Los parámetros de filtros que vamos a mantener en todas las URLs,
# solo los que no estén vacíos.
#
# @return [Hash]
def filter_params
@filter_params ||= params.permit(:q, :category, :layout).to_h.select { |_,v| v.present? }
end
end

View file

@ -28,6 +28,8 @@ class IndexedPost < ApplicationRecord
# Trae los IndexedPost en el orden en que van a terminar en el sitio.
default_scope lambda { order(order: :desc, created_at: :desc) }
scope :in_category, lambda { |category| where("front_matter->'categories' ? :category", category: category.to_s) }
scope :by_usuarie, lambda { |usuarie| where("front_matter->'usuaries' @> :usuarie::jsonb", usuarie: usuarie.to_s) }
belongs_to :site

View file

@ -11,7 +11,7 @@ class Post
# Devuelve una versión indexable del Post
#
# @return [IndexedPosts]
# @return [IndexedPost]
def to_index
IndexedPost.find_or_create_by(id: uuid.value).tap do |indexed_post|
indexed_post.layout = layout.name
@ -41,9 +41,16 @@ class Post
#
# @return [Hash]
def indexable_front_matter
return {} unless attribute? :categories
{}.tap do |indexable_front_matter|
indexable_front_matter = {
usuaries: usuaries.map(&:id),
draft: attribute?(:draft) ? draft.value : false
}
{ categories: categories.indexable_values }
if attribute? :categories
indexable_front_matter[:categories] = categories.indexable_values
end
end
end
# Devuelve un documento indexable en texto plano

View file

@ -59,9 +59,7 @@ class PostPolicy
def resolve
return scope if scope&.first&.site&.usuarie? usuarie
scope.select do |post|
post.usuaries.include? usuarie
end
scope.by_usuarie(usuarie.id)
end
end
end

View file

@ -3,7 +3,7 @@
@site.name,
link_to(t('posts.index'),
site_posts_path(@site)),
@category_name]
@category]
%main.row
%aside.menu.col-md-3
@ -14,15 +14,13 @@
%table.mb-3
- @site.layouts.each do |layout|
- next if layout.hidden?
- filter = params[:layout] == layout.value
%tr
%th= layout.humanized_name
%td.pl-3= link_to t('posts.add'),
new_site_post_path(@site, layout: layout.name),
class: 'badge badge-secondary'
%td= link_to t(filter ? 'posts.remove_filter' : 'posts.filter'),
site_posts_path(@site, layout: (filter ? nil : layout.value)),
class: 'badge badge-' + (filter ? 'primary' : 'secondary')
%td.pl-3= link_to t('posts.add'), new_site_post_path(@site, **@filter_params), class: 'badge badge-secondary'
- if @filter_params[:layout] == layout.value
%td= link_to t('posts.remove_filter'), site_posts_path(@site, **@filter_params.merge(layout: nil)), class: 'badge badge-primary'
- else
%td= link_to t('posts.filter'), site_posts_path(@site, **@filter_params.merge(layout: layout.value)), class: 'badge badge-secondary'
- if policy(@site).edit?
= link_to t('sites.edit.btn', site: @site.title), edit_site_path(@site), class: 'btn'
@ -48,19 +46,24 @@
%section.col
= render 'layouts/flash'
.d-flex.justify-content-between.align-items-center.pl-2-plus.pr-2-plus.mb-2
%form
- @filter_params.each do |param, value|
- next if param == 'q'
%input{ type: 'input', name: param, value: value }
.form-group.flex-grow-0.m-0
%input.form-control.border.border-magenta{ type: 'search', placeholder: 'Buscar', name: 'q', value: @q }
%input.sr-only{ type: 'submit' }
- if @site.locales.size > 1
%nav#locales
- @site.locales.each do |locale|
= link_to t("locales.#{locale}.name"), site_posts_path(@site, **@filter_params.merge(locale: locale)),
class: "mr-2 mt-2 mb-2 #{locale == @locale ? 'active font-weight-bold' : ''}"
- if @posts.empty?
%h2= t('posts.none')
%h2= t('posts.empty')
- else
= form_tag site_posts_reorder_path, method: :post do
.d-flex.justify-content-between.align-items-center
-#
TODO: Pensar una interfaz mejor para cuando haya más de tres
idiomas
- unless @site.locales.length == 1
.locales
- @site.locales.each do |locale|
= link_to t("locales.#{locale}.name"), site_posts_path(@site, locale: locale),
class: "mr-2 mt-2 mb-2#{locale == @locale ? 'active font-weight-bold' : ''}"
%table.table{ data: { controller: 'reorder' } }
%caption.sr-only= t('posts.caption')
%thead
@ -76,6 +79,7 @@
%button.btn{ data: { action: 'reorder#bottom' } }= t('posts.reorder.bottom')
%tbody
- dir = t("locales.#{@locale}.dir")
- size = @posts.size
- @posts.each_with_index do |post, i|
-#
TODO: Solo les usuaries cachean porque tenemos que separar
@ -84,45 +88,36 @@
TODO: Verificar qué pasa cuando se gestiona el sitio en
distintos idiomas a la vez
- cache_if @usuarie, post do
- checkbox_id = "checkbox-#{post.uuid.value}"
%tr{ id: post.uuid.value, data: { target: 'reorder.row' } }
- checkbox_id = "checkbox-#{post.id}"
%tr{ id: post.id, data: { target: 'reorder.row' } }
%td
.custom-control.custom-checkbox
%input.custom-control-input{ id: checkbox_id, type: 'checkbox', autocomplete: 'off', data: { action: 'reorder#select' } }
%label.custom-control-label{ for: checkbox_id }
%span.sr-only= t('posts.reorder.select')
-# Orden más alto es mayor prioridad
= hidden_field 'post[reorder]', post.uuid.value,
value: @posts.length - i,
= hidden_field 'post[reorder]', post.id,
value: size - i,
data: { reorder: true }
%td.w-100{ class: dir }
= link_to site_post_path(@site, post.id) do
%span{ lang: post.lang.value, dir: dir }= post.title.value
- if post.attributes.include? :draft
- if post.draft.value
%span.badge.badge-primary
= post_label_t(:draft, post: post)
- if post.attributes.include? :categories
- unless post.categories.value.empty?
%br
%small
- (post.categories.respond_to?(:belongs_to) ? post.categories.belongs_to : post.categories.value).each do |c|
= link_to site_posts_path(@site, category: (c.respond_to?(:uuid) ? c.uuid.value : c)) do
%span{ lang: post.lang.value, dir: dir }= (c.respond_to?(:title) ? c.title.value : c)
= link_to site_post_path(@site, post.path) do
%span{ lang: post.locale, dir: dir }= post.title
- if post.front_matter['draft'].present?
%span.badge.badge-primary
= post_label_t(:draft, post: post)
- if post.front_matter['categories'].present?
%br
%small
- post.front_matter['categories'].each do |category|
= link_to site_posts_path(@site, **@filter_params.merge(category: category)) do
%span{ lang: post.locale, dir: dir }= category
%td
= post.date.value.strftime('%F')
= post.created_at.strftime('%F')
%br/
- if post.attribute? :order
= post.order.value
= post.order
%td
- if @usuarie || policy(post).edit?
= link_to t('posts.edit'),
edit_site_post_path(@site, post.id),
class: 'btn btn-block'
= link_to t('posts.edit'), edit_site_post_path(@site, post.path), class: 'btn btn-block'
- if @usuarie || policy(post).destroy?
= link_to t('posts.destroy'),
site_post_path(@site, post.id),
class: 'btn btn-block',
method: :delete,
data: { confirm: t('posts.confirm_destroy') }
= link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-block', method: :delete, data: { confirm: t('posts.confirm_destroy') }

View file

@ -397,6 +397,7 @@ en:
en: 'English'
ar: 'Arabic'
posts:
empty: "There are no results for those search parameters."
attribute_ro:
file:
download: Download file

View file

@ -459,6 +459,7 @@ es:
en: 'inglés'
ar: 'árabe'
posts:
empty: No hay artículos con estos parámetros de búsqueda.
caption: Lista de artículos
attribute_ro:
file: