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

feat: new_has_one

This commit is contained in:
f 2024-06-03 17:52:53 -03:00
parent ff3042da90
commit 96aebb1346
No known key found for this signature in database
10 changed files with 104 additions and 11 deletions

View file

@ -40,10 +40,18 @@ class PostsController < ApplicationController
render layout: false render layout: false
end end
# El formulario de un Post, si pasamos el uuid, estamos editando, sino def new_has_one
@uuid = params.require(:value).strip
@indexed_post = site.indexed_posts.find_by!(post_id: @uuid)
render layout: false
end
# El formulario de un Post, si pasamos el UUID, estamos editando, sino
# estamos creando. # estamos creando.
def form def form
uuid = params.permit(:uuid).try(:[], :uuid) uuid = params.permit(:uuid).try(:[], :uuid).presence
locale locale
@post = @post =
@ -111,7 +119,7 @@ class PostsController < ApplicationController
params: params) params: params)
@post = service.create @post = service.create
if @post.persisted? if post.persisted?
site.touch site.touch
forget_content forget_content
end end
@ -119,11 +127,11 @@ class PostsController < ApplicationController
# @todo Enviar la creación a otro endpoint para evitar tantas # @todo Enviar la creación a otro endpoint para evitar tantas
# condiciones. # condiciones.
if htmx? if htmx?
if @post.persisted? if post.persisted?
swap_modals swap_modals
@value = @post.title.value @value = post.title.value
@uuid = @post.uuid.value @uuid = post.uuid.value
@name = params.require(:name) @name = params.require(:name)
render render_path_from_attribute, layout: false render render_path_from_attribute, layout: false
@ -133,8 +141,8 @@ class PostsController < ApplicationController
render 'posts/form', layout: false, post: post, site: site, **params.permit(:form, :base, :dir, :locale) render 'posts/form', layout: false, post: post, site: site, **params.permit(:form, :base, :dir, :locale)
end end
elsif @post.persisted? elsif post.persisted?
redirect_to site_post_path(@site, @post) redirect_to site_post_path(site, post)
else else
render 'posts/new' render 'posts/new'
end end
@ -235,7 +243,7 @@ class PostsController < ApplicationController
# @param triggers [Hash] Otros disparadores # @param triggers [Hash] Otros disparadores
def swap_modals(triggers = {}) def swap_modals(triggers = {})
params.permit(:show, :hide).each_pair do |key, value| params.permit(:show, :hide).each_pair do |key, value|
triggers["modal:#{key}"] = { id: value } triggers["modal:#{key}"] = { id: value } if value.present?
end end
headers['HX-Trigger'] = triggers.to_json if triggers.present? headers['HX-Trigger'] = triggers.to_json if triggers.present?
@ -247,6 +255,7 @@ class PostsController < ApplicationController
when 'new_has_many' then 'posts/new_has_many_value' when 'new_has_many' then 'posts/new_has_many_value'
when 'new_belongs_to' then 'posts/new_belongs_to_value' when 'new_belongs_to' then 'posts/new_belongs_to_value'
when 'new_has_and_belongs_to_many' then 'posts/new_has_many_value' when 'new_has_and_belongs_to_many' then 'posts/new_has_many_value'
when 'new_has_one' then 'posts/new_has_one_value'
else 'nothing' else 'nothing'
end end
end end

View file

@ -18,9 +18,23 @@ export default class extends Controller {
window.removeEventListener("modal:hide", this.hideEvent); window.removeEventListener("modal:hide", this.hideEvent);
} }
/*
* Abrir otro modal, enviando el ID a toda la ventana.
*/
showAnother(event = undefined) {
event?.preventDefault();
if (!event.target?.dataset?.modalShowValue) return;
window.dispatchEvent(new CustomEvent("modal:show", { detail: { id: event.target.dataset.modalShowValue } }));
}
/* /*
* Podemos enviar la orden de apertura como un click o como un * Podemos enviar la orden de apertura como un click o como un
* CustomEvent incluyendo el id del modal como detail. * CustomEvent incluyendo el id del modal como detail.
*
* El elemento clicleable puede tener un valor que se refiera a otro
* modal también.
*/ */
show(event = undefined) { show(event = undefined) {
event?.preventDefault(); event?.preventDefault();

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
# Nueva interfaz para relaciones 1:1
class MetadataNewHasOne < MetadataHasOne
include Metadata::UnusedValuesConcern
end

View file

@ -61,8 +61,8 @@
= errors.first = errors.first
-# Parámetros para HTMX -# Parámetros para HTMX
%input{ type: 'hidden', name: 'hide', value: params.require((post.errors.empty? ? :show : :hide)) } %input{ type: 'hidden', name: 'hide', value: params.permit((post.errors.empty? ? :show : :hide)).try(:values).try(:first) }
%input{ type: 'hidden', name: 'show', value: params.require((post.errors.empty? ? :hide : :show)) } %input{ type: 'hidden', name: 'show', value: params.permit((post.errors.empty? ? :hide : :show)).try(:values).try(:first) }
%input{ type: 'hidden', name: 'name', value: params.require(:name) } %input{ type: 'hidden', name: 'name', value: params.require(:name) }
%input{ type: 'hidden', name: 'base', value: params.require(:base) } %input{ type: 'hidden', name: 'base', value: params.require(:base) }
%input{ type: 'hidden', name: 'form', value: options[:id] } %input{ type: 'hidden', name: 'form', value: options[:id] }

View file

@ -0,0 +1,2 @@
= render 'posts/new_related_post', post: post
%input{ type: 'hidden', name: name, value: value }

View file

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

View file

@ -0,0 +1,53 @@
-#
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 = random_id
name = "#{base}[#{attribute}]"
target_id = random_id
form_id = random_id
modal_id = random_id
post_id = random_id
post_form_id = random_id
post_modal_id = random_id
post_form_loaded_id = random_id
value_list_id = random_id
layout = metadata.filter[:layout]
%div{ data: { controller: 'modal' }}
.form-group
= hidden_field_tag name, ''
.d-flex.align-items-center.justify-content-between
= label_tag id, post_label_t(attribute, post: post), class: 'h3'
= render 'bootstrap/btn', content: t('.edit'), action: 'modal#showAnother', data: { 'modal-show-value': modal_id }
-# Aquí se reemplaza por la tarjeta y el UUID luego de guardar
.row.row-cols-1.no-gutters.placeholder-glow{ id: target_id }
-# @todo issue-7537
- if !metadata.empty? && (indexed_post = site.indexed_posts.find_by(post_id: metadata.value))
= render 'posts/new_has_one', post: indexed_post, name: name, value: metadata.value
-#
El modal se genera por fuera del formulario, para poder enviar los
datos y recibir su UUID en respuesta.
- content_for :post_form do
%div{ id: modal_id, data: { controller: 'modal' }}
- if layout.is_a?(String)
= render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' } do
- content_for :"#{id}_body" do
-# @todo ocultar el modal después de guardar
.placeholder-glow{ 'hx-get': site_posts_form_path(site, layout: layout, base: id, name: name, form: form_id, swap: 'innerHTML', target: target_id, attribute: 'new_has_one', hide: modal_id, uuid: metadata.value), 'hx-trigger': 'load' }
%span.placeholder.w-100.h-100
- content_for :"#{id}_footer" do
= render 'bootstrap/btn', form: form_id, content: t('.save'), type: 'submit', class: 'm-0 mt-1 mr-1'
= render 'bootstrap/btn', content: t('.cancel'), action: 'modal#hide', class: 'm-0 mt-1 mr-1'
- else
Nada

View file

@ -0,0 +1 @@
= render 'posts/new_has_one', post: @indexed_post, name: params.require(:name), value: @uuid

View file

@ -0,0 +1 @@
= render 'posts/new_has_one', post: @post.to_index, name: params.require(:name), value: @uuid

View file

@ -103,6 +103,7 @@ Rails.application.routes.draw do
get :'posts/new_array', to: 'posts#new_array' get :'posts/new_array', to: 'posts#new_array'
get :'posts/new_array_value', to: 'posts#new_array_value' get :'posts/new_array_value', to: 'posts#new_array_value'
get :'posts/new_related_post', to: 'posts#new_related_post' get :'posts/new_related_post', to: 'posts#new_related_post'
get :'posts/new_has_one', to: 'posts#new_has_one'
get :'posts/form', to: 'posts#form' get :'posts/form', to: 'posts#form'
resources :posts do resources :posts do