5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 20:26:22 +00:00

feat: pertenece a

This commit is contained in:
f 2024-05-27 15:15:55 -03:00
parent 105b2a1f1c
commit c150acbd6f
No known key found for this signature in database
8 changed files with 116 additions and 2 deletions

View file

@ -126,7 +126,7 @@ class PostsController < ApplicationController
@uuid = @post.uuid.value
@name = params.require(:name)
render 'posts/new_has_many_value', layout: false
render "posts/#{params.require(:attribute)}_value", layout: false
else
headers['HX-Retarget'] = "##{params.require(:form)}"
headers['HX-Reswap'] = 'outerHTML'

View file

@ -0,0 +1,4 @@
# frozen_string_literal: true
# Nueva interfaz
class MetadataNewBelongsTo < MetadataBelongsTo; end

View file

@ -3,7 +3,7 @@
checkbox_attributes = local_assigns.slice(:id, :type, :name, :value, :required, :checked)
checkbox_attributes[:type] ||= 'checkbox'
.custom-control.custom-checkbox
.custom-control{ class: "custom-#{checkbox_attributes[:type]}" }
%input.custom-control-input{ **checkbox_attributes }
%label.custom-control-label{ for: id, aria: { describedby: help_id } }= content
- if (block = yield).present?

View file

@ -58,6 +58,7 @@
%input{ type: 'hidden', name: 'form', value: options[:id] }
%input{ type: 'hidden', name: 'dir', value: dir }
%input{ type: 'hidden', name: 'locale', value: locale }
%input{ type: 'hidden', name: 'attribute', value: params.require(:attribute) }
%input{ type: 'hidden', name: 'target', value: params.require(:target) }
%input{ type: 'hidden', name: 'swap', value: params.require(:swap) }
- if params[:inverse].present?

View file

@ -0,0 +1,6 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td{ dir: dir, lang: locale }
- p = metadata.belongs_to
- if p
= link_to p.title.value, site_post_path(site, p.id)

View file

@ -0,0 +1,100 @@
-#
Genera un listado de radios entre los que se puede elegir solo uno para
guardar. Podemos elegir entre los artículos ya cargados o agregar uno
nuevo.
Al agregar uno nuevo, se abre un segundo modal que carga el formulario
correspondiente vía HTMX. El formulario tiene que cargarse por fuera
del formulario principal porque no se pueden anidar.
:ruby
id = id_for(base, attribute)
name = "#{base}[#{attribute}]"
form_id = "form-#{Nanoid.generate}"
modal_id = "modal-#{Nanoid.generate}"
post_id = "post-#{Nanoid.generate}"
post_form_id = "post-form-#{Nanoid.generate}"
post_modal_id = "post-modal-#{Nanoid.generate}"
post_form_loaded_id = "post-loaded-#{Nanoid.generate}"
value_list_id = "#{id}_body"
%div{ id: modal_id, data: { controller: 'modal array', 'array-original-value': metadata.value.to_json, 'array-new-array-value': site_posts_new_related_post_path(site) } }
.form-group
= hidden_field_tag name, ''
= label_tag id, post_label_t(attribute, post: post)
-# Mostramos la lista de valores actuales.
Al aceptar el modal, se vacía el listado y se completa en base a
renderizaciones con HTMX. Para poder hacer eso, tenemos que poder
acceder a todos los items dentro del modal (como array.item) y
enviar el valor al endpoint que devuelve uno por uno. Esto lo
tenemos disponible en Stimulus, pero queremos usar HTMX o técnica
similar para poder renderizar del lado del servidor.
Para poder cancelar, mantenemos el estado original y desactivamos
o activamos los ítemes según estén incluidos en esa lista o no.
.row.row-cols-3.row-cols-md-4{ data: { target: 'array.current' } }
- metadata.values.slice(*metadata.value).each do |value|
= render 'posts/new_array_value', value: value
= render 'bootstrap/btn', content: t('.edit'), action: 'modal#show'
= render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do
- content_for :"#{id}_header" do
.form-group.flex-grow-1.mb-0
= label_tag id, post_label_t(attribute, post: post)
%input.form-control{ data: { target: 'array.search', action: 'input->array#search' }, type: 'search', placeholder: t('.filter') }
- content_for :"#{id}_body" do
.form-group.mb-0{ id: value_list_id }
- metadata.values.each_pair do |value, uuid|
.mb-2{ data: { target: 'array.item', 'searchable-value': value.remove_diacritics.downcase, value: uuid } }
= render 'bootstrap/custom_checkbox', name: name, id: "value-#{Nanoid.generate}", value: uuid, checked: metadata.value.include?(uuid), content: value, type: 'radio'
-#
Según la definición del campo, si hay un filtro, tenemos que poder
elegir qué tipo de esquema queremos o si hay uno solo, siempre
vamos a enviar ese. Si no hay ninguno, tendríamos que poder elegir
entre todos los esquemas.
- content_for :"#{id}_footer" do
- layout = metadata.filter[:layout]
- if layout.is_a?(String)
%input{ type: 'hidden', name: 'layout', value: layout, form: post_form_id }
= render 'bootstrap/btn', content: t('.add', layout: site.layouts[layout].humanized_name), form: post_form_id, type: 'submit', class: 'm-0 mr-1'
- else
- layouts = layout&.map { |x| site.layouts[x] }
- layouts ||= site.layouts.values
.input-group.w-auto.flex-grow-1.my-0
%select.form-control{ form: post_form_id, name: 'layout' }
- layouts.each do |layout|
%option{ value: layout.name }= layout.humanized_name
.input-group-append
= render 'bootstrap/btn', content: t('.add', layout: ''), form: post_form_id, type: 'submit', class: 'mb-0 mr-0'
= render 'bootstrap/btn', content: t('.accept'), action: 'array#accept modal#hide', class: 'm-0 mr-1'
= render 'bootstrap/btn', content: t('.cancel'), action: 'array#cancel modal#hide', class: 'm-0'
-#
Este segundo modal es el que carga los formularios de
creación/modificación de artículos relacionados. Se envía a post_form
para que sea externo al formulario actual.
- content_for :post_form do
%form{ id: post_form_id, 'hx-get': site_posts_form_path(site), 'hx-target': "##{post_form_loaded_id}" }
%input{ type: 'hidden', name: 'show', value: post_modal_id }
%input{ type: 'hidden', name: 'hide', value: modal_id }
%input{ type: 'hidden', name: 'target', value: value_list_id }
%input{ type: 'hidden', name: 'swap', value: 'beforeend' }
%input{ type: 'hidden', name: 'base', value: id }
%input{ type: 'hidden', name: 'name', value: name }
%input{ type: 'hidden', name: 'form', value: form_id }
%input{ type: 'hidden', name: 'attribute', value: metadata.type }
- if metadata.inverse?
%input{ type: 'hidden', name: 'inverse', value: metadata.inverse }
%div{ id: post_modal_id, data: { controller: 'modal' } }
= render 'bootstrap/modal', id: post_id, modal_content_attributes: { class: 'h-100' } do
- content_for :"#{post_id}_body" do
%div{ id: post_form_loaded_id }
- content_for :"#{post_id}_footer" do
= render 'bootstrap/btn', form: form_id, content: t('.save'), type: 'submit'
-# @todo: Volver al otro modal
= render 'bootstrap/btn', content: t('.cancel'), action: 'modal#hide'

View file

@ -87,6 +87,7 @@
%input{ type: 'hidden', name: 'base', value: id }
%input{ type: 'hidden', name: 'name', value: name }
%input{ type: 'hidden', name: 'form', value: form_id }
%input{ type: 'hidden', name: 'attribute', value: metadata.type }
- if metadata.inverse?
%input{ type: 'hidden', name: 'inverse', value: metadata.inverse }
%div{ id: post_modal_id, data: { controller: 'modal' } }

View file

@ -0,0 +1,2 @@
.mb-2{ data: { target: 'array.item', 'searchable-value': @value.remove_diacritics.downcase, value: @uuid } }
= render 'bootstrap/custom_checkbox', name: @name, id: "value-#{Nanoid.generate}", value: @uuid, checked: true, content: @value, type: 'radio'